Integration by substitution: general partial credit checks and problem templates.

From WeBWorK_wiki
Jump to navigation Jump to search

The following problem will show you how to check when the student answer S and the correct answer C are in the relationship S = aC+b for any real a and b. It is also designed as a problem template. This means that you can obtain many different problems spending a few seconds and modifying a few lines. One needs to be a little careful when modifying code. Go through the exercises for more details on this.

# Created by Nikola Kuzmanovski

########################################################################

DOCUMENT();      

loadMacros(
   "PGstandard.pl",
   "MathObjects.pl",
   "PGinfo.pl",
);

TEXT(beginproblem());
$showPartialCorrectAnswers = 1;

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

$f = Formula("e^x");
$F = Formula("e^x");
$g = Formula("sin(x)");
$gD = $g->D('x');

$integrand = $f->substitute(x => $g) * $gD;
$integral = $F->substitute(x => $g);
$fu = $f->substitute(x => "u");
$Fu = $F->substitute(x => "u");


$lowerLimit = random(10, 19, 1);
$upperLimit = random(20, 29, 1);
$area = $integral->eval(x => $upperLimit) - $integral->eval(x => $lowerLimit);
##############################################################
#
#  Text
#
#

Context()->texStrings;
BEGIN_TEXT
This problem deals with the following integral
\[ \int $integrand dx .\]

Your job is to evaluate it using substitution.
We are going to use the variable \(u\) as the substitution variable.
Give a choice for \(u\) below.

$BR
$BCENTER
\(\displaystyle  u = \) \{ans_rule\}.
$ECENTER

$BR
Then
$BCENTER
\(\displaystyle  du = \) \{ans_rule\} \(dx\).
$ECENTER

$BR
With this we can change the integral \(\displaystyle  \int $integrand dx \) to an integral of the form \(\displaystyle \int g(u) du\) for some function \(g(u)\).
Input this function in the line below $BBOLD (note that the \(du\) is included at the end, so you don't need to input it). $EBOLD.

$BR
$BCENTER
\(\displaystyle  \int $integrand dx = \int \) \{ans_rule\} \(du\).
$ECENTER

$BR
Next, find the general antiderivative $BBOLD (note that the \(+C\) is included at the end, so you don't need to input it). $EBOLD
$BR
$BCENTER
\(\displaystyle  \int $integrand dx = \) \{ans_rule\} \(+C\).
$ECENTER

$BR
Finally, compute
$BR
$BCENTER
\(\displaystyle  \int_{$lowerLimit}^{$upperLimit} $integrand dx = \) \{ans_rule\}.
$ECENTER

END_TEXT
Context()->normalStrings;

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

sub checkMult{
	my ( $correct, $student ) = @_;
	
	if($student->isConstant){
		return 0
	}
    
	my $context = Context()->copy;
	return 0 if $student == 0;
    
	$context->flags->set(no_parameters=>0);
	$context->variables->add('C0'=>'Parameter');
    
	my $c0 = Formula($context,'C0');
	$student = Formula($context,$student);
	$correct = Formula($context,"$c0 * $correct");
    
	return $correct == $student;
}

sub checkAdd{
	my ( $correct, $student ) = @_;
	
	if($student->isConstant){
		return 0
	}
    
	my $context = Context()->copy;
	return 0 if $student == 0;
    
	$context->flags->set(no_parameters=>0);
	$context->variables->add('C0'=>'Parameter');
    
	my $c0 = Formula($context,'C0');
	$student = Formula($context,$student);
	$correct = Formula($context,"$c0 + $correct");
    
	return $correct == $student;
}

sub checkMultAdd{
	my ( $correct, $student ) = @_;
	
	if($student->isConstant){
		return 0
	}
    
	my $context = Context()->copy;
	return 0 if $student == 0;
    
	$context->flags->set(no_parameters=>0);
	$context->variables->add('C0'=>'Parameter');
	$context->variables->add('C1'=>'Parameter');
    
	my $c0 = Formula($context,'C0');
	my $c1 = Formula($context,'C1');
	$student = Formula($context,$student);
	$correct = Formula($context,"$c1 + $c0 * $correct");
    
	return $correct == $student;
}


$studentU = Formula("");
$scoreU = 0.0;
$checkU = sub{
	if($inputs_ref->{previewAnswers}){
		return 0.0;
	}
	
	my ($correctAns, $studentAns, $ansHash) = @_;
	my $score = 0.0;
	$studentAns = Formula("$studentAns");
	$studentAns = $studentAns->substitute(X => "x");
	$studentU = $studentAns;
	
	my $studentSub = $f->substitute(x => $studentAns) * $gD;
	
	if($integrand == $studentSub){
		$ansHash->{ans_message} = "This substitution will work!";
		$score = 1.0;
	}elsif(checkMult($integrand, $studentSub)){
		$ansHash->{ans_message} = "This substitution will almost work. The final antiderivative will have an extra multiplicative constant";
		$score = 0.9;
	}elsif(checkMult($correctAns, $studentAns)){
		$ansHash->{ans_message} = "Your answer is close to the correct one. You have an extra multiplicative constant.";
		$score = 0.8;
	}elsif(checkAdd($correctAns, $studentAns)){
		$ansHash->{ans_message} = "Your answer is close to the correct one. You have added an extra constant.";
		$score = 0.8;
	}elsif(checkMultAdd($correctAns, $studentAns)){
		$ansHash->{ans_message} = "Your answer is close to the correct one. You have added an extra constant and you have an extra multiplicative constant.";
		$score = 0.7;
	}else{
		$ansHash->{ans_message} = "Your answer won't work. Try reviewing the section on integration by substitution.";
	}
	
	
	$scoreU = $score;
	return $score;
};
ANS($g->cmp(checker => $checkU));

$studentDiv = Formula("");
$scoreDiv = 0.0;
$checkDiv = sub{
	if($inputs_ref->{previewAnswers}){
		return 0.0;
	}
	
	my ($correctAns, $studentAns, $ansHash) = @_;
	my $score = 0.0;
	$studentAns = Formula("$studentAns");
	$studentAns = $studentAns->substitute(X => "x");
	$studentDiv = $studentAns;
	
	if($studentU == Formula("")){
		$ansHash->{ans_message} = "This answer depends on the previous answer. You don't get any points for it because you didn't enter anything for the previous answer.";
		return $score;
	}
	
	my $studentDerivative = $studentU->D('x');
	
	if($studentDerivative == $studentAns){
		$ansHash->{ans_message} = "You differentiated correctly!";
		$score = 1.0;
	}elsif(checkAdd($studentDerivative, $studentAns)){
		$ansHash->{ans_message} = "It seems like you made some mistake while differentiating. You have some extra additive constant.";
		$score = 0.9;
	}elsif(checkMult($studentDerivative, $studentAns)){
		$ansHash->{ans_message} = "It seems like you made some mistake while differentiating. You have some extra multiplicative constant.";
		$score = 0.9;
	}elsif(checkMultAdd($studentDerivative, $studentAns)){
		$ansHash->{ans_message} = "It seems like you made some mistake while differentiating. You have some extra additive constant and an extra multiplicative constant.";
		$score = 0.8;
	}else{
		$ansHash->{ans_message} = "It seems that you didn't differentiate correctly. Try reviewing differentiation from Calculus I.";
	}
	
	return $score;
};
ANS($gD->cmp(checker => $checkDiv));

$studentSub = Formula("");
$scoreSub = 0.0;
$checkSub = sub{
	if($inputs_ref->{previewAnswers}){
		return 0.0;
	}
	
	my ($correctAns, $studentAns, $ansHash) = @_;
	my $score = 0.0;
	$studentAns = Formula("$studentAns");
	$studentSub = $studentAns;
	
	if($studentU == Formula("") || $studentDiv == Formula("")){
		$ansHash->{ans_message} = "This answer depends on the previous two answers. You don't get any points for it because you didn't enter anything for the previous answers.";
		return $score;
	}
	
	if($correctAns == $studentAns){
		$ansHash->{ans_message} = "Good work substituting!";
		$score = 1.0;
	}elsif(checkAdd($correctAns, $studentAns)){
		$ansHash->{ans_message} = "It seems like you made some mistake while substituting. You have some extra additive constant.";
		$score = 0.9;
	}elsif(checkMult($correctAns, $studentAns)){
		$ansHash->{ans_message} = "It seems like you made some mistake while substituting. You have some extra multiplicative constant.";
		$score = 0.9;
	}elsif(checkMultAdd($correctAns, $studentAns)){
		$ansHash->{ans_message} = "It seems like you made some mistake while substituting. You have some extra additive constant and an extra multiplicative constant.";
		$score = 0.8;
	}else{
		$ansHash->{ans_message} = "It seems that your answer is not correct. Try reviewing integration by substitution.";
	}
	
	return $score;
};
ANS($fu->cmp(checker => $checkSub));

$studentIntegral = Formula("");
$scoreIntegral = 0.0;
$checkIntegral = sub{
	if($inputs_ref->{previewAnswers}){
		return 0.0;
	}
	
	my ($correctAns, $studentAns, $ansHash) = @_;
	my $score = 0.0;
	$studentAns = Formula("$studentAns");
	$studentAns = $studentAns->substitute(X => "x");
	$studentIntegral = $studentAns;

	
	if(checkAdd($correctAns, $studentAns)){
		$ansHash->{ans_message} = "Great Job!";
		$score = 1.0;
	}elsif(checkMultAdd($correctAns, $studentAns)){
		$ansHash->{ans_message} = "It seems like you made some mistake while integrating. You have some extra multiplicative constant.";
		$score = 0.9;
	}elsif(checkAdd($Fu, $studentAns)){
		$ansHash->{ans_message} = "You forgot to switch the u at the end.";
		$score = 0.8;
	}elsif(checkMultAdd($Fu, $studentAns)){
		$ansHash->{ans_message} = "You forgot to switch the u at the end and you have an extra multiplicative constant.";
		$score = 0.7;
	}else{
		$ansHash->{ans_message} = "It seems that your answer is not correct. Try reviewing integration by substitution.";
	}
	
	$scoreIntegral = $score;
	return $score;
};
ANS($integral->cmp(checker => $checkIntegral));

$studentFTC = Formula("");
$scoreFTC = 0.0;
$checkFTC = sub {
	if($inputs_ref->{previewAnswers}){
		return 0.0;
	}
	
	my ($correctAns, $studentAns, $ansHash) = @_;
	my $score = 0.0;
	$studentAns = Formula("$studentAns");
	$studentIntegral = $studentIntegral->substitute(u => "x");
	
	if($studentU == Formula("") || $studentDiv == Formula("") || $studentSub == Formula("")){
		$ansHash->{ans_message} = "This answer depends on the previous three answers. You don't get any points for it because you didn't enter anything for the previous answers.";
		$scoreFTC = 0.0;
		return $score;
	}
	
	if($scoreIntegral == 1.0 && $correctAns == $studentAns){
		$score = 1.0;
		$scoreFTC = $score;
		$ansHash->{ans_message} = "You computed the antiderivative correctly and used the Fundamental Theorem of Calculus correctly!";
		return $score;
	} 

	eval{
                my $lowerEval = $studentIntegral->eval(x => $lowerLimit);
				my $upperEval = $studentIntegral->eval(x => $upperLimit);
		
		if ($upperEval - $lowerEval == $studentAns || $correctAns == $studentAns){
			$ansHash->{ans_message} = "You didn't compute the antiderivative correctly. However, you used the Fundamental Theorem of Calculus correctly.";
			$score = 1.0;
		}elsif($lowerEval - $upperEval == $studentAns){
			$ansHash->{ans_message} = "You switched the bounds of integration.";
			$score = 0.9;
		}elsif($upperEval + $lowerEval == $studentAns){
			$ansHash->{ans_message} = "You need to subtract the lower bound, not add it.";
			$score = 0.9;
		}else{
			$ansHash->{ans_message} = "It seems that your answer is not correct. Try reviewing the Fundamental Theorem of Calculus.";
		}
		
		1;
	} or do{
		$ansHash->{ans_message} = "It seems that the answer you gave for the antiderivative doesn't evaluate at the bounds of the definite integral";
		$ansHash->{ans_message} = $ansHash->{ans_message} . " Try double checking your work for the antiderivative.";
		$ansHash->{ans_message} = $ansHash->{ans_message} . " Check for things like division by 0 or negatives under a square root.";
	};
	
	return $score;
};
ANS($area->cmp(checker => $checkFTC));


ENDDOCUMENT();        

Exercises:

  1. Create another problem by modifying $f, $F and $g.
  2. Create a problem that will produce an error. Think about $area and the last part of the problem.
  3. Break the isConstant property in checkMult. Write x/x for the first answer.
  4. Write your own isConstant function that won't have this issue. Think about how variables and the Formula object are implemented. Think about how this affects things like the differentiation operation.