WeBWorK Problems

Error Message Based on Inputs

Error Message Based on Inputs

by Sam Nelson -
Number of replies: 7

Hi there,


Essentially I am trying to give students specific feedback based on their inputs. I have gotten by so far using the following code:

ANS($someValue->cmp()->withPostFilter(AnswerHints(

-$someValue => ["Check the sign of your answer",score=>.25]

    )));

This has worked for the most basic of problems when the most common student mistakes are just mixing up their signs or frames of reference. What I am now trying to do is give a specific response if 3 different answers are all the negative version of the actual answer. This seems like it should be possible using some sort of if statement, but my Perl knowledge is limited. Rather than just saying "Check the sign of your answer", I would like to give a message saying that the frame of reference used to find 3 particular values were wrong. Any help would be appreciated!


Thanks,

Sam

In reply to Sam Nelson

Re: Error Message Based on Inputs

by Danny Glin -

When you say "3 different answers", do you mean the answers that the student enters in three different blanks all have the opposite sign?

If so, you'll probably want to use MultiAnswer (https://webwork.maa.org/wiki/MultiAnswerProblems).  This allows you to check multiple answers together.  The example on that page should show you how to do what you want.  If you get stuck you can post more detail and/or a code snippet.

In reply to Danny Glin

Re: Error Message Based on Inputs

by Sam Nelson -

Hi Danny,

Yes, that is what I meant by 3 different answers, I was referring to 3 different student inputs. I have solved the original problem using MultiAnswer as you suggested, although the string of ifs and elsifs I had to incorporate was less than pretty. Is it possible to use both MultiAnswer and regular answer evaluators? In this problem I had two parts, one where I just needed regular answer evaluators and the second part I wanted specific feedback to go through. I have gotten a syntax error trying to use both kinds of evaluators, but I was hoping I wouldn't have to include the first 3 answer checkers in with the MultiAnswer to avoid making more elsif statements. Do you know if this is possible? I can share the code I have if you think that would be useful.

Thanks, 
Sam

In reply to Sam Nelson

Re: Error Message Based on Inputs

by Glenn Rice -

If you are willing to share the code, that would certainly help.  We can give you tips on how to clean it up.

In reply to Glenn Rice

Re: Error Message Based on Inputs

by Sam Nelson -
I have included my code below, I am trying to add another section to the problem that simply checks $Frx, $Fry, and $Frz without anything special.

Thanks for any tips in advance!

DOCUMENT();

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

Context("Numeric");
Context()->flags->set(
tolerance => .01, # the relative or absolute tolerance
tolType => 'relative', # or 'absolute'
);

# 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
#
#


$F1 = random(150, 450, 75);

$F2x = random(-100, -300, 50);

$F2y = random(200, 500, 100);

$F2z = random(-200, -500, 100);

$F3 = random(350, 600, 50);

$d1 = random(4, 6, .5);

$d2 = random(2, 3, .5);

$d3 = random(2, 3, .5);

$FRx = Compute("($F2x)");

$FRy = Compute("$F3+$F2y");
$FRz = Compute("$F2z-$F1");

$MRox = Compute("(-($d1*$F1)+($d1*$F2z))");
$MRx = -$MRox;
$MRoy = Compute("-($d2*$F2z)");
$MRy = -$MRoy;
$MRoz = Compute("((-$d1*$F2x+$d2*$F2y)+$d2*$F3)");
$MRz = -$MRoz;

$multians = MultiAnswer($MRox, $MRoy, $MRoz)->with(
singleResult => 0,
checker => sub {
my ( $correct, $student, $self ) = @_;
my ( $mxstu, $mystu, $mzstu ) = @{$student};
my ( $MRox, $MRoy, $MRoz ) = @{$correct};
if ( $MRox == $mxstu && $MRoy == $mystu && $MRoz == $mzstu) {
return [1,1,1];
} else {
if (-$MRox == $mxstu && $MRoy == $mystu && $MRoz == $mzstu) {
$self->setMessage(1,"Check the sign of your answer");
return [0,1,1];
} elsif ($MRox == $mxstu && -$MRoy == $mystu && $MRoz == $mzstu) {
$self->setMessage(2,"Check the sign of your answer");
return [1,0,1];
} elsif ($MRox == $mxstu && $MRoy == $mystu && -$MRoz == $mzstu) {
$self->setMessage(3,"Check the sign of your answer");
return [1,1,0];
} elsif ($MRox == $mxstu && -$MRoy == $mystu && -$MRoz == $mzstu) {
$self->setMessage(2,"Check the sign of your answer");
$self->setMessage(3,"Check the sign of your answer");
return [1,0,0];
} elsif (-$MRox == $mxstu && $MRoy == $mystu && -$MRoz == $mzstu) {
$self->setMessage(1,"Check the sign of your answer");
$self->setMessage(3,"Check the sign of your answer");
return [0,1,0];
} elsif (-$MRox == $mxstu && -$MRoy == $mystu && $MRoz == $mzstu) {
$self->setMessage(1,"Check the sign of your answer");
$self->setMessage(2,"Check the sign of your answer");
return [0,0,1];
} elsif (-$MRox == $mxstu && -$MRoy == $mystu && -$MRoz == $mzstu) {
$self->setMessage(1,"Your frame of reference was backwards, the components of your moment have the wrong sign");
return [0,0,0];
} elsif ($MRox == $mxstu && $MRoz == $mzstu) {
return [1,0,1];
} elsif ($MRoz == $mzstu && $MRoy == $mystu) {
return [0,1,1];
} elsif ($MRox == $mxstu) {
return [1,0,0];
}elsif ($MRoy == $mystu) {
return [0,1,0];
}elsif ($MRoz == $mzstu) {
return [0,0,1];
} elsif ($MRox == $mxstu && $MRoy == $mystu) {
return [1,1,0];
}else {
return [0,0,0];
}
}
}
);

Context()->texStrings;
BEGIN_TEXT

Replace the force system by an equivalent resultant force and moment at point O where F1 is \( $F1 \)lbs, F2 is (\( $F2x \)i ,\( $F2y \)j ,\( $F2z \)k)lbs , F3 is \( $F3 \)lbs, and d1 is \( $d1 \)ft, d2 is \( $d2 \)ft, and d3 is \( $d3 \)ft.
$BR
$BR
$BCENTER
\{ image( "Q4.jpg", width=>500, height=>500,
tex_size=>700, extra_html_tags=>'alt=" "' ) \}
$ECENTER
$BR
$BR
The moment about point O is
(\{$multians->ans_rule(10)\}i, \{$multians->ans_rule(10)\}j, \\{$multians->ans_rule(10)\}k)lbs*ft
$BR
END_TEXT
Context()->normalStrings;

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

# tolerance is set to be within 1 percent (0.01)
# if the answer is negative but otherwise correct,
# the student gets partial credit and is notified of their mistake

ANS( $multians->cmp() );

ENDDOCUMENT();
In reply to Sam Nelson

Re: Error Message Based on Inputs

by Alex Jordan -

I made a version of your problem, pasted below). Overall, we (the WeBWorK community) have a problem in that so much of the OPL and even the wiki demonstrates old (or in some cases bad) coding techniques. And then these things propagate when people naturally use them for templates.

The main things I changed are:

  • eliminated stuff from your preamble that is not used
  • switched from the TEXT method of problem statement to PGML
  • condensed the code for your multians
I also made some cosmetic changes.

I did not have the image file that this uses, so I'm not sure what that looks like. But one more thing I might have changed would be to draw that image directly using tikz. As of WW 2.16 it is possible to do that. It's nice to not have to manage separate image files that pair with a problem file.

Either way, you should write some alt text for the image. As of WW 2.16, you can add alt text in a straightforward way as I put in the code below.

Lastly, I think that in your setup with the definitions of $F1 through $MRz, you may have some unnecessary things in there. But I didn't want to think too hard about what I could cut.

DOCUMENT();

loadMacros(
    "PGstandard.pl", # Standard macros for PG language
    "MathObjects.pl",
    "parserMultiAnswer.pl",
    "PGML.pl",
    "PGcourse.pl",
);

Context("Numeric");
Context()->flags->set(
    tolerance => .01, # the relative or absolute tolerance
);

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

$F1 = random(150, 450, 75);

$F2x = random(-100, -300, 50);
$F2y = random(200, 500, 100);
$F2z = random(-200, -500, 100);

$F3 = random(350, 600, 50);

$d1 = random(4, 6, .5);
$d2 = random(2, 3, .5);
$d3 = random(2, 3, .5);

$FRx = Compute("($F2x)");
$FRy = Compute("$F3+$F2y");
$FRz = Compute("$F2z-$F1");

$MRox = Compute("(-($d1*$F1)+($d1*$F2z))");
$MRx = -$MRox;
$MRoy = Compute("-($d2*$F2z)");
$MRy = -$MRoy;
$MRoz = Compute("((-$d1*$F2x+$d2*$F2y)+$d2*$F3)");
$MRz = -$MRoz;

$multians = MultiAnswer($MRox, $MRoy, $MRoz)->with(
    singleResult => 0,
    checker => sub {
        my ( $correct, $student, $self ) = @_;
        # Figure out which ones are correct
        $return = [
            $correct->[0] == $student->[0],
            $correct->[1] == $student->[1],
            $correct->[2] == $student->[2]
        ];
        # Special feedback
        if (-$correct->[0] == $student->[0] &&
            -$correct->[1] == $student->[1] &&
            -$correct->[2] == $student->[2])
        {
            for my $i (1,2,3) {$self->setMessage($i,"Your frame of reference was backwards, the components of your moment have the wrong sign");}
        } else {
            for my $i (1,2,3) {$self->setMessage($i,"Check the sign of your answer") if (-$correct->[$i-1] == $student->[$i-1]);}
        }
        # Return results
        return $return;
    }
);

##############################################################
# Statement
#

BEGIN_PGML

Replace the force system by an equivalent resultant force and moment at point [`O`]
where [`F_1`] is [`[$F1]\,\text{lbs}`], [`F_2`] is
[`\left([$F2x]\hat{\imath} + [$F2y]\hat{\jmath} + [$F2z]\hat{k}\right)\,\text{lbs}`],
[`F_3`] is [`[$F3]\,\text{lbs}`], and
[`d_1`] is [`[$d1]\,\text{ft}`],
[`d_2`] is [`[$d2]\,\text{ft}`], and
[`d_3`] is [`[$d3]\,\text{ft}`].

>> [@image( "Q4.jpg", width => 500, height => 500, tex_size => 700, alt => 'some alt text here')@]* <<

The moment about point [`O`] is
[`\Big(`][_]{$multians}{10}[`\hat{\imath}+{}`]
[_]{$multians}{10}[`\hat{\jmath}+{}`]
[_]{$multians}{10}[`\hat{k}\Big)\,\text{lbs}\cdot\text{ft}`].

END_PGML

ENDDOCUMENT();
In reply to Alex Jordan

Re: Error Message Based on Inputs

by Sam Nelson -

Hi Alex,

I really appreciate you taking the time to clean this up so much. I will take much of the advice you've given here moving forward. One question I still had was whether it was possible to have a second set of question boxes for the students to fill in separate from the multi answer section. Originally to get it working I just separated the question into two unique problems, but the first half of the question originally had elements of code that I've shared below in it too which cause errors if I added them in. Do you know if there are any resources available for learning about PGML methods? Most of the problems I've seen on the wiki use text so that's just what I've learned to use. Thanks again for all of your help, it has been very informative.

Thanks,

Sam

(within my original TEXT method)

The resultant force for the system is

(\{ ans_rule(20) \}i, \{ ans_rule(20) \}j, \{ ans_rule(20) \}k)lbs.



ANS($FRx->cmp->withPostFilter(AnswerHints(

      -$FRx => ["Check the sign of your answer",score=>.25]

    )));

ANS($FRy->cmp->withPostFilter(AnswerHints(

      -$FRy => ["Check the sign of your answer",score=>.25]

    )));

ANS($FRz->cmp->withPostFilter(AnswerHints(

      -$FRz => ["Check the sign of your answer",score=>.25]

    )));


In reply to Sam Nelson

Re: Error Message Based on Inputs

by Alex Jordan -

I'm not sure what would explain the errors before, but once you are using PGML, you can declare answers using the [_]{$answer}{width} method that is in the code that I posted, and you don't need to use the ANS() routine. In that code, each answer was the same $multians object, but you can add more things.

The "$answer" in what I wrote above can be a MathObject or some string that can be passed to Compute() thereby creating a MathObject. But it can also be a MathObject's cmp, except that to avoid syntax issues I usually store that as something before the statement part of the question.

You should be able to add the following to the setup portion from before:

$Frxcmp = $FRx->cmp->withPostFilter(AnswerHints(-$FRx => ["Check the sign of your answer",score=>.25]));

$Frycmp = $FRy->cmp->withPostFilter(AnswerHints(-$FRy => ["Check the sign of your answer",score=>.25]));

$Frzcmp = $FRz->cmp->withPostFilter(AnswerHints(-$FRz => ["Check the sign of your answer",score=>.25]));

And then within the PGML, have things like:

[_]{$Frxcmp}{10}