Find the equation of the line parallel to $x+y=4$ and going through (2,4).
I want the solution to be inputted in a way so that one side of th equation would be zero, so for this problem's solution (x+y=6), I would like to accept
x+y-6, 2x+2y-12, -x-y+6, etc.
So I would like to use an adapted parameter, and I've implemented this.
However, if a student simply puts in 0, then their answer is also scored as correct.
So I tried tinkering with the routine to make 0 not be a correct answer.
I would like to make this routine available for a variety of problems, and I don't want to cut and paste the entire subroutine in each .pg file, so I want to write a macro for it. In order to use this adaptive parameter, I need access to the context of the problem, so I came up with the following code for my macro:
sub scalarEquation_cmp {
my ($correct, $student, $ah ) = @_;
return 0 if $student == Formula(0);
my $context = $ah->{correct_value}->{context}->copy;
$context->flags->set(no_parameters=>0);
$context->variables->add('C0'=>'Parameter');
$student = Formula($context,$student);
$correct = Formula($context,"C0*(".$ah->{correct_value}.")");
return $correct == $student;
}
So my question is: is this the best way to code this? Mind you, I'm trying to maintain another's code, and so my follow-up question is: is there a better way to format the question to check the answer? I should say we are emphasizing the Ax+By+C=0 format for the equation of a line, so I would like to guarantee the student's input is of that form.
Thanks,
Mike Schroeder
sub scalarEquation_cmp { my ($correct, $student, $ah ) = @_; if ($student == Formula(0)) { return 0 if $ah->{isPreview}; Value->Error("Your answer should be a formula that is not always 0"); } my $context = $correct->context->copy; $context->flags->set(no_parameters=>0); $context->variables->add(C0=>'Parameter'); $student = Formula($context,$student); $correct = Formula($context,"C0*$correct"); return $correct == $student; }Here we produce a hint if the student enters a formula equivalent to 0 rather than just marking it incorrect. You can also use
$correct
for the correct answer rather than having to go to $ah->{correct_value}
. I would have recommended using
$student = $student->inContext($context); $correct = ($correct->inContext($context))*"C0";as being more efficient internally, except that
inContext()
was broken for Formula obejcts (ouch). I have just corrected that in the HEAD version of the CVS archive, but your approach works fine. Note that I have substituted $correct into the string rather than using the dot notation; Formulas automatically insert parentheses for themselves in such circumstances so you can do exactly this.
Hope that helps.
Davide
PS, if you do
$scalarEquation_cmp = sub scalarEquation_cmp { ... };then you can use
ANS($f->cmp(checker=>$scalarEquation_cmp));without the nasty
~~&
notation.
PPS, have you considered using the parserImplicitPlane.pl
macros instead, which also implement implicit lines (or hyperplanes, or linear objects in any dimension)? See
the documentation for more details.
Please inform your instructor that an error occurred while checking your answer at [PG]/lib/Value/AnswerChecker.pm line 247
I've tried to run this down, but to no avail. Any ideas?Mike
Davide
-Mike
## DESCRIPTION
## given a point and "parallel to..."
## ENDDESCRIPTION
## KEYWORDS('line')
## DBsubject('Algebra')
## DBchapter('Equations')
## DBsection('Linear')
## Date('Monday, 4 June 2007')
## Author('Rob Owen')
## Institution('UW-Madison')
## TitleText1('College Algebra')
## EditionText1('Fifth Edition')
## AuthorText1('David Cohen')
## Section1('1.6')
## Problem1('1.6.28')
DOCUMENT();
loadMacros(
"PGbasicmacros.pl",
"MathObjects.pl",
"UWMadisonMacros.pl");
$showPartialCorrectAnswers = 1;
############################
$absx = 3;
$y = 4;
############################
TEXT(beginproblem());
BEGIN_TEXT
$PAR
Find the equation of the line that passes through the point
\( (-$absx, $y) \) and is parallel to the \( y \)-axis.
Write your answer in the form \( A x + B y + C = 0 \).
$PAR
\( \hspace{.25in} \mbox{Line is:} \) \{ ans_rule(20) \} \( = 0 \)
END_TEXT
############################
$f = Compute("x + $absx");
ANS($f->cmp(checker=>~~&scalarMultipleEquation_cmp));
############################
ENDDOCUMENT();
Mike
WeBWorK attempts to inform a student when they enter an equivalent (not not identical) expression (to help them learn what differences are actually important in an expression), and to do the test, it does a comparison of the old student answer with the new one. It does this using the answer checker so that "equivalent" is interpreted as it is in the actual problem. Unfortunately, the first time through, there IS no old student answer, but the custom checker is called anyway, and the error message you are getting is due to $correct not being defined in that case (it is supposed to be the old answer).
The fix is simple enough; just at one line at the top of the checker:
sub scalarMultipleEquation_cmp { my ($correct, $student, $ah ) = @_; return 0 unless defined $correct; if ($student == Formula(0)) { return 0 if $ah->{isPreview}; Value->Error("Your answer should be a formula that is not always 0"); } my $context = $correct->context->copy; $context->flags->set(no_parameters=>0); $context->variables->add(C0=>'Parameter'); $student = Formula($context,$student); $correct = Formula($context,"C0*$correct"); return $correct == $student; }I didn't catch it when I was testing the routine because by the time I had the correct routine, there was already a previous answer. :-)
Davide
Is there a fix for this? Thanks.
A solution is to add a check for whether the CORRECT answer is zero as well:
sub scalarMultipleEquation_cmp { my ($correct, $student, $ah ) = @_; return 0 unless defined $correct; if ($student == Formula(0)) { return 0 if $ah->{isPreview}; Value->Error("Your answer should be a formula that is not always 0"); } return 0 if $correct == Formula(0); my $context = $correct->context->copy; $context->flags->set(no_parameters=>0); $context->variables->add(C0=>'Parameter'); $student = Formula($context,$student); $correct = Formula($context,"C0*$correct"); return $correct == $student; }
I think that should take care of it for you.
Davide
first, then follow with
(where right_answer is, obviously, the formula for the correct answer, expressed in terms of the variables x and y). Am I just unlucky?
Can you send the current version of you problem file and the answer checker, so I'm sure we are working with the same thing? Also, the problem seed that you are using, in case that makes a difference? Finally, what message is in the results table at the top of the page when you get the error about reporting the problem to the instructor? (It should include the actual perl error message there.)
Thanks.
Davide
DOCUMENT();
loadMacros(
"Parser.pl",
"PG.pl",
"MathObjects.pl",
"PGstandard.pl",
"PGchoicemacros.pl",
"PGbasicmacros.pl"
);
sub scalarMultipleEquation_cmp {
my ($correct, $student, $ah ) = @_;
return 0 unless defined $correct;
if ($student == Formula(0)) {
return 0 if $ah->{isPreview};
Value->Error("Your answer should be a formula that is not always 0");
}
return 0 if $correct == Formula(0);
my $context = $correct->context->copy;
$context->flags->set(no_parameters=>0);
$context->variables->add(C0=>'Parameter');
$student = Formula($context,$student);
$correct = Formula($context,"C0*$correct");
return $correct == $student;
}
#################################################
Context("Numeric");
Context()->variables->are(x=>'Real',y=>'Real');
Context()->flags->set(reduceConstants => 0);
Context()->flags->set(reduceConstantFunctions => 0);
$a = random(2,5,1);
$b = random(2,6,1);
$x_disp = "$b \cos $a t";
$y_disp = "$b \sin $a t";
$end_t = Formula("pi/$a");
$end_t_disp = "\frac{\pi}{$a}";
$left_hand_side = Formula("x^2 + y^2 - $b^2");
$x0=Formula("-$b");
$x1=Formula("$b");
$y0=Formula("0");
$y1=Formula("$b");
##########################################
# Multiple choice:
$correct_ans = "the movement is counter-clockwise";
$question = "(1) As \(\;t\;\) increases on \(\left[0, $end_t_disp\right]\), in which direction is the point \( (x(t), y(t))\) moving?";
$mc = new_multiple_choice();
$mc->qa("$question","$correct_ans");
$mc->extra("the movement is counter-clockwise","the movement is clockwise");
$mc->makeLast("the movement is counter-clockwise","the movement is clockwise");
#################################################
TEXT(beginproblem());
Context()->texStrings;
BEGIN_TEXT
$PAR
A particular curve is represented parametrically by
$PAR
\( x = $x_disp\), \( \;\;\; y=$y_disp, \) \(\;\;\; t\in \left[0, $end_t_disp\right].\)
$PAR
----------------------------------------------------------------------------------
$PAR
\{ $mc->print_q() \}
\(\;\;\;\) \(\;\;\;\) \(\;\;\;\)\(\;\;\;\) \{ $mc->print_a() \}
$PAR
----------------------------------------------------------------------------------
$PAR
(2) What is the corresponding Cartesian equation for this curve (the equation in \(\;x\;\) and \(\;y\;\) only)?
$PAR
\(\;\;\;\) \(\;\;\;\) \(\;\;\;\) Cartesian equation: \{ ans_rule(30) \} \(\;=0\).
$PAR
$BITALIC Write your answer as an expression in \(\; x \;\) and \(\; y \;\) which is the left-hand side of the equation when the right-hand side is set equal to zero. For example, the equation of the parabola \(y = x^2+1\) can be rewritten as \(y-x^2-1 =0 \), so your answer would be \(y-x^2-1\). Write the equation of the full curve, even if only part of the curve is given by the parametrization. $EITALIC
$PAR
----------------------------------------------------------------------------------
$PAR
(3) Give the smallest and largest values of \(y\) taken by this curve (both $BITALIC inf $EITALIC and $BITALIC -inf $EITALIC are possible answers.)
$PAR
\(\;\;\;\) \(\;\;\;\) \(\;\;\;\)
\{ans_rule(5)\} \(\le y \le \) \{ans_rule(5)\}.
$BR ---------------------------------------------------------------------------------- $BR
END_TEXT
##################################################
Context()->normalStrings;
Parser::Number::NoDecimals();
Context()->flags->set(formatStudentAnswer=>'parsed');
Context()->flags->set(
tolerance => .000001,
tolType => 'relative',
limits => [-4,4],
num_points => 5,
);
ANS(radio_cmp( $mc->correct_ans() ) );
ANS($left_hand_side->cmp(checker=>~~&scalarMultipleEquation_cmp));
ANS($y0->cmp);
ANS($y1->cmp);
############################################
Context("Numeric");
Context()->texStrings;
#############################################
#### the written explanation + answer is given below
#### -- it's available for TAs and professor at any time (complete answer)
#### -- it's available for students when the date for solutions has passed
#### (only a brief guide to the answer is given for the students; they
#### can always see the final numerical answer in the answer box).
Context("Numeric");
Context()->texStrings;
if ($permissionLevel >= 5) { #solution for TAs and professor
SOLUTION(EV3(<<'END_SOLUTION'));
$PAR SOLUTION for PROFESSORS and TAs $PAR
The curve is an upper-semi-circle of radius $b$, with formula \(x^2 + y^2 - $b^2 = 0\).
END_SOLUTION
}
install_problem_grader(sub {
my ($result,$state) = std_problem_grader(@_);
my $time = time();
my $open = $time >= $openDate && $time <= $dueDate;
my $submit = $inputs_ref->{submitAnswers};
my $attempts = $state->{num_of_correct_ans} + $state->{num_of_incorrect_ans};
$attempts-- if $attempts && !$submit;
my @msg = ();
push(@msg,"Your score was ".($open ? "" : "not "). "recorded.") if $submit;
push(@msg,"You have attempted this problem $attempts time".($attempts == 1 ? "." : "s."));
if ($submit) {
if ($result->{score} == 1) {
push(@msg,"You received a score of 100% for this attempt.");
push(@msg,"Your overall recorded score is 100%.");
} else {
push(@msg,"Your answers are not yet fully correct.");
}
}
unless ($open) {
push(@msg,"The homework set is not yet open.") if $time < $openDate;
push(@msg,"The homework set is closed.") if $time > $dueDate;
}
$result->{summary} = '<DIV CLASS="ResultsWithError">Not all the answers above are correct.</DIV>' unless $result->{score} == 1;
$state->{state_summary_msg} = join('<br>',@msg);
return ($result,$state);
});
ENDDOCUMENT();
If the answer 0 (i.e., for 0=0) is given and checked, followed by an answer which is twice the correct answer (or even equals the correct answer), a pink screen appears and the following warning is given:
Warning messages
Please inform your instructor that an error occurred while checking your answer at [PG]/lib/Value/AnswerChecker.pm line 247
(In my testing, the other 3 answers for the problem are left blank.)
Here's the result table at the top of the warning page -- I'm not sure what you mean about a perl error appearing here:
Entered | Answer Preview | Correct | Result |
---|---|---|---|
A | incorrect | ||
2*[(x^2)+(y^2)-(6^2)] | x^2+y^2-6^2 | correct | |
0 | incorrect | ||
6 | incorrect |
The problem seems to be the extraneous
Context("Numeric"); Context()->texStrings;near the bottom of the problem (there are two copies). These are not needed since you don't make any new MathObjects after that, but the fact that the context has changed is, I think, causing the Formula comparisons to fail in the checker, since formulas can only be compared to ones in the same context, and the Formula(0) calls will create ones in the current context, not the context of the correct answer, when the checker is called to test the past answer against the current answer. (The current context is set to that of the correct answer during the check of the student's answer to the professor's answer, but not when the previous student answer is checked against the current one.)
The solution is to force the Formula(0) into the correct context. Here is some more code to try:
sub scalarMultipleEquation_cmp { my ($correct, $student, $ah ) = @_; return 0 unless defined $correct; my $context = $correct->context; if ($student == Formula($context,"0")) { return 0 if $ah->{isPreview}; Value->Error("Your answer should be a formula that is not always 0"); } return 0 if $correct == Formula($context,0); $context = $context->copy; $context->flags->set(no_parameters=>0); $context->variables->add(C0=>'Parameter'); $student = Formula($context,$student); $correct = Formula($context,"C0*$correct"); return $correct == $student; }At least this seems to work for me. Hope it does for you, too.
Davide
PS, the reason that you didn't see an error message in the results table is that the failure wasn't during the main check (student vs. professor) but in the check for equivalent answers (student vs past student), which doesn't add anything to the results table. Sorry for the confusion on that.
The problem seems to be the extraneous
Context("Numeric");
Context()->texStrings; A-ha, yes. It's working now -- many thanks! -Patti
-
$end_t_disp
could be obtained from$end_t->TeX
to be sure that the two formulas always correspond correctly. Alternatively, if you setContext()->texStrings
before defining$question
, you could just use the value of$end_t
directly, as it would turn itself into a TeX string when inserted into the question.
I don't think you want to use Formula's for
$x0
, $x1
, $y0
, and $y1
, as these will produce the wrong type of error messages when students type the wrong things. You should use Real()
or Compute()
to get these values, as in
$x0 = Real(-$b); $x1 = Real($b); $y0 = Real(0); $y1 = Real($b);
Davide
As for the Formula with $x0, etc -- point taken. I should mention that this code is a template for several different problems where the $x0 variable is actually a formula in some cases; so I kept the "Formula" in place even when constants were used. Can you give me an example of the wrong type of error message that might be produced if a student gives an incorrect answer? So far I haven't run into this.
Many thanks for the help.
-Patti
Davide
-Patti