PREP 2014 Question Authoring - Archived

Simplifying output of automatic differentiation

Simplifying output of automatic differentiation

by Nicholas Nguyen -
Number of replies: 7
This problem asks students to compute the indefinite integral of a function which is the derivative of f(x)=a*sin(bx) (a, b are random coefficients). The problem displays the derivative f'(x)=(a*b)cos(bx) inside the integral, but it does not simplify a*b.

Below is the code. Thank you for your help.

##############################################
# Initialization

DOCUMENT();

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"PGcourse.pl",
"AnswerFormatHelp.pl",
"parserFormulaUpToConstant.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 0;

##############################################
# Setup

Context("Numeric");

# Integrate a*sin(b*x), a and b randomized

$a = Real(non_zero_random(-5,5,1));
$b = Real(non_zero_random(-5,5,1));
$c = Real($a*$b);

$f = FormulaUpToConstant("$a sin($b * x)")->reduce("(-x)-y"=>0,"(-x)+y"=>0);
$dfdx = $f->D; # f'(x)




##############################################
# Main text

Context()->texStrings;
BEGIN_TEXT
Compute the indefinite integral
\[ \int \{$dfdx->TeX\} dx \]
$BR
(remember: your answer should be a function of \(x\)!)
$BR
\{ ans_rule(20) \}
END_TEXT

Context()->normalStrings;

ANS( $f->cmp() );

ENDDOCUMENT();
In reply to Nicholas Nguyen

Re: Simplifying output of automatic differentiation

by Davide Cervone -
The problem displays the derivative f'(x)=(a*b)cos(bx) inside the integral

Actually, it is f'(x) = a*(b*cos(bx)), which is structurally different, and it is because of the structural difference that the constants are not combined. The reduce() method would have reduced the constants in your expression, but because the two constants aren't multiplied directly in the derivative, they are not.

The reduction rules don't include anything for this situation. There are more rules that could be added that would help with this but currently there aren't any. One way around this, however, is to take advantage of the fact that there are no parentheses displayed around the b*cos(bx) in its string version and ask MathObject to parse the value again. Try

    $dfdx = Formula($f->D->string);
to force the expression to be reparsed, so that the multiplication of the two constants is performed first.

Also, I note that you have used reduce("(-x)-y"=>0,"(-x)+y"=>0) for your formula. But it doesn't contain any sums or differences, so these rules never apply anyway, so there is no need to disable them in this case.

I see you are making $a and $b into Real MathObjects, that is fine, though unnecessary in this problem, since they are only used to be inserted into the formula for $f. You also make a variable $c that is never used, and you force it to a Real as well. Since $a and $b are already Real objects, there is no need to use Real() again on the result, as it will be a Real automatically.

In reply to Davide Cervone

Re: Simplifying output of automatic differentiation

by Paul Pearson -
Hi Nicholas,

In the Main Text section, you have 

Context()->texStrings;
BEGIN_TEXT
\[ \int \{$dfdx->TeX\} dx \]
END_TEXT
Context()->normalStrings;

which uses \[ \] to change to display math mode and then \{ \} to change to Perl mode where you take the MathObject $dfdx and generate it's TeX string using the method ->TeX defined on MathObject formulas.  

Since you have Context()->texStrings; before BEGIN_TEXT, when you write $dfdx in the TEXT block, it will automatically generate the TeX formula from $dfdx, so generating the TeX string manually via \{ $dfdx->TeX \} is unnecessary.  Thus, you could instead use

Context()->texStrings;
BEGIN_TEXT
\[ \int $dfdx \, dx \]
END_TEXT
Context()->normalStrings;

For purely aesthetic reasons, I inserted a small space \, between the formula $dfdx and the differential dx using a TeX command \, for generating a small space. 

Note that the Context()->normalStrings; after the END_TEXT ensures that normal strings (not TeX strings) are used inside of answer checkers that come later in the code.

Best regards,

Paul Pearson
In reply to Nicholas Nguyen

Re: Simplifying output of automatic differentiation

by Nicholas Nguyen -
Dear Davide and Paul,
Thank you both. At this point, the problem still displays formulas like
"-(15cos(3x)),"
but at least it multiplies the coefficients now.

Davide: I ended up keeping the reduction exceptions for $f, because without them, in the solution, WeBWorK might display
"C - 5sin(3x)" instead of "-5sin(3x) + C."

Here is the updated code.

##############################################
# Initialization

DOCUMENT();

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"PGcourse.pl",
"AnswerFormatHelp.pl",
"parserFormulaUpToConstant.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 0;

##############################################
# Setup

Context("Numeric");

# Integrate a*sin(b*x), a and b randomized

$a = Real(non_zero_random(-5,5,1));
$b = Real(non_zero_random(-5,5,1));
$c = $a*$b; # Needed for solution display

$f = FormulaUpToConstant("$a sin($b * x)")->reduce("(-x)-y"=>0,"(-x)+y"=>0);
# Without the rules "(-x)-y"=>0,"(-x)+y"=>0, the solution might display "C - sin($ax)."

$dfdx = Formula($f->D->string);
# Reparse so $a and $b are multiplied in display




##############################################
# Main text

Context()->texStrings;
BEGIN_TEXT
Compute the indefinite integral
\[ \int $dfdx \, dx \]
$BR
(remember: your answer should be a function of \(x\)!)
$BR
\{ ans_rule(20) \}
END_TEXT

BEGIN_SOLUTION
Use subtitution with:
\[
u = $b x, \, du = $b dx \implies \frac{1}{$b}du = dx
\]

\[ \int \frac{$c}{$b} \cos(u) \, du = \int $a \cos(u) \, du \]
An antiderivative of \(\cos(u)\) is \(\sin(u)\):
\[
= $a \sin(u) + C
\]

Don't forget to substitute \(u = $b x\):
\[
= $f
\]

END_SOLUTION
Context()->normalStrings;

ANS( $f->cmp() );

ENDDOCUMENT();
In reply to Nicholas Nguyen

Re: Simplifying output of automatic differentiation

by Nicholas Nguyen -
I was rewriting the problem so that the setup uses the chain rule to differentiate "$a*sin(u)," where u=$b*x, as a function of x. I managed to get it to display something like
"-15cos(3x)"
in the problem now. Here's the rewrite:


##############################################
# Initialization

DOCUMENT();

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"PGcourse.pl",
"AnswerFormatHelp.pl",
"parserFormulaUpToConstant.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 0;

##############################################
# Setup

Context("Numeric");
Context()->variables->add(u=>"Real");

# Integrate a*sin(u), with u=b*x a and b randomized

$a = Real(non_zero_random(-5,5,1));
$b = Real(non_zero_random(-5,5,1));
$c = $a*$b; # Needed for solution display

# Define $u = b*x as a formula of x for substitution
$u = Formula("$b x");

$f = FormulaUpToConstant("$a sin(u)")->reduce("(-x)-y"=>0,"(-x)+y"=>0);
# Without the rules "(-x)-y"=>0,"(-x)+y"=>0, the solution might display "C - sin($ax)."

$dfdu = Formula($f->D('u')); # df/du
$dfdux = $dfdu->substitute(u=>$u)->reduce; # Substitute u = $b*x into df/du
$dudx = Formula($u->D('x'))->reduce; # du/dx
$dfdx = Formula($dfdux*$dudx); # Chain rule df/du * du/dx = df/dx
$dfdxr = Formula($dfdx->reduce->string)->reduce; # Simplify

# In $dfdxr, first reduce moves coefficients outside cosine to left, but doesn't multiply
# Next, use string to multiply coefficients. This puts coefficient (with negative sign) in parentheses
# Finally, second reduce gets rid of excess parentheses around coefficient


##############################################
# Main text

Context()->texStrings;
BEGIN_TEXT
Compute the indefinite integral
\[ \int $dfdxr \, dx \]
$BR
(remember: your answer should be a function of \(x\)!)
$BR
\{ ans_rule \}

END_TEXT

BEGIN_SOLUTION
Use subtitution with:
\[
u = $b x, \, du = $b dx \implies \frac{1}{$b}du = dx
\]

\[ \int \frac{$c}{$b} \cos(u) \, du = \int $a \cos(u) \, du \]
An antiderivative of \(\cos(u)\) is \(\sin(u)\):
\[
= $a \sin(u) + C
\]

Don't forget to substitute \(u = $b x\):
\[
= $f
\]

END_SOLUTION
Context()->normalStrings;

ANS( $f->cmp() );

ENDDOCUMENT();
In reply to Nicholas Nguyen

Re: Simplifying output of automatic differentiation

by Mary Cameron -

I have been finding this series of posts helpful for something I’ve been working on.  I suspect another manifestation of this problem is illustrated by the code below. 

 Like Nicholas, the output I get has an extra pair of parentheses, namely: 

  -(sqrt(2x+3) ) +2 instead of -sqrt(2x+3)  +2.  The issue only seems to arise when $parent = sqrt(x).  If $parent is 1/x or x^2 for example, there is no issue of extra parentheses.

~Mary


DOCUMENT();     
loadMacros(
   "PGstandard.pl",     # Standard macros for PG language
   "MathObjects.pl",
);
TEXT(beginproblem());
Context("Numeric");
 
$a = -1;      #non_zero_random(-3, 3, 1);            # vertical stretch and reflection
$b = non_zero_random(-2, 2, 1);           # horizontal stretch and reflection
$c = random(-4, 4, 1);                              # horizontal shift
$d = random(-4, 4, 1);                              # vertical shift
 
Context() -> flags -> set ( reduceConstants => 0, reduceConstantFunctions => 0  );
 
$parent = Formula("sqrt(x)");
$fx =$parent ->substitute(x => "$b * x - $c") -> reduce ("(-x)-y" => 0, " x-(-y)" => 0, "(-x)+y" =>0);
$fxy = Formula("$a * $fx + $d") -> reduce( "(-x)-y" => 0, "(-x)+y" =>0, "-a" => 0  );
 
Context()->texStrings;
BEGIN_TEXT
Given the function \(  f(x) = \displaystyle $fxy  \) and its parent function \( y =  \displaystyle $parent\),   mid-formula is  \( y =  \displaystyle $fx \)
END_TEXT
 
ENDDOCUMENT();        

In reply to Mary Cameron

Re: Simplifying output of automatic differentiation

by Davide Cervone -
I get has an extra pair of parentheses, namely: -(sqrt(2x+3))+2 instead of -sqrt(2x+3)+2.

Your issue turns out to be from a different cause. The MathObjects library adds extra parentheses in its output to try to make it painfully clear to the student what the structure of the expression is. For example, sin(x)^2 is shown as [sin(x)]^2 so it is clear that the whole expression is squared, not just the x.

Your situation is coming from that process. You can do

    Context()->operators->set(fn => {parenPrecedence => 6.5})
to fix this. (The parenPrecedence tells when extra parens are added around functions based on the precedence of the operator that surrounds them. 6.5 puts it between the precedence of unary minus and exponentiation, so that you still get [sin(x)]^2 but not -[sin(x)].)

I give you a modified version of your problem below. There are several small changes. One thing to keep in mind is that the names of the reduction formulas must be given exactly, so your " x-(-y)" (which has an extra leading space) does nothing. In any case, I don't think you want that one since, you do want x-(-3) to be converted to x+3, I assume. (Your $c can be negative in "$b * x - $c").

Similarly, your "-a"=>0 specification does nothing since there is no rule with the name "-a". Did you mean "-n"? In any case, I would not recommend that you remove that one in this case. The parenPrecedence is what is needed, here.

So here is the modified version:

loadMacros(
   "PGstandard.pl",     # Standard macros for PG language
   "MathObjects.pl",
);
TEXT(beginproblem());
Context("Numeric");
 
$a = -1;      #non_zero_random(-3, 3, 1);            # vertical stretch and reflection
$b = non_zero_random(-2, 2, 1);           # horizontal stretch and reflection
$c = random(-4, 4, 1);                              # horizontal shift
$d = random(-4, 4, 1);                              # vertical shift
 
Context()->operators->set(fn => {parenPrecedence => 6.5});
Context()->reduction->noreduce("(-x)-y","(-x)+y");
 
$parent = Formula("sqrt(x)");
$fx = $parent->substitute(x => "$b * x - $c")->reduce;
$fxy = Formula("$a * $fx + $d")->reduce;
 
Context()->texStrings;
BEGIN_TEXT
Given the function \(f(x) = $fxy\) and its parent function \(y = $parent\), the mid-formula is  \(y = $fx\)
END_TEXT
In reply to Nicholas Nguyen

Re: Simplifying output of automatic differentiation

by Davide Cervone -
I ended up keeping the reduction exceptions for $f, because without them, in the solution, WeBWorK might display "C - 5sin(3x)" instead of "-5sin(3x) + C."

Right. I forgot that you were using FormulaUpToConstant() and that it does introduce an addition.

At this point, the problem still displays formulas like "-(15cos(3x)),"

OK, I've handled this by adjusting the reduction rules a little further. In the code below, I added

    Context()->reduction->noreduce("(-x)-y","(-x)+y","(-x)*y","x*(-y)");
which removes the rules that factor out negatives from sums, additions, and products (it is the latter that is causing your issues, here).

I also added reduce to the definition of $dfdx. Without this, you would end up with "(-15)cos(3x)".

So here is my modified version:

DOCUMENT();

loadMacros(
  "PGstandard.pl",
  "MathObjects.pl",
  "PGcourse.pl",
  "AnswerFormatHelp.pl",
  "parserFormulaUpToConstant.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 0;

##############################################
# Setup

Context("Numeric");

Context()->reduction->noreduce("(-x)-y","(-x)+y","(-x)*y","x*(-y)");

# Integrate a*sin(b*x), a and b randomized

$a = Real(non_zero_random(-5,5,1));
$b = Real(non_zero_random(-5,5,1));
$c = $a*$b; # Needed for solution display

$f = FormulaUpToConstant("$a sin($b * x)")->reduce; 
$dfdx = Formula($f->D->string)->reduce;
# Reparse so $a and $b are multiplied in display


##############################################
# Main text

Context()->texStrings;
BEGIN_TEXT
Compute the indefinite integral
\[ \int $dfdx \, dx \]
(remember: your answer should be a function of \(x\)!)
$BR
\{ ans_rule(20) \}
END_TEXT

BEGIN_SOLUTION
Use subtitution with:
\[u = $b x, \, du = $b dx \implies \frac{1}{$b}du = dx\]
\[\int \frac{$c}{$b} \cos(u) \, du = \int $a \cos(u) \, du\]
An antiderivative of \(\cos(u)\) is \(\sin(u)\):
\[= $a \sin(u) + C\]
Don't forget to substitute \(u = $b x\):
\[= $f\]
END_SOLUTION
Context()->normalStrings;

ANS($f->cmp);

ENDDOCUMENT();