Using MathObjects
From WeBWorK
Using MathObjects
To use MathObjects in your own problems, you need to load the MathObjects.pl macro file:
loadMacros("MathObjects.pl");
which defines the commands you need to interact with MathObjects.
Once you have done that, you can call the MathObjects functions to
create formulas for you. The main call is Formula()
, which takes
a string and returns a parsed version of the string. For example:
$f = Formula("x^2 + 3x + 1");
will set $f to a reference to the parsed version of the formula.
Working With Formulas
A formula has a number of methods that you can call. These include:
$f>eval(x=>5)

Evaluate the formula when
x
is 5. If$f
has more variables than that, then you must provide additional values, as in$f>eval(x=>3,y=>1/2);
$f>reduce

Tries to remove redundent items from your formula. For example,
Formula("1x+0")
returns "x
". Reduce tries to factor out negatives and do some other adjustments as well. (There still needs to be more work done on this. What it does is correct, but not always smart, and there need to be many more situations covered.) All the reduction rules can be individually enabled or disabled using theContext()>reduction>set()
method, and you can enable or disable individual rules using thereduce
method itself. For example$f>reduce('x+y'=>0);
would reduce
$f
but not perform the change fromx+5
to5x
if that expression occurred in$f
. $f>substitute(x=>5)

Replace
x
by the value 5 throughout the formula (you may want to reduce the result afterword, as this is not done automatically). Note that you can replace a variable by another formula, if you wish. To make this easier, substitute will applyFormula()
to any string values automatically. E.g.,Formula("x1")>substitute(x=>"y")
returns
<y1
> as a formula. $f>string

returns a string representation of the formula (should be equivalent to the original, though not necessarily identical to it).
$f>TeX

returns a LaTeX representation of the formula. You can use this in
BEGIN_TEXT...END_TEXT
blocks as follows:BEGIN_TEXT Suppose \(f(x) = \{$f>TeX}\). ... END_TEXT
If you place
Context()>texStrings
before aBEGIN_TEXT...END_TEXT
block, andContext()>normalStrings
afterward, then using$f
within the text will cause the TeX version to be inserted, rather than the string version. This makes it easier to generate wellformated output in your problems without having to produce a separate TeX form yourself. $f>perl

returns a representation of the formula that could be evaluated by perl's
eval()
function. $f>perlFunction

returns a perl code block that can be called to evaluate the function. For example:
$f = Formula('x^2 + 3')>perlFunction; $y = &$f(5);
will assign the value 28 to
$y
. You can also pass a function name toperlFunction
to get a named function to call:Formula('x^2 + 3')>perlFunction('f'); $y = f(5);
If the formula involves more than one variable, then the paramaters should be given in alphabetical order.
Formula('x^2 + y')>perlFunction('f'); $z = f(5,3); # $z is 28.
Alternatively, you can tell the order for the parameters:
Formula('x^2 + y')>perlFunction('f',['y','x']); $z = f(5,3); $ now $z is 14.
Combining Formulas
There is a second way to create formulas. Once you have a formula, you can create additional formulas simply by using perls' builtin operations and functions, which have been overloaded to handle formulas. For example,
$x = Formula('x'); $f = 3*x**2 + 2*$x  1;
makes $f
be a formula, and is equivalent to having done
$f = Formula("3x^2 + 2x  1");
This can be very convenient, but also has some pitfalls. First, you
need to include *
for multiplication, since perl doesn't do
implied multiplication, and you must remember to use **
not
^
. (If you use ^
on a MathObject, the library will remind
you to use **
. But if you use it on native Perl numbers, it will
just compute the wrong answer silently.) Second, the precedences of
the operators in perl are fixed, and so changes you make to the
precedence table for the parser are not reflected in formulas produced
in this way. (The reason ^
is not overloaded to do exponentiation
is that the precedence of ^
is wrong for that in perl and can't be
changed.) As long as you leave the default precedences, however,
things should work as you expect.
Note that the standard functions, like sin, cos, etc, are overloaded to generate appropriate formulas when their values are formulas. For example,
$x = Formula('x'); $f = cos(3*$x + 1);
produces the same result as $f = Formula("cos(3x+1)");
and you can
then go on to output its TeX form, etc.
Special Syntax
The MathObjects expression parser has support for some mathematical
notation that is not available is some other parsers. For example,
you can say 1+x
rather than abs(1+x)
(though both are allowed), and
even 1  x
works.
Also, you can use sin^2(x)
(or even sin^2 x
) to get (sin(x))^2
.
Finally, you can use sin^1(x)
to get arcsin(x)
.
There is an experimental set of operator precedences that make it
possible to write sin 2x + 3
and get sin(2x) + 3
. See
examples/7precedence.pg for some details.
The Formula Types
The MathObjects library defines a wide range of data types, including real and complex numbers, infinity, points, vectors, matrices, arbitrary lists, intervals, unions of intervals, and predefined words. Each has a syntax for use within formulas, as described below:
 numbers
The usual forms: 153, 233.5, 2.456E3, etc.
 complex numbers
An expression
a + b i
wherea
andb
are numbers, e.g.:1+i
,5i
,67i
, etc.  infinitites
The words
infinity
orinfinity
(or several equivalents, e.g.,inf
).  points
A point is represented as
(a,b,c)
wherea
,b
andc
are real or complex numbers. any number of coordinates are allowed. Eg,(1,2)
,(1,0,0,0)
,(1,2,3)
. Points are promoted to vectors automatically, when necessary.  vectors
A vetor is represented
<a,b,c>
ora i + b j + c k
(when used in vector context). As with points, vectors can have any number of coordinates. For example,<1,0,0>
,<1,3>
,<x,1x>
, etc.  matrices
A matrix is represented as a collection or rows,
[[a11,...,a1n],...[am1,...amn]]
; i.e., use[...]
around each row, and around the matrix itself. The elements are separated by commas (not spaces). e.g,[[1,2],[3,4]] (a 2x2 matrix) [1,2] (a 1x2 matrix, really a vector) [[1],[2]] (a 2x1 matrix, i.e., a column vector)
Points and vectors are promoted to matrices when appropriate. Vectors are converted to column vectors when needed for matrixvector multiplication. Matrices can be 3dimensional or higher by repeated nesting of matrices. (In this way, a 2dimensional matrix is really thought of as a vector of vectors, and ndimensional ones as vectors of (n1)dimensional ones.)
 lists
A list is represented
(a,b,c)
or justa,b,c
wherea
,b
, andc
are arbitrary elements. For example,(1+i, 3, <1,2,3>, Infinity)
. The empty list()
is allowed. If a professor's answer includes the parentheses, then the student must as well, and if the professor's answer has no parentheses, then the student must not use them either.  intervals
The usual forms:
(a,b)
,(a,b]
,[a,b)
,[a,b]
, or[a,a]
wherea
andb
are numbers or appropriate forms of infinity. For example,(INF,3]
,[4,4]
,[2,infinity)
,(inf,inf)
.  sets
Finite sets of numbers are represented
{a,b,c}
, wherea
,b
, andc
are any real numbers. You can include as many as you like, e.g.,{0,pi,sqrt(2)}
,{10,1/2,3.14,0,100}
. The empty set is{}
.  unions
Unions are represented by
U
. For example[1,0) U (0,1]
.  strings
These are special predefined strings like
NONE
andDNE
. Additional strings can be defined as needed.
These forms are what are used in the strings passed to Formula()
,
or when a student types them for an answer. If you want to create
versions of these as part of the pg code for an answer, there are
several ways to do it. One way is to use the Compute()
command,
which takes a string parses it and then evaluates the result (and in
addition, sets the correct answer to be exactly the string that was
passed to Compute()
, so this makes it easy to show the correct
answer in whatever format you desire). If the formula produces a
vector, for example, the result will be a Vector constant that you can
use in perl formulas by hand.
For example:
$v = Compute("<1,1,0> >< <1,4,2>");
would compute the dot product of the two vectors and assign the
resulting vector object to $v
.
Another way to generate constants of the various types is to use the
following routines. If their inputs are constant, they produce a
constant of the appropriate type. If an input is a formula, they
produce corresponding formula objects. If an input is a MathObject,
it will be converted to the appropriate type, if possible (e.g., you
can use Point($v)
to coerce a vector $v
to a Point
MathObject). Finally, if the input is a string, it is first parsed and
the result is converted to the appropriate class, if possible.
Real(a)

Creates a real number with "fuzzy" comparisons (so that
1.0000001 == Real(1)
is true). Complex(a,b)

Creates the complex number
a + b i
Infinity
or(Infinity)

Creates the positive and negative infinity objects.
Point(x1,...xn)
orPoint([x1,...,xn])

Produces the point
(x1,...,xn)
. Vector(x1,...,xn)
orVector([x1,...,xn])

Produces the vector
<x1,...,xn>
. Matrix([a11,...,a1m],...,[am1,...,amn])
orMatrix([[a11,...,a1m],...,[am1,...,amn]])

Produces an n x m matrix.
List(a,...,b)

Produces a list with the given elements.
Interval('(',a,b,']')

Produces the interval
(a,b]
, (the other types of endpoints work as expected). UseInfinity
and(Infinity)
for unbounded intervals. Set(a,b,c,d)

Produces the set consisting of the given numbers.
Set()
produces the empty set. Union(I1,...,In)

Takes the union of the n intervals or sets (where
I1
toIn
are Interval or Set objects). String(word)

Produces a string object for the given word (if it is a known word).
For example,
$a = random(5,5,1) $V = Vector($a,1$a,$a**2+1);
produces a vector with some random coordinates.
Objects of these types also have TeX
, string and perl
methods,
so you can use:
Vector(1,2,3)>TeX
to produce a TeX version of the vector, just as you can with formulas.
There are several "constant" functions that generate common constant
values. These include pi
, i
, j
, k
and Infininty
. you
can use these in perl expressions as though they were their actual
values:
$z = $a + $b * i; $v = $a*i + $b*j + $c*k; $I = Infinity;
Note that because of a peculiarity of perl, you need to use (pi)
or  pi
(with a space) rather than pi
, and similarly for the
other functions. Without this, you will get an error message about an
ambiguity being resolved. (This is not a problem that occurs with
strings passed to Formula()
or Compute()
, or in student answers,
but only if you are writing expressions in perl directly. Note that
since student answers are processed by the MathObjects string parser,
not perl directly, they can write pi
without problems.)
Specifying the Context
You may have noticed that i
was used in two different ways in the
examples above. In the first example, it was treated as a complex
number and the second as a coordinate unit vector. To control which
interpretation is used, you specify a parser context.
The context controls what operations and functions are defined in the parser, what variables and constants to allow, how to interpret various paretheses, and so on. Changing the context can completely change the way a formula is interpreted.
There are several predefined contexts: Numeric
, <
Complex
>, Point
, Vector
, Vector2D
,
Interval
, Matrix
, and Full
. A numbmer
of specialized contexts are defined in files in the pg/macros
directory (e.g., for scientific notation, currency values, chemical
reactions, and so on). To select a context, use the Context()
function, e.g.
Context("Numeric");
selects the numeric context, where i
, j
, and k
have no
special meaning, points and vectors can't be used, and the only
predefined variable is x
.
On the other hand, Context("Vector")
makes i
, j
, and k
represent the unit coordinate vectors, and defines variables x
,
y
and z
, while Context("Vector2D")
has i
and j
(but no
k
) as vectors in 2D.
Context("Interval")
is like numeric context, but it also defines
the parentheses so that they will form intervals (rather than points
or lists). Context("Matrix")
defined brackets so that they produce
matrices, so students can type matrices directly.
Once you have selected a context, you can modify it to suit the particular needs of your problem. The command
$context = Context();
gets you a reference to the current context object (you can also use something like
$context = Context("Numeric");
to set the context and get its reference at the same time). Once you have this reference, you can call the Context methods to change values in the context. Some of the more common actions are described here.
To add a variable, use, for example,
$context>variables>add(y=>'Real');
To delete any existing variables and replace them with new ones, use
$context>variables>are(t=>'Real');
To remove a variable, use
$context>variables>remove('t');
To get the names of the defind variables, use
@names = $context>variables>names;
Similarly, you can add a named constant via
$context>constants>add(M=>1/log(10));
and can change, remove or list the constants via methods like those used for variables above. The command
$M = $constant>constants>get('M');
will return the value of the consant M
. (See the
pg/lib/Value/Context/Data.pm file for more information on the methods
you can call for the various types of context data.)
To add new predefined words (like NONE
and DNE
), use something
like
$constant>strings>add(TRUE=>{},FALSE=>{});
Note that strings are caseinsensitive by default, but you can force them to be casesensitive:
$constant>strings>add(A=>{caseSensitive=>true},B=>{caseSensitive=>true});
You can also create strings that mean the same thing as other strings (and will be counted as equal):
$constant>strings>add( T => {alias=>'TRUE'}, F => {alias=>'FALSE'}, );
so that either TRUE
or T
(upper or lowercase) will be interpreted as TRUE
.
There are a number of values stored in the context that control things like the tolerance used when comparing numbers, and so on. You control these via commands like:
$context>flags>set(tolerance=>.00001);
For example,
$context>flags>set(ijk=>1);
will cause the output of all vectors to be written in ijk
format
rather than <...>
format.
Finally, you can add or modify the operators and functions that are
available in the parser via calls to $context>operators
and
$context>functions
. See the files in pg/docs/MathObjects/extensions
for examples of how to do this.