I can do this:
$a = random(6,10,1);
$b = random(2,5,1);
$c = random(6,10,1);
$fa = Formula("$a y")->reduce;
$fb = Formula("$b y")->reduce;
$fc = Formula("$c y")->reduce;
...
Find the general solution for the equation
\( $fa'' + $fb' + $fc = 0 \).
but it's painful, and doesn't work if I allow negative coefficients. I'd like to be able to just do
$f = Formula("$a y'' + $b y' + $c y")->reduce;
...
Find the general solution for the equation
\( $f = 0 \).
But this is errormatic. Is there a way to put a prime into a Formula?
# # Define a prime subclass of the unary operator class # package my::UOP::prime; our @ISA = ('Parser::UOP'); # # Do a typecheck on the operand # sub _check { my $self = shift; return if $self->checkInfinite || $self->checkString || $self->checkList || $self->checkNumber; $self->{type} = {%{$self->{op}->typeRef}}; } # # A hack to prevent double-primes from inserting parentheses # in string and TeX output (change the precedence to hide it) # sub string { my ($self,$precedence,$showparens,$position,$outerRight) = @_; my $uop = $self->{def}; $precedence -= .01 if $uop->{precedence} == $precedence; return $self->SUPER::string($precedence,$showparens,$position,$outerRight); } sub TeX { my ($self,$precedence,$showparens,$position,$outerRight) = @_; my $uop = $self->{def}; $precedence -= .01 if $uop->{precedence} == $precedence; return $self->SUPER::TeX($precedence,$showparens,$position,$outerRight); } # # Add prime to the given or current context # sub Enable { my $self = shift; my $context = shift || main::Context(); $context->operators->add("'"=>{ precedence => 8.5, associativity => "right", type => "unary", string => "'", class => "my::UOP::prime", isCommand => 1 }); } sub Disable { my $self = shift; my $context = shift || main::Context(); $context->operators->remove("'"); }
The Enable
routine is the one you call to add the operator to the current context. You can put the code into a macro file (either in the same directory with the problems that use it, or in the course templates/macros
directory, or somewhere else in the macros path). If you call it "parserPrime.pl", then code that uses it could look like:
loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"parserPrime.pl"
);
Context("Numeric")->variables->add(y=>'Real'); # set the context
my::UOP::prime->Enable; # add primes to it
# create $a, $b, c here
$f = Formula("$a y'' + $b y' + $c y")->reduce;
$ans = Formula("..whatever...");
Context()->texStrings;
BEGIN_TEXT
Find the general solution to \($f = 0\):
\{ans_rule(30)\}
END_TEXT
Context()->normalStrings;
my::UOP::prime->Disable; # don't allow students to enter primes
ANS(Formula($ans)->cmp);
It's a little complicated, but can be done. Note that this is for display purposes only. Primes can NOT be used in the student or correct answers, as we have not implemented the eval
method, which is needed for that. To do it right, we would also need to implement call
and perl
to handle the derivatives, though I'm not sure everything would work out for that.
Hope that helps.
Davide
Hope that helps.
Davide
PS, it would probably be possible to use d/dx(...) notation to do differentiation as well. Would that be a help to anyone?
y'
and y''
to the context as variables so that they could be used in Formulas without defining the prime operator. The difficulty is that variable names can only include alphabetic and numeric characters, an the underscore. To get around that, you need to change the name patter for variables. For example,
Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;would allow variable names to end in any number of primes. So you could do the following:
Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i; Context()->variables->add("y'"=>"Real","y''"=>"Real"); ... $f = Formula("$a y'' + $b y' + $c y")->reduce;Ideally, this would also allow you to have students give answers that have derivatives in them, but due to the way that variables are inserted into the perl-code that underlies the formulas, that will generate illegal perl variable names. I have updated MathObjects to correctly handle these variables, but you would need to update your copy of
pg/lib/Parser.pm
and pg/lib/Parser/Variable.pm
in order to take advantage of that. So until you update, this is for display purposes only.
Hope that helps.
Davide
It would be nice to allow answers with primes, so that the first question on a word problem could be what's the differential equation. Having the ability to use d/dt would be useful, but not essential. Of course, we'd need d^2/dt^2 as well, since there's probably more work with second order equations. Higher derivatives could be handled with primes, I think.
This is excellent. I'll be writing an assignment using this stuff this weekend.
parserPrime.pl
file could be used for that in a sneeky way. It would allow more flexibility in the format of answers, like (y')' would be accepted as y'', and (y+y)' would be the same as (2y)', but you might not want that flexibility.
In any case, to do this, you would need to add a "constant" that is really a formula. The constant will be shown in the correct and student answers, but the formula will be used in determining equality of the two differential equations. For example,
loadMacros("parserPrime.pl"); Context("Numeric")->constants->add(y=>Formula("x^5+sin(2x)")); parser::Prime->Enable('x'); $f = Formula("y'' + 2y' + y"); ... ANS($f->cmp);Here, the formula given for y when it is added to the constants should be something that will have different values for different derivatives, and will not be something the student is likely to type themselves. It's a bit of a hack, but I think it should work reasonably well. In any case, using
y'
and y''
as variables is also a hack.
But, in order to make this work, you will need to update your copies of pg/lib/Parser/Constant.pm
, pg/lib/Parser/Differentiation.pm
, and pg/macros/parserPrime.pl
to the most current HEAD versions. These include corrections needed for handling Formula-valued constants properly.
See if that helps.
Davide
I just updated Webwork to the rel-patches and was able to get a similar problem to work. However I wanted to use this same idea in an implicit equation, if a make a couple of changes the problem to use parserImplicitEquation I get an error I can't fix.
My code:
DOCUMENT();
# Load the macro file to create graphs.
loadMacros("PGgraphmacros.pl");
# Load whatever macros you need for the problem
loadMacros("PG.pl",
"PGbasicmacros.pl",
"PGchoicemacros.pl",
"PGanswermacros.pl",
"PGauxiliaryFunctions.pl",
"MathObjects.pl",
"parserImplicitEquation.pl");
## Show partial correct answers
$showPartialCorrectAnswers = 1;
## Display the problem information
TEXT(beginproblem());
##########################################################################
##
## Allow variable names with primes in them
##
Context("ImplicitEquation")->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;
Context()->variables->add("y'"=>"Real","y''"=>"Real");
Context()->strings->are(linear=>{},nonlinear=>{});
$linear = String(linear);
$non = String(nonlinear);
$eqn1 = ImplicitEquation("y'+y=0");
Context()->texStrings;
BEGIN_TEXT
\($eqn1\) is a \{ pop_up_list([$linear->string,$non->string]) \} differential equation.
END_TEXT
Context()->normalStrings;
ANS($linear->cmp);
ENDDOCUMENT();
Which produces the following error(s):
Error messages
Global symbol "$y" requires explicit package name at line 6 of (eval 2079). Global symbol "$oldContext" requires explicit package name at (eval 2079) line 7. Global symbol "@result" requires explicit package name at (eval 2079) line 8. Global symbol "@result" requires explicit package name at (eval 2079) line 8. at line 341 of (eval 2058) Died within ImplicitEquation::getPositiveNegativeZero called at line 299 of [PG]/macros/parserImplicitEquation.pl from within ImplicitEquation::createPoints called at line 233 of [PG]/macros/parserImplicitEquation.pl from within ImplicitEquation::new called at line 2 of (eval 2077) from within main::ImplicitEquation called at line 54 of [TMPL]/alfredLibrary/diffeq/intro/order.pg
Error details
Problem1 ERROR caught by Translator while processing problem file:alfredLibrary/diffeq/intro/order.pg **************** Global symbol "$y" requires explicit package name at line 6 of (eval 2079). Global symbol "$oldContext" requires explicit package name at (eval 2079) line 7. Global symbol "@result" requires explicit package name at (eval 2079) line 8. Global symbol "@result" requires explicit package name at (eval 2079) line 8. at line 341 of (eval 2058) Died within ImplicitEquation::getPositiveNegativeZero called at line 299 of [PG]/macros/parserImplicitEquation.pl from within ImplicitEquation::createPoints called at line 233 of [PG]/macros/parserImplicitEquation.pl from within ImplicitEquation::new called at line 2 of (eval 2077) from within main::ImplicitEquation called at line 54 of [TMPL]/alfredLibrary/diffeq/intro/order.pg **************** ------Input Read 1 ##DESCRIPTION 2 # 3 # File Created: 12/13/2009 4 # Last Modified: 12/13/2009 5 # Problem Author: Darwyn Cook 6 # WeBWorK Entry: 7 # Location: Alfred University 8 # 9 ##ENDDESCRIPTION 10 11 ##KEYWORDS() 12 ## 13 14 ## DBsubject('Calculus') 15 ## DBchapter('Differential Equations') 16 ## DBsection('Introduction to Differential Equations') 17 ## Date('12/13/2009') 18 ## Author('Darwyn Cook') 19 ## Institution('Alfred University') 20 ## TitleText1('Differential Equations: with Boundary Value Problems') 21 ## EditionText1('6') 22 ## AuthorText1('Zill') 23 ## Section1('') 24 ## Problem1('') 25 26 DOCUMENT(); 27 28 # Load the macro file to create graphs. 29 loadMacros("PGgraphmacros.pl"); 30 # Load whatever macros you need for the problem 31 loadMacros("PG.pl", 32 "PGbasicmacros.pl", 33 "PGchoicemacros.pl", 34 "PGanswermacros.pl", 35 "PGauxiliaryFunctions.pl", 36 "MathObjects.pl", 37 "parserImplicitEquation.pl"); 38 ## Show partial correct answers 39 $showPartialCorrectAnswers = 1; 40 ## Display the problem information 41 TEXT(beginproblem()); 42 43 44 ########################################################################## 45 ## 46 ## Allow variable names with primes in them 47 ## 48 Context("ImplicitEquation")->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i; 49 Context()->variables->add("y'"=>"Real","y''"=>"Real"); 50 Context()->strings->are(linear=>{},nonlinear=>{}); 51 $linear = String(linear); 52 $non = String(nonlinear); 53 54 $eqn1 = ImplicitEquation("y'+y=0"); 55 Context()->texStrings; 56 BEGIN_TEXT 57 \($eqn1\) is a \{ pop_up_list([$linear->string,$non->string]) \} differential equation. 58 END_TEXT 59 Context()->normalStrings; 60 ANS($linear->cmp); 61 ENDDOCUMENT();
Try using Formula() rather than ImplicitEquation() and see of that doesn't work for you (since you don't really need $eqn1 to be an actual ImplicitEquation object.) You are really only using ImplicitEquation context to get the equal sign into your formula; it would be possible to just enable the equal sign in Numeric context and avoid the implicit equation issues entirely. To do that, use
Context("Numeric")->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i; Context()->variables->add("y"=>"Real","y'"=>"Real","y''"=>"Real"); Context()->strings->are(linear=>{},nonlinear=>{}); Parser::BOP::equality->Allow; $eqn1 = Formula("y'+y=0");Note the addition of the variable "y" to the context as well as the equality.
I actually did fix the variable-name problem in version 1.56 of pg/lib/Parser.pm, but that hasn't made it into the patches release yet. You should be able to update just that one file (I checked and it doesn't look like any of the other changes require other files to be updated), if you prefer to go that way. I tested your problem with the current HEAD version, and it works properly there.
Hope that helps.
Davide
Thanks for the quick reply. For the purpose of the problem I am writing, which is just to display the equation, I could just TeX the formulas in the problem. An alternative I decided to use for this problem is to create a list of variables that I then give a TeX alias to.
I was trying this technique to see if I could make it work for problems where the answer will be a differential equation in prime notation. I can make that work simply enough by using formulas.
After a recent update of webwork I reinstalled the head version of Parser.pm, but it caused an error: Global symbol "$main::__files__" requires explicit package name at (eval
3373) line 6.
Are there some other files I need to upgrade to the head version to match?
It should be safe to update ALL of pg if you want to try that. But I don't think that's where the problem is.
Davide
PS, be sure to restart the server after making any of these changes.
I decided to start fresh, so I reload Parser.pm to the head version (1.56), and rebooted.
We are getting this error:
WeBWorK Warnings
WeBWorK has encountered warnings while processing your request. If this occured when viewing a problem, it was likely caused by an error or ambiguity in that problem. Otherwise, it may indicate a problem with the WeBWorK system itself. If you are a student, report these warnings to your professor to have them corrected. If you are a professor, please consult the warning output below for more information.
Warning messages
Variable "$C" is not imported at line 6 of (eval 8906)
(Did you mean &main::__files__ instead?)
From this problem:
loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"PGchoicemacros.pl",
"parserMultiAnswer.pl",
# "parserNumberWithUnits.pl",
# "parserFormulaWithUnits.pl",
# "parserFormulaUpToConstant.pl",
# "PGcourse.pl",
);
Context("Numeric");
Context()->variables->add( C=>"Real", n=>"Real" );
$showPartialCorrectAnswers = 1;
$a = random(2,4,1);
$x0 = random(2,5,1);
$y0 = random(10,50,5);
$ans0 = Formula("0 x^n");
$ans1 = Formula("C x^($a)");
$multipart = MultiAnswer($ans0, $ans1)->with(
singleResult => 0,
checker => sub {
my ( $correct, $student, $self ) = @_;
my ( $f1stu, $f2stu ) = @{$student};
my ( $f1, $f2 ) = @{$correct};
if ( ($f1 == $f1stu && $f2 == $f2stu) ||
($f1 == $f2stu && $f2 == $f1stu) ) {
return [1,1];
} else {
if ($f1 == $f1stu || $f2 == $f1stu) {
return [1,0];
} elsif ($f1 == $f2stu || $f2 == $f2stu) {
return [0,1];
} else {
return [0,0];
}
}
}
);
TEXT(beginproblem());
Context()->texStrings;
BEGIN_TEXT
${BBOLD}(a)$EBOLD
Consider the differential equation
\[ x\frac{dy}{dx} - $a y = 0. \]
$BR
Find a general solution to this differential equation that
has the form \( y = Cx^n \).
$BR
\( y = \) \{ ans_rule(35) \}.
$BR
Find a second solution \( y = Cx^n \) that might not be a
general solution and which may have a different value of \(n\)
than your first solution.
$BR
\( y = \) \{ ans_rule(35) \}.
$PAR
${BBOLD}(b)$EBOLD
If the solution additionally satisfies \(y=$y0\) when \(x=$x0\),
what is the solution?
$BR
\(y = \) \{ ans_rule(35) \}
END_TEXT
Context()->normalStrings;
# ANS( $multipart->cmp() );
ANS( $ans1->cmp() );
ANS( $ans0->cmp() );
ANS( Compute("$y0*(x/$x0)^($a)")->cmp() );
I am also having trouble with the questions that involve primes.
Here is a simple problem I had working before:
loadMacros("PG.pl",
"PGbasicmacros.pl",
"PGchoicemacros.pl",
"PGanswermacros.pl",
"PGauxiliaryFunctions.pl",
"MathObjects.pl");
TEXT(beginproblem());
#########################################################
##
## Set up the context to allow ' in variable names
##
Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;
Context()->variables->are("x"=>"Real","y"=>"Real","y'"=>"Real","y''"=>"Real");
$f = Formula("1+y'+y''")->reduce;
Context()->texStrings;
BEGIN_TEXT
$PAR
Rewrite the differential equation in prime notation: \(y(x) =1+\frac{dy}{dx}+\frac{d^2y}{dx^2}\)
then
$BR
\( y(x) = \) \{$f->ans_rule()\}
END_TEXT
ANS($f->cmp);
Context()->normalStrings;
That now returns the error
Warning messages
String found where operator expected at line 6 of (eval 10799), near "$y') + $y'"
(Missing operator before ') + $y'?)
String found where operator expected at line 6 of (eval 10799), at end of line
(Missing operator before ?)
P.S. I did a webwork update rel-2-4-patches three weeks ago, and as I mentioned above just updated Parser.pm to the HEAD version.
Also, are you sure your web server is running the updated copy of WeBWorK? Could it be that there is more than one WeBWorK on your system and it is using an older copy, and so not using the new Parser.pm?
I am not able to reproduce either error. Both problems work as expected for me.
Davide
Well I moved Parser.pm.bak back to Parser.pm and did cvs status Parser.pm again, and it also says it is version 1.56. Modulo not liking the prime notation it works just fine.
There are two problems ( I know of) that are giving me issues when Parser.pm is updated to the head version, and they both use PGchoicemacros.pl, which has the following status:
File: PGchoicemacros.pl Status: Up-to-date
Working revision: 1.8.2.1
Repository revision: 1.8.2.1 /webwork/cvs/system/pg/macros/PGchoicemacros.pl,v
Sticky Tag: rel-2-4-patches (branch: 1.8.2.1.2)
Sticky Date: (none)
Sticky Options: (none)
You might try updating the entire PG directory to HEAD, which should not be a problem. (But then, neither should going to the current Parser.pm by itself.)
When you go back to the older Parser.pm, you say it works fine except for the prime notation. Do you get the same error message for that as you do with the new Parser.pm?
Davide
In response to your second question, yes I am getting the same message, the long version is:
Warning messages
String found where operator expected at line 4 of (eval 3248), near "$K',$K'"
(Missing operator before ',$K'?)
String found where operator expected at line 4 of (eval 3248), near "',$K'',$K'"
(Missing operator before ',$K'?)
String found where operator expected at line 4 of (eval 3248), near "',$K'''"
(Missing operator before ''?)
String found where operator expected at line 6 of (eval 3248), at end of line
(Missing operator before ?)
You made the point earlier that this shouldn't happen if webwork was finding the updated Parser.pm. I think that tomorrow morning, when I am pretty well guaranteed that no students will be on, I will take a more radical approach by reinstalling pg. If that doesn't work then I will follow it up by reinstalling webwork (with the appropriate backups of course).
It is clear from your comments that this is peculiar to our system, so maybe that will clear it up?
P.S. I took your comment about having a second webwork on our server to heart. I compared the directories on our production server with a fresh install on a virtual server and didn't see anything.
Oh yeah, I learned my lesson from before, I reboot frequently :)
At any rate, no luck for me. Here is what I did in order:
1) Updated pg to the head version using cvs update -A. Reboot, get both of the error messages from above when the head version of Parser.pm is installed.
2) Moved webwork2 to webwork2_save, deleted webwork2 and reinstalled from cvs. Didn't help.
3) Moved pg to pg_save, deleted pg, reinstalled pg from cvs to the rel-2-4-patches. Updated Parser.pm to the head version. Didn't work.
Since the production version of our webwork is on a virtual server I reverted back to the snapshot I took just before starting this.
The next step for me is to get the virtual webwork I have on my laptop working. If I can get the primes working on it then it will become production :) Time to go to bed.
After I got webwork up and running I deleted Parser.pm and performed a cvs update -A Parser.pm, then rebooted. I got a missing string error, which I wasn't clever enough to copy. Updated the pg directory by cvs update -A, rebooted, and it works fine.
Time to figure out what is up the production server now I guess.
So I updated the entire pg directory to the head version again, rebooted, still didn't work. Then just for the heck of it I deleted Parser.pm and a backup I had made some time ago, Parser.pm.bak, and rebooted again. Then did the cvs to the head, rebooted again, and voila it works. Apparently the system needed to be rebooted in between deleting the files and updating from cvs.
I have to believe that the Parser.pm.bak was causing me trouble, although how that could be possible after I completely removed the pg directory last and did a "fresh install" of pg night is a mystery*. I will say that after removing the directory last night I did not reboot before reinstalling pg, which apparently was my mistake.
Oh yeah, the version of webwork on my laptop is clearly newer than the one on our production server, although they should be identical, the browser interface has clearly changed. So whatever is happening, updates don't seem to be.
*If you're wondering how a copy of Parser.pm.bak ended up in a directory that I completely removed - after my lack of success I reverted to a previous snapshot that still had that file.
Anyways, thanks again for the help Davide.
Davide