WeBWorK Problems

NumberWithUnits doesn't work with OneOf

NumberWithUnits doesn't work with OneOf

by Marc Smith -
Number of replies: 8

Hi All:

    I am writing some WeBWorK problems for engineering and need to accept numerical answers with units.  In one simple example, the student needs to compute a temperature and I would like to accept answers in either Kelvin or degree Celsius units (since these are not converted automatically).  Using the OneOf macro with the NumberWithUnits math object seems to fit this problem perfectly.  However, when I run the simple example below and enter either 300 degK or 27 degC, the problem does not accept an answer with units.  If I enter either 300 or 27, the answer is correct.  Am I doing something wrong here?  

Thanks for any help. 

DOCUMENT();

loadMacros(

    "PGstandard.pl",

    "MathObjects.pl",

    "PGML.pl",

    "parserNumberWithUnits.pl",

    "parserOneOf.pl",

);

TEXT(beginproblem());

Context("Numeric");

$T1 = NumberWithUnits( 300, "degK" );

$T2 = NumberWithUnits(  27, "degC" );

Context()->texStrings;

BEGIN_PGML

[` T_1 = [$T1],  T_2 = [$T2] `]  

Enter either temperature:  [__]{ OneOf($T1, $T2) }  (Use units in your answer.)  

END_PGML

ENDDOCUMENT();

In reply to Marc Smith

Re: NumberWithUnits doesn't work with OneOf

by Davide Cervone -

The MathObject answer checking mechanism has several layers, with different hooks that make customization possible. The OneOf object hooks into the cmp_compare() method, which is a second-level function, and calls the individual cmp_compare() methods of the different choices in the OneOf. Unfortunately, the NumberWithUnits() object hooks into a higher-level function, cmp_parse(), and that is where the unit is located and managed. So the NumberWithUnits object's cmp_parse() method is never calls, and that is why your problem is complaining about the degK.

This is certainly a limitation of the OneOf implementation, if not an outright bug. The OneOf object should probably use its top-level cmp_parse() method to call evaluate() on all the choices individual answer checkers looking for a correct answer among them, rather than taking the shortcut of calling their cmp_compare(). This was done for efficiency, but it is probably more reliable to call cmp->evaluate() instead.

Fortunately, you can do this easily enough yourself for now. You can add

package myOneOf;
our @ISA = ('parser::OneOf');

sub cmp_parse {
  my $self = shift; my $ans = shift;
  my $student = $ans->{original_student_ans};
  my $max = 0;
  foreach $choice (@{$self->{data}}) {
    my $hash = $choice->cmp->evaluate($student);
    if ($hash->{score} >= $max) {
      foreach my $name ('correct_ans', 'correct_ans_latex_string', 'correct_value') {
        $hash->{$name} = $ans->{$name};
      }
      $ans = $hash;
      $max = $hash->{score};
    }
  }
  return $ans;
}

package main;

sub myOneOf {myOneOf->new(@_)}

to the top of the problem, and then use myOneOf() in place of OneOf() and it should work with NumberWithUnits objects as well as other ones.

I will make a pull request to adjust OneOf to work this way, but for now you can use this work-around.

In reply to Davide Cervone

Re: NumberWithUnits doesn't work with OneOf

by Marc Smith -

It has taken two terms using this fix until a student notified me of a little bug.  Let's define an answer as follows:

$T1 = NumberWithUnits( 1,  "degC" );

$T2 = NumberWithUnits( 2,  "degK" );

Enter the answer 1 degC or 2 degK.

a) What is the answer?  [__]{ myOneOf($T1,$T2) }

If I enter a correct value with incorrect units, I get a Result that the answer is incorrect and a Message that the units are wrong.  If I enter 3 degK as the answer, I get a Result that the answer is incorrect and no Message about incorrect units.  So far so good.  If I enter 3 degC as the answer, I get a Result that the answer is incorrect and a Message that the units are wrong, even though they are correct.  I have also attached a .pg file that demonstrates this problem.

I don't know the current status of the pull request on this fix for OneOf working with NumberWithUnits, but is there a way to fix this other issue or should I just wait and tell my students to ignore incorrect unit messages like this for now.

Thanks for any advice.  


In reply to Marc Smith

Re: NumberWithUnits doesn't work with OneOf

by Glenn Rice -

I am sorry, but I do not understand why 3 degC should be correct.  3 degC is not equal to either 1 degC or 2 degK (even with a conversion which the current implementation does not support).  If I enter either 1 degC or 2 degK the answer is reported as correct.

Currently there is no pull request to fix OneOf with NumberWithUnits.

In reply to Glenn Rice

Re: NumberWithUnits doesn't work with OneOf

by Marc Smith -
Hi Glenn:
Thanks for answering. The answer 3 degC is reported as incorrect, which it should. But the feedback Message along with this says that the units are incorrect, but they are actually correct. This feedback message should not appear. It works correctly when 3 degK is entered (marked as incorrect but no message about incorrect units).
I mentioned the pull request because Davide said in his response that he would do this. I guess he didn't.
In reply to Marc Smith

Re: NumberWithUnits doesn't work with OneOf

by Boyd Duffee -
Hi Marc,

Sorry for the late reply, but my experience with NumberWithUnits is that it already does the conversion for you, such that

$T1 = NumberWithUnits( 300, "degK" );
ANS( $T1->cmp );

should accept either "300 degK" or "26.85 degC". I haven't used it with PGML, but that's how it works with old school MathObjects. If you want to avoid that difference of 0.15 degrees, you'll want to set the tolerance
https://webwork.maa.org/wiki/NumericalTolerance
In reply to Boyd Duffee

Re: NumberWithUnits doesn't work with OneOf

by Alex Jordan -

Unit equivalencies can only work with units that are scales of one another.

See:

https://github.com/Alex-Jordan/pg/blob/7446ffc02800b59fe9cb6bc788ffd327ff2c2419/lib/Units.pm#L36

In reply to Alex Jordan

Re: NumberWithUnits doesn't work with OneOf

by Boyd Duffee -
Sorry, my mistake. I'd avoided using NumberWithUnits for thermodynamics problems because they don't display nicely in LaTeX (degC and degK instead of °C and K) so I hadn't run into that issue.