Modifying Contexts (advanced)

From WeBWorK_wiki
Jump to navigation Jump to search

Context Modification: How to Modify an Existing Context or Make Your Own Context

This document explains how to modify the current context and how to define your own context. You might want to do the latter if the problems you write/use always have certain nonstandard characteristics. For example, maybe your book always uses a certain parentheses type, etc.

First we will describe common context modifications which you can make. The second part of the document will explain how to combine these changes into a file to define your own custom context.

Part I. Modifying an Existing Context

What can you change? Here is a description of some of the basic changes you can make, what the options are, and how to change those values. You can do a lot of customization here, probably more than you need, but more advanced modifications can be made if you know how to program in Perl.

(1) Operators

The list of predefined operators includes stardard arithmetic operators:


* / + - ! >< U ^ **
. ,


Where ! is the factorial operator, both ^ and ** give exponentiation, . is a dot product, and , is a list operation used to create lists.

You may also find the operators u+, u-, and fn, but these are internal operators and should not be modified.

Here you will most often want to undefine some operators. The following example undefines cross product and dot product:


Context()->operators->undefine('><','.');


You can also redefine an operator which was previously undefined.

Context()->operators->redefine('><','.');

To get rid of an operator you could also use

Context()->operators->remove('><','.');

but this is not recommended, as undefine makes the operator unavailable (but still recognized), while after remove WebWork will not recognize the operator at all. Thus if an operator is undefined, students will get sensible error messages indicating that the operator is not available in the context of the problem.

(2) Functions

The list of predefined functions is

sin, cos, tan, sec, csc, cot, asin, acos, atan, asec,
acsc, acot, sinh, cosh, tanh, sech, csch, coth, asinh,
acosh, atanh, asech, acsch, acoth, ln, log, log10, exp,
sqrt, abs, int, sgn, atan2, norm, unit, arg, mod,
Re, Im, conj

Here the most common need is to make some functions unavailable in the context of a problem. The following example makes functions needed only for complex variables unavailable:

Context()->functions->undefine('norm','unit','arg','mod','Re','Im','conj');

You can also undefine entire collections of functions with disable, e.g.,

Context()->functions->disable("Trig");

The categories of functions are: SimpleTrig (with sin, cos, tan, sec, csc, and cot), InverseTrig (with asin, acos, atan, asec, acsc, acot and atan2), SimpleHyperbolic (with sinh, cosh, tanh, sech, csch, and coth), InverseHyperbolic (with asinh, acosh, atanh, asech, acsch, acoth), Numeric (with ln, log, log10, exp, sqrt, abs, int, sgn), Vector (with norm and unit) and Complex (with arg, mod, Re, Im, conj).

There is also

Trig (SimpleTrig together with InverseTrig), Hyperbolic (with SimpleHyperbolic and InverseHyperbolic), and All.

(3) Constants

The list of predefined constants is e, pi, i, j, k. The constant i denotes sqrt(-1) in Context("Complex"), denotes the vector <1,0> in Context("Vector2D"), and denotes the vector <1,0,0> in Context("Vector"), Context("Matrix"), and Context("Point"). The constant i is undefined outside of those contexts. The constants j and k are <0,1,0> and <0,0,1>, respectively, in Context("Vector") and Context("Matrix"). The constant j is <0,1> in Context("Vector2D"), and k is undefined there. The constants i, j and k are undefined outside of the contexts described above.

Context()->constants->set(i => {TeX=>'\boldsymbol{i}', perl=>'i'});
Context()->constants->remove("k");
Context()->constants->set(R => {TeX => '{\bf R}'});


(4) Variables

The default context Context("Numeric") recognizes a single real variable x. You can set variables in your context like this:


Context()->variables->are(z=>'Complex');
Context()->variables->are(x=>'Real',y=>'Real',z=>'Real');


Note that declaring variables this way with 'are' indicates to the context that these are the only variables in the context. You can add variables to a context while preserving already defined variables by doing:

Context()->variables->add(x=>'Real',y=>'Real',z=>'Real');

You can add any number of real or complex variables in this manner, just be careful that your variable names don't interfere with names of other defined objects. You may also create vector-valued variables, or variables of nearly any MathObject? type. For example:

Context()->variables->set(r=>'Vector3D');
Context()->variables->set(r=>Vector(1,2,3,4));

You can set variable limits like this:

Context()->variables->set(x=>{limits=>[-1,1]});

The limits can also be set at the time the variable is created, as follows:

Context()->variables->add(x => ~['Real',limits=>[-1,1]]);

which creates a real variable x with limits from -1 to 1.

(5) Strings

The list of predefined strings is:

  • infinity,
  • inf,
  • NONE,
  • DNE.

The strings listed in a context indicate allowed responses by students even though the responses might not be correct. If a string is in the context then entering the string will not trigger an error (even if it is not the correct answer). However the student enters a string such as 'undefined' which is not listed in the context then an error message: " 'undefined' is not defined in this context" is returned.

You can add strings to your context as follows:

The following command adds string 'True', and makes 'T' and alias for 'True'.

Context()->strings->add(True=>{},T=>{alias=>'True'});

The following line defines the string 'Continuous' in the current context:

Context()->strings("Continuous"=>{});

This sort of thing is useful for writing problems in which the student must enter text. Be sure here to provide sensible aliases for equivalent terms which students may use. Another good practice is to define strings for incorrect answers which students are likely to enter.

Another option for use on strings allows you to specify whether or not WebWork should be sensitive to uppercase/lowercase letters. By default WebWork is case insensitive with respect to any string which it recognizes.

To change this for a String, the caseSensitive flag must be specified when the String is added to the Context:

Context()->strings->add(True=>{caseSensitive=>1});


(6) Lists

This section and the next section 'Parens' are closely related. WebWork considers the following objects to be types of lists:

  • Point,
  • Vector,
  • Matrix,
  • List,
  • Interval,
  • Set,
  • Union,
  • AbsoluteValue.

The most common modification made to lists are to which type of parentheses is used to enclose them. The purpose of the following description is meant to make you aware of how the various parenthesis types are used by default.

  • Points by default look like e.g. (3,4).
  • Vectors by default look like e.g., <3,4,5>.
  • Matrix objects by default look like ~[[2,3],[2,3]].
  • A list by default looks like 3, 4, 5. An interval by default looks like (0,9), 0,9), etc.
  • A set by default looks like {3,4,5}.
  • A union by default looks like (-infinity,0? U (5,7].
  • Absolute value by default looks like |-5|.

Next we'll discuss how to modify the type of parentheses used with the various objects.

(7) Parens

WebWork recognizes the full range of parentheses types, as explained above (e.g., (, <, [, { ). But by default their meanings are dependent on the context. You can change how this works.

For example, this command will cause Vector objects to look like (3,4,5) instead of <3,4,5>:

Context()->parens->set('('=>{type=>'Vector'});


(8) Flags

A discussion of the context flags can be found under ContextFlags. The point to emphasize here is that to change the context flags in your context do, e.g.,

Context()->flags->set(
   tolerance => 0.0001,
   tolType => 'absolute',
);

There are other ways to manipulate the context as well. For example, some function calls change the context:

Parser::Number::NoDecimals(Context());

Also, some macro files provide methods for changing the context:

loadMacros("contextLimitedPowers.pl");
Context()->operators->set(@LimitedPowers::OnlyIntegers);

Part II. Create Your Own Context

Suppose that you have accumulated a nontrivial number of context modifications which you use frequently when writing problems. You can combine all of these modifications into a single file and define your own context.

First, what do you want to call your context? Let's say we will name it MyContext. Whatever you end up naming your context, it is recommended practice to begin your filename with 'context' and end with '.pl'. So your filename might be contextMyContext.pl. When we're done we'll put the file in the /pg/macros/ sudbdirectory of the WebWork installation.

You will then call the file in the loadMacros statement along with the other macros you load. You should call your context file after the standard macro files are called. So, for example, to call contextMyContext.pl in loadMacros one might do:

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"contextMyContext.pl",
"PGcourse.pl",
);

When defining a new context in your file, the code will proceed as follows: (i) copy an existing context which is close to what you want (ii) modify what you want changed.

For example, this line copies Context("Numeric") into a new Context("MyContext"):

$context{MyContext} = Parser::Context->getCopy(undef,"Numeric");

The following lines modify some aspects of this context:

$context{MyContext}->functions->disable("Trig");
$context{MyContext}->parens->set('('=>{type=>'Vector'});
etc...

So your complete file will look like:

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"contextMyContext.pl",
"PGcourse.pl",
);

$context{MyContext} = Parser::Context->!getCopy(undef,"Numeric");
$context{MyContext}->functions->disable("Trig");
$context{MyContext}->parens->set('('=>{type=>'Vector'});

That's it. Save it, put it in /pg/macros/ or your course templates/macros directory, and load it in your problems with loadMacros().

Note that when it comes to answer checking (discussed elsewhere), context checked is the one where the object was created, not the currently active one (when they differ). This means you can create an object, change the context, then create another one in order to get answer checkers from two different contexts.