PREP 2015 Question Authoring - Archived

LimitedVector context?

LimitedVector context?

by Alice McLeod -
Number of replies: 10
I'm experimenting with some simple vector problems, since I'll be teaching an introductory Linear Algebra course next fall.

As a first attempt, I made this problem:

*** BEGIN CODE ***

DOCUMENT();

loadMacros("PGstandard.pl",
"MathObjects.pl",
"PGML.pl");

Context("Vector");

$v1 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));
$v2 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));

TEXT(beginproblem());
BEGIN_PGML
[$v1] + [$v2] = [________]{Compute("$v1+$v2")}
END_PGML

ENDDOCUMENT();

*** END CODE ***

The trouble with this problem is that the student can enter a sum of two vectors as their answer, instead of calculating the sum and entering a single vector as an answer. In this problem I'm checking if the student understands how to add two vectors, so that's undesirable.

Reading the wiki, I found:
http://webwork.maa.org/pod/pg_TRUNK/macros/contextLimitedVector.pl.html

which made me think that I could fix the problem by inserting

Context("LimitedVector");

However, when I do that, I get an error message containing:

ERRORS from evaluating PG file:
 Unknown context 'LimitedVector' at line 136 of [PG]/macros/Parser.pl Died within main::Context called at line 8 of (eval 2165)


What am I doing wrong?
In reply to Alice McLeod

Re: LimitedVector context?

by Paul Pearson -
Hi Alice,

You need to load the contextLimitedVector.pl macro file in order to be able to use the LimitedVector context.  Also, since the operation of addition of MathObject vectors is not allowed in the LimitedVector context (for students and for problem authors), you should create some Perl arrays, perform the addition operation on the Perl arrays, and then promote the Perl arrays to MathObject vectors.  The .pg file included below has some comments in with the code that explain what is going on.

I have also included an example of how to require vectors to be constructed and entered using (a,b,c) notation instead of <a,b,c> notation.  This requires creating a macro file parserCustomization.pl and placing it in the same directory as the .pg problem file or in the course templates/macros directory.  You will also need to uncomment the line in the .pg file below that loads parserCustomization.pl in order to get it to work.  The documentation for this can be found at:
  • https://raw.githubusercontent.com/openwebwork/pg/master/macros/parserCustomization.pl

  • http://webwork.maa.org/wiki/Course-Wide_Customizations

Note: There are two files below (one .pg problem file and one .pl macro file).

Best regards,

Paul Pearson


###########  BEGIN PG FILE ####################

DOCUMENT();

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"PGML.pl",
"contextLimitedVector.pl",
#"parserCustomization.pl", # uncomment this for (a,b,c) vectors
"PGcourse.pl",
);

Context("LimitedVector");

# Create some Perl arrays
@v1 = (random(-10,10,1),random(-10,10,1),random(-10,10,1));
@v2 = (random(-10,10,1),random(-10,10,1),random(-10,10,1));
@v3 = ();

# Fill the @v3 array with entries that are the sum of entries from @v1 and @v2.
foreach my $i (0..$#v1) { # Note: $#v1 returns one less than the number of entries in @v1 
  $v3[$i] = $v1[$i] + $v2[$i]; 
}

# Promote the Perl arrays to MathObject vectors.
# Note: We cannot get $V3 by adding $V1 and $V2 since addition of MathObject 
# vectors is not allowed in the LimitedVector context for students and for problem authors.
# That's why we added them above as Perl arrays.
$V1 = Vector( @v1 );
$V2 = Vector( @v2 );
$V3 = Vector( @v3 );


TEXT(beginproblem());
BEGIN_PGML
[` [$V1]  + [$V2] `] = [__________________]{$V3}
END_PGML

ENDDOCUMENT();

############# END PG FILE ##################



########### BEGIN CUSTOM MACRO FILE ##########
# save as parserCustomization.pl

################################################################################
# WeBWorK Online Homework Delivery System
# Copyright � 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
# $CVSHeader$
# This program is free software; you can redistribute it and/or modify it under
# the terms of either: (a) the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version, or (b) the "Artistic License" which comes with this package.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
# Artistic License for more details.
################################################################################

=head1 NAME

parserCustomization.pl - Placeholder for site/course-local customization file.

=head1 DESCRIPTION

Copy this file to your course templates directory and put any
customization for the Parser that you want for your course
here.  For example, you can make vectors display using
ijk notation (and force students to use it for entering
vectors) by using:

$context{Vector} = Parser::Context->getCopy("Vector");
$context{Vector}->flags->set(ijk=>1);
$context{Vector}->parens->remove('<');

To allow vectors to be entered with parens (and displayed with
parens) rather than angle-brakets, use

$context{Vector} = Parser::Context->getCopy("Vector");
$context{Vector}->{cmpDefaults}{Vector} = {promotePoints => 1};
$context{Vector}->lists->set(Vector=>{open=>'(', close=>')'});

(This actually just turns points into vectors in the answer checker
for vectors, and displays vectors using parens rather than angle
brackets.  The student is really still entering what MathObjects
thinks is a point, but since points get promoted automatically, that
should work.  But if a problem checks if a student's value is actually
a Vector, that will not be true.)

=cut

sub _parserCustomization_init {}

#$context{Vector} = Parser::Context->getCopy("Vector");
#$context{Vector}->flags->set(ijk=>1);
#$context{Vector}->parens->remove('<');

# See http://webwork.maa.org/wiki/Course-Wide_Customizations
# See https://raw.githubusercontent.com/openwebwork/pg/master/macros/parserCustomization.pl


$context{Vector} = Parser::Context->getCopy("Vector");
$context{Vector}->lists->set(Vector=>{open=>'(', close=>')'});
$context{Vector}->parens->set('('=>{type=>'Vector'});
$context{Vector}->parens->remove('<');

1;

########### END CUSTOM MACRO FILE ############

In reply to Paul Pearson

Re: LimitedVector context?

by Davide Cervone -
Paul, thanks for posting the parserCustomize.pl file. Note, however, that this file is loaded by MathObjects.pl automatically, so there is no need to include it in loadMacros() yourself (and in fact, it can be counter-productive). The parserCustomization.pl file can be used to customize MathObjects in any problem that uses MathObjects.
In reply to Davide Cervone

Re: LimitedVector context?

by Alice McLeod -
First of all, thanks so much to Davide and Paul for the help you've given me so far!

I confess I'm struggling to properly understand the distinction between what's happening in Perl and what's happening in MathObjects; hopefully I'll pick up more of that as I go along.

Regarding making vectors use parentheses rather than angle-brackets (which I'd like to manage, btw, because the textbook I'll be using next semester uses parentheses for vectors, and I'd like to keep the notation consistent for the students) ... based on the above discussion, I thought that the following code would work, but it doesn't. (It doesn't produce a visible error, but the vectors continue to render with angle-brackets.) Help?

DOCUMENT();

loadMacros("PGstandard.pl",
"MathObjects.pl",
"PGML.pl");

Context("Vector");

$context{Vector} = Parser::Context->getCopy("Vector");
$context{Vector}->{cmpDefaults}{Vector} = {promotePoints => 1};
$context{Vector}->lists->set(Vector=>{open=>'(', close=>')'});


$v1 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));
$v2 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));

TEXT(beginproblem());
BEGIN_PGML
[$v1] + [$v2] = [________]*{$v1+$v2}
END_PGML

ENDDOCUMENT();
In reply to Alice McLeod

Re: LimitedVector context?

by Gavin LaRose -
Hi Alice,

You're fighting with some fairly subtle coding issues here, and are very close to a working problem. The following does what you want.

DOCUMENT();
loadMacros("PGstandard.pl", "MathObjects.pl", "PGML.pl");

Context("Vector");
Context()->{cmpDefaults}{Vector} = {promotePoints => 1};
Context()->lists->set(Vector=>{open=>'(', close=>')'});

$v1 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));
$v2 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));

TEXT(beginproblem());
BEGIN_PGML
[$v1] + [$v2] = [________]*{$v1+$v2}
END_PGML

ENDDOCUMENT();

What's the difference? Here, we've declared the Vector Context: Context(Vector);, and then the subsequent calls to set the different parameters (the Context()->... lines) are setting them for the current context, which is what you want. By itself, Context() returns the current context.

In your example, you had gotten a copy of the Context, and then modified that copy, leaving the current Context in which everything was working unchanged. As I noted, this is subtle, and a really good example of what sets WeBWorK apart from some other web homework systems: it gives you a tremendous amount of power to do things, but at the cost of occasionally having to get into the trenches to deal with subtle coding issues.

Gavin

In reply to Gavin LaRose

Re: LimitedVector context?

by Davide Cervone -
I was just getting ready to respond to this, when Gavin beat me to it. I did want to add a little bit more detail, however. The commands
$context{Vector} = Parser::Context->getCopy("Vector");
$context{Vector}->{cmpDefaults}{Vector} = {promotePoints => 1};
$context{Vector}->lists->set(Vector=>{open=>'(', close=>')'});
work just as Gavin said: they make a local copy of the Vector context, but don't set that as the default. But this copy is in a special place (the %context hash) and the Context() command will look there for the named context before it looks in the main system-defined list of contexts. So if your
Context("Vector");
call had come after you had made the copy and modified it, then it would have worked, since the Context("Vector") call would have found your modified copy rather than the default system one.

The commands that you used were intended to be placed in parserCustomization.pl, which is loaded whenever MathObjects.pl is loaded, and so they would normally run before your initial Context("Vector") call. Since you moved them to your problem itself, you ran into the problem of getting them in the right order.

I would recommend that you not put these commands into your individual problems, however, and use the parserCustomization.pl approach instead, for two reasons. 1) If you ever intend to share your problems, it will be easier for others to choose the notation that they prefer (if the code is in the problem, they won't be able to override it, and will have to edit all your problems by hand), and 2) if you ever change the book you are using, you would need to edit all your problems to change the notation.

In general, it is much better to make these types of customizations in a macro file, as overriding that does not require editing all the problem files. Just something to keep in mind.

In reply to Davide Cervone

Re: LimitedVector context?

by Alice McLeod -
First, thanks again for all your help! I'm learning so much (although I'm daunted by how much I still don't understand).

So, I've now got the original problem to work as intended, by moving the Context("Vector"); call to after the lines changing <> to ().

But I haven't yet succeeded in doing it the "right" way, using parserCustomization.pl.

I didn't want to mess around in the templates directory in the Webwork course that we're all sharing, so I did it in the course that's set up for me to use next fall, on a local server.

The version info at the bottom of each page for that Webwork course is

WeBWorK © 1996-2015 | theme: math4 | ww_version: 2.10 | pg_version: 2.10


if that matters.

Anyway, I made a file called parserCustomization.pl and I put it in the templates directory. The text of that file was as follows:

################################################################################
# WeBWorK Online Homework Delivery System
# Copyright � 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
# $CVSHeader$
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of either: (a) the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version, or (b) the "Artistic License" which comes with this package.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
# Artistic License for more details.
################################################################################

=head1 NAME

parserCustomization.pl - Placeholder for site/course-local customization file.

=head1 DESCRIPTION

# From https://raw.githubusercontent.com/openwebwork/pg/master/macros/parserCustomization.pl

# Copy this file to your course templates directory and put any
# customization for the Parser that you want for your course
# here. For example, you can make vectors display using
# ijk notation (and force students to use it for entering
# vectors) by using:

# $context{Vector} = Parser::Context->getCopy("Vector");
# $context{Vector}->flags->set(ijk=>1);
# $context{Vector}->parens->remove('<');

# To allow vectors to be entered with parens (and displayed with
# parens) rather than angle-brakets, use

$context{Vector} = Parser::Context->getCopy("Vector");
$context{Vector}->{cmpDefaults}{Vector} = {promotePoints => 1};
$context{Vector}->lists->set(Vector=>{open=>'(', close=>')'});

# (This actually just turns points into vectors in the answer checker
# for vectors, and displays vectors using parens rather than angle
# brackets. The student is really still entering what MathObjects
# thinks is a point, but since points get promoted automatically, that
# should work. But if a problem checks if a student's value is actually
# a Vector, that will not be true.)

=cut

sub _parserCustomization_init {}

1;

(I used the text from
https://raw.githubusercontent.com/openwebwork/pg/master/macros/parserCustomization.pl
and commented out the bits I thought I didn't need.)

Then I put the following problem in a subdirectory of templates:

DOCUMENT();

loadMacros("PGstandard.pl",
"MathObjects.pl",
"PGML.pl");

Context("Vector");

$v1 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));
$v2 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));

TEXT(beginproblem());
BEGIN_PGML
[$v1] + [$v2] = [________]*{$v1+$v2}
END_PGML

ENDDOCUMENT();


It worked without errors, but the vectors were in angle brackets instead of parentheses.

I also tried adding parserCustomization.pl to the loadMacros bit:

loadMacros("PGstandard.pl",
"MathObjects.pl",
"PGML.pl",
"parserCustomization.pl");

but it didn't make a difference; the vectors were still rendering with angle brackets.

Any idea what I'm doing wrong?
In reply to Alice McLeod

Re: LimitedVector context?

by Davide Cervone -
Note that your parserCustomization.pl file includes the lines
=head1 NAME
and
=cut
These are used to mark sections of the file that are to be considered documentation rather than code. Perl ignores the lines between these, so in your case, the entire file is being ignored!

You want to put your custom lines at the bottom of the file (after the =cut), or remove the other lines from the file.

In reply to Davide Cervone

Re: LimitedVector context?

by Alice McLeod -
Aha, I see!

I've changed my parserCustomization.pl file accordingly, and it works!

Thanks so much.
In reply to Alice McLeod

Re: LimitedVector context?

by Davide Cervone -
Note that if you put parserCustomization.pl in the same directory as your .pg file, only the other .pg files in your directory will be affected. So if you are working in Homework/Workshop2/McLeod, you will not alter other people's problems.
In reply to Alice McLeod

Re: LimitedVector context?

by Davide Cervone -
Paul is correct that the missing contextLimitedVector.pl is the source of the error message you are receiving.

He is also right that your Compute("$v1+$v2") is also a problem. To be more explicit, since you are using $v1 and $v2 inside a string, the values of these variables are first turned into strings, and then inserted into the larger string that you are passing to Compute(). So you effectively have Compute("<1,5,-2>+<4,-6,2>") (or whatever the random vectors are). But, as Paul points out, the LimitedVector context doesn't allow + to be used in this way. So this produces an invalid expression. It should produce an error message (though the Interactive Labs trap those errors and don't show them).

Paul suggests performing the addition yourself, but while that works it is not actually necessary. The restriction on addition is in the parsing of MathObjects only. If you have two Vector objects, you can still add them in your Perl code. For example,

Context("LimitedVector");
$v1 = Vector(-2,1,5);
$v2 = Vector(1,1,-4);
$v3 = $v1+$v2;
is still allowed, even though
$v3 = Compute("$v1+$v2");
is not. This is another reason not to insert values into compute strings when they are already MathObjects. You might as well just add them rather than convert them to strings and re-parse the resulting string, which will just cause them to be added in the end anyway.

So a modified version of your problem that actually works is

loadMacros(
  "PGstandard.pl",
  "MathObjects.pl",
  "PGML.pl",
  "contextLimitedVector.pl",
);

Context("LimitedVector");

$v1 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));
$v2 = Vector(random(-10,10,1),random(-10,10,1),random(-10,10,1));

TEXT(beginproblem());

BEGIN_PGML
[$v1] + [$v2] = [________]{$v1 + $v2}
END_PGML