WeBWorK Problems

Problem with LimitedPolynomial

Problem with LimitedPolynomial

by Stacy Hoehn -
Number of replies: 2
Hi, 

I am having trouble with the following problem (and other similar problems) I'm writing for an algebra gateway exam.  I am trying to have the students simplify an expression like \displaystyle -4 x^{-2}\cdot (2 x^{8}) =. or \displaystyle -2 x^{-2}\cdot (8 x^{-3}) = or \displaystyle \frac{5 x^{7}}{10 x^{4}} =. 

I currently have the output to these problems formatted as a multianswer fraction because I don't want to give away if the resulting exponents should be positive or negative and I want to use LimitedPolynomial to make sure the students actually simplify the expression correctly.  

The code I have accepts the correct answer, but gives some errors that are unexpected when I enter some incorrect answers.  For example, if I enter, 2/-4 (using 2 in the first answer blank and -4 in the second answer blank), I get the error "Coefficients must come before variables in a polynomial".  I get the error "A variable can appear only once in each term of a polynomial" if I enter -8x^8/x^2 (using -8x^8 in the first blank and x^2 in the second blank), and if I change the singlePowers flag to 0, I get the coefficients coming before variables error with the same input.  

Any ideas on why my code is producing this behavior?

Thanks,
Stacy


-------------------------------------------------------------------------------------
DOCUMENT();

loadMacros(
"PGstandard.pl", 
"MathObjects.pl", 
"PGunion.pl",
"parserMultiAnswer.pl",
"contextLimitedPolynomial.pl",
"PGcourse.pl",
);

TEXT(beginproblem());


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

Context("LimitedPolynomial")->variables->are(x=>"Real");
Context()->flags->set(singlePowers=>1);
Context()->{error}{msg}{"Operands of '*' can't be words"} = " ";

$a = random(2,5,1);
$b = random(2,5,1);
$c = random(2,9,1);
$d = random(6,9,1);


$expr = "-$a x^{-$b}\cdot ($c x^{$d})";


$num = Formula("-1*$a*$c*x^{$d-$b}");
$den = Formula("1");


$multians = MultiAnswer($num, $den)->with(
  singleResult => 1,
  allowBlankAnswers => 0,
  checker => sub {
      my ( $correct, $student, $self ) = @_;
      my ( $f1stu, $f2stu ) = @{$student};
      my ( $f1, $f2 ) = @{$correct};
 
      if ( ( $f1==$f1stu &&  $f2==$f2stu) || 
           (-$f1==$f1stu && -$f2==$f2stu) ) {
          return [1,1];
      } elsif ( $f1==$f1stu || -$f1==$f1stu) {
          return [1,0];
       } elsif ( $f2==$f2stu || -$f2==$f2stu ) {
          return [0,1];
      } elsif ( $f1*$f2stu==$f1stu*$f2 ) {
          $self->setMessage(1,"Simplify your answer further");
          $self->setMessage(2,"Simplify your answer further");
          return [0,0];
      } else {
          return [0,0];
      }
  }
);



#  Display the fraction and answer blanks nicely
#
Context()->texStrings;
if ($displayMode eq 'TeX') {
  $showExpr =
  "\[ $expr = ".$multians->ans_rule(10).$multians->ans_rule(10)." \]";
} else {
  $showExpr =
  ColumnTable(
  "\( \displaystyle $expr = \)",
  $multians->ans_rule(20).$BR.$HR.$multians->ans_rule(20),
  indent => 0, separation => 10, valign => "MIDDLE"
  );
}
Context()->normalStrings;



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

Context()->texStrings;
BEGIN_TEXT
Simplify the following expression completely.  Do not use negative exponents in your answer; express your answer as a reduced fraction, using '1' for the denominator if appropriate.
$BR
$BR
$BCENTER
$showExpr
$ECENTER
END_TEXT
Context()->normalStrings;


#################################
#  Answer evaluation

$showPartialCorrectAnswers = 1;

install_problem_grader(~~&std_problem_grader);

ANS( $multians->cmp() );


#################################
#  Solution

Context()->texStrings;
BEGIN_SOLUTION
${PAR}SOLUTION:${PAR}
Solution explanation goes here.
END_SOLUTION
Context()->normalStrings;

COMMENT('MathObject version.');

ENDDOCUMENT();
In reply to Stacy Hoehn

Re: Problem with LimitedPolynomial

by Davide Cervone -
The error messages you are receiving are due to the expression
    $f1*$f2stu == $f1stu*$f2
in the checker for your MultiAnswer object. Note that the correct and student answers are in the LimitedPolynomial context, and so if $f1 is -8x^6 and $f2stu is x^2, then the product is (-8x^6)*(x^2), which is not valid in this context, and the error is reported. Similarly for when $f2tu is -4.

The solution is to perform those computations in a different context (where they are valid). One way is to set the context and recompute the products, as in

    Context("Numeric");
    if (Compute("$f1*$f2stu") == Compute("$f1stu*$f2")) {
      ...
    }
This forces the product to be represented first as a string and then that string is recomputed in the current context (which is now Numeric rather than LimitedPolynomial).

There are a couple of other changed that I would suggest, as well. First, you might want to use the LimitedPolynomial-Strict context rather than just LimitedPolynomial, so that you can't enter things like -4*2*x^6 in place of -8x^6. If you do that, however, you will need to be more careful about the initial formula for the numerator and denominator, since they no longer can include computations. So something like

    $num = Formula((-1*$a*$c)."*x^".($d-$b));
    $den = Formula("1");
where you do the computations outside the string, would work.

Second, I like that you are using a single result for this, but it is possible to format the student answer more naturally by showing it as a fraction. One way would be to use

    format => "(%s)/(%s)",
    tex_format => "\frac{%s}{%s}",
in your MultiAnswer object to get the student's answer shown as a fraction. This is better, and works well for the TeX version, but it means the text version may have extra parentheses, as in (-8x^6)/(1). That is not wrong, but you might want to use
    $self->{format} = Compute("$f1stu/$f2stu")->string;
within the checker (after setting Context("Numeric") first) in order to get a better text output.

Third, you can improve the correct answer output in a similar way. Unfortunately, the MultiAnswer object doesn't use the format option to set the correct answer (a bug that should be fixed), and because the MultiAnswer object was written before the correct answer was available in TeX form, it doesn't set the value for that, so a little more work needs to be done to make that work. In this case, you need to use

    my ( $correct, $student, $self, $ansHash ) = @_;
in order to get the AnswerHash as well as the other data, and then use
    Context("Numeric");
    $correct = Compute("$f1/$f2");
    $ansHash->{correct_ans} = $correct->string;
    $ansHash->{correct_ans_latex_string} = $correct->TeX;
to set the correct answer string and LaTeX values. Note, however, that if the student presses the submit button when one or both answers are blank, the checker won't run, and so these values won't be set, and the correct answer will not show the fraction. To resolve that, you can use
    allowBlankAnswers => 1,
so that your checker will run even for blank answers, and then use
    return [0,0] if $f1stu eq "" || $f2stu eq "";
after setting the correct answers (and before setting the format) to handle the blank answers.

The only remaining time that you won't get fractions is if the student has a syntax error in their answer (and so your checker won't run). But since this is unlikely to occur when the correct answers are being shown, I wouldn't worry about it.

Finally, your error message for simplification can be improved by not setting messages for the individual entry blanks, but using a single error message for the pair, as in the code below.

Here is the pertinent code with all the changes above:

    Context("LimitedPolynomial-Strict")->variables->are(x=>"Real");
    ...
    $num = Formula((-1*$a*$c)."*x^".($d-$b));
    $den = Formula("1");
    
    $multians = MultiAnswer($num, $den)->with(
      singleResult => 1,
      allowBlankAnswers => 1,
      format => "(%s)/(%s)",
      tex_format => "\frac{%s}{%s}",
      checker => sub {
        my ( $correct, $student, $self, $ansHash ) = @_;
        my ( $f1stu, $f2stu ) = @{$student};
        my ( $f1, $f2 ) = @{$correct};
  
        Context("Numeric");
        $correct = Compute("$f1/$f2");
        $ansHash->{correct_ans} = $correct->string;
        $ansHash->{correct_ans_latex_string} = $correct->TeX;
  
        return [0,0] if $f1stu eq "" || $f2stu eq "";
        $self->{format} = Compute("$f1stu/$f2stu")->string;
   
        if ( ( $f1==$f1stu &&  $f2==$f2stu) || 
            (-$f1==$f1stu && -$f2==$f2stu) ) {
            return [1,1];
        } elsif ( $f1==$f1stu || -$f1==$f1stu) {
            return [1,0];
        } elsif ( $f2==$f2stu || -$f2==$f2stu ) {
            return [0,1];
        } elsif (Compute("$f1*$f2stu") == Compute("$f1stu*$f2")) {
            $self->context->setError("Your answer should be further simplified");
            return; # don't return values here (so message will show)
        } else {
            return [0,0];
        }
      }
    );
The rest of the problem is not modified.

Hope that helps.

Davide

In reply to Davide Cervone

Re: Problem with LimitedPolynomial

by Stacy Hoehn -
Thanks for the suggestions, especially on how to improve the answer formats!

Stacy