Formula (MathObject Class)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Formula Class

A Formula object represents an expression whose result is one of the MathObject types defined above. These act like functions in that you can evaluate them at different values of the variables that they use, or substitute other expressions for the variables (to form compositions).

Construction

\$f = Formula("2x^2+3x-5");

\$a = random(2,5,1);
\$b = random(5,9,1);
\$f = Formula("x^2 + \$a x + \$b");

The variables used in a Formula must be declared in the Context. The Numeric Context has x pre-defined, but you can add more, as in the following example:

Context("Numeric");

\$f = Formula("x^2 + 2xy + y^2");

Operations on Formulas

Formulas can be added, subtracted, multiplied, etc, to obtain new Formula objects, and functions like sin(), sqrt(), and so on will return Formula objects when their arguments are formulas:

\$x = Formula("x");
\$f = 3* \$x**2 - 2 * \$x + 5;    # same as Formula("3x^2 - 2x + 5");
\$g = \$x - 5;
\$h = \$f / \$g;                  # same as Formula("(3x^2 - 2x + 5) / (x - 5)");
\$g1 = sin(\$g)                  # same as Formula("sin(x-5)");

Formulas can produce any type of MathObject as its result, including points, vectors, intervals, etc. For example,

Context("Vector");
\$f1 = Formula("<2x+1,1-x,x^2>");           # a vector-valued formula

\$f2 = Formula("(1,3,-2) + t <4,-1,2>");    # a parametric line

Context("Interval");
\$f3 = Formula("(x,2x+1]");                 # an interval-valued formula

Reducing Formulas

If you substitute values as coefficients in a formula, you may end up with things like 1 x^2 + -3 x + 0, but Formulas have a reduce method that can be used to remove coefficients of 1, simplify addition of negatives, remove sums or products of 0, and so forth. E.g.,

\$f = Formula("1 x^2 + -3 x + 0")->reduce;  # same as Formula("x^2 - 3x");

There are a number of reduction rules, and you can enable or disable them individually (reference needed). Note, however, that MathObjects is not a full computer algebra system, and the reduction rules are mainly geared toward improving the output, not solving equations or performing algebraic manipulations to simplify the expression.

Evaluating Formulas

Given a Formula, you may want to evaluate the Formula at a particular value of its variable; that can be accomplished by the eval() method. The arguments to eval() assign values to all the variables of the Formula, and it returns the value of the Formula for those inputs. For example:

\$f = Formula("x^2 + 2x + 1");
\$a = \$f->eval(x=>2);            # f at x=2, or Real(9)

\$g = Formula("xy + x + y");
\$b = \$g->eval(x=>2,y=>3);       # g at (x,y) = (2,3), or Real(11);

The substitute() method is similar to eval(), but in this case, the specified variables are replaced by the values that are given. The values need not be constants; they could be Formulas, in which case the result is the composition of the two Formulas. Note that not all the variables need to be substituted (unlike with eval(), where all variables must be given a value).

\$f = Formula("x^2 + 2x + 1");
\$g1 = \$f->substitute(x => "y");            # same as Formula("y^2 + 2y + 1");
\$g2 = \$f->substitute(x => "2x-1");         # same as Formula("(2x-1)^2 + 2(2x-1) + 1");

\$h = Formula("xy + x + y");
\$h1 = \$h->substitute(x => "y");            # same as Formula("y*y + y + y") or Formula("y^2 + 2y");
\$h2 = \$h->substitute(x => 2, y => "3x");   # same as Formula("2(3x) + 2 + 3x");

Perl Code from Formulas

If you need to evaluate a Formula multiple times (for example, to produce a graph), it is not very efficient to use eval(). Instead, you can use the perlFunction method to generate a native Perl function that you can call to evaluate the Formula. If given no arguments, perlFunction() returns an anonymous code reference to a subroutine that evaluates the Formula; the parameters to the subroutine are the values of the variables (in alphabetical order). If a single argument is given, it is the name to give to the subroutine; if two arguments are given, the second is an array reference that lists the order of the variables to use for the arguments to the subroutine.

\$f = Formula("x^2+y");

\$F = \$f->perlFunction;            # anonymous subroutine reference
\$a = &{\$F}(2,3);                  # value of \$f for x=2 and y=3, i.e., Real(7)
\$f->perlFunction("F");            # subroutine named F
\$a = F(2,3);                      # again, Real(y)
\$f->perlFunction("G",["y","x"]);  # change order of variables in arguments to G
\$a = \$G(2,3);                     # value of \$f for y=2 and x=3, i.e.,  Real(11);

Derivatives of Formulas

You can obtain the derivative of a Formula using the D() method. If the Formula has more than one variable, then you need to indicate which one to differentiate by; you do this by giving the variable name as an argument to the method. You can get second or third derivatives (or higher) either by using D() a second time or third time, or by including more variable names in the call to D(). For example:

\$f = Formula("3x^2-5x+2");
\$df = \$f->D('x');                    # same as Formula("3*(2x)-5");
\$df_4 = \$df->eval(x=>4);             # f'(4), i.e., Real(19);
\$ddf = \$df->D('x');                  # same as Formula("6");
\$ddf = \$f->D('x','x');               # same as above

\$f = Formula("x^2 + 4xy^2 + y^3");
\$fx = \$f->D('x');                    # same as Formula("2x+4y^2");
\$fxy = \$fx->D('y');                  # same as Formula("4*(2y)");
\$fxy = \$f->D('x','y');               # same as above

As with all MathObjects, you obtain an answer checker for a Formula object via the cmp() method:

ANS(Compute("x^2+2x+1")->cmp);

The options for the Formula answer checker is dependent on the type of the result of the Formula. They include all the options for the class of the result, and the following additional options:

Option Description Default
upToConstant => 1 or 0 For Real-valued formulas, this controls whether the student's answer only needs to match the correct answer up to addition of a constant. 0
showDomainErrors => 1 or 0 If the test points for the function comparison reveals that the student answer is defined on a different domain from the correct answer (e.g., the student's answer is not defined at one of the test points), then this value determines whether or not a message is issued alerting the student to that fact. 1
showTestPointErrors => 1 or 0 If not enough test points can be found for the correct answer, a warning message is given to the student indicating that. This value determines whether or not additional information about the reason why the function can't be evaluated should be included in the message. undef

Methods

The Formula class supports the Common MathObject Methods, and the following additional methods:

Method Description
\$f->eval(x => value,...) Returns the value of \$f evaluated at the given values of its variables. All variables used in the Formula must be given a value (use substitute if you want to set only some of the variables). See the Evaluating Formulas above for examples.
\$f->substitute(x => value,...) Returns a copy of \$f with the given values replaced by their given values. The values can be any appropriate MathObject, including other Formula objects. If the value is a perl string, it will be parsed to form a MathObject. See the Evaluating Formulas above for examples.
\$f->reduce
\$f->reduce(rule => 0 or 1,...)
Returns a copy of \$f where the MathObject reduction rules have been applied. You can turn on or off individual rules or collections of rules by giving the name of the rule and setting it to 0 (don't apply) or 1 (apply). See Reducing Formulas above for examples. See the Reduction rules for MathObject Formulas for a list of the reduction rules.
\$f->perlFunction
\$f->perlFunction("name")
\$f->perlFunction("name",["x",...])
Turns \$f into executable Perl code that can be called to evaluate the Formula efficiently. The first form returns an anonymous code reference, the second makes a names Perl subroutine, and the third specifies the order of the variables in the subroutine's argument list (the default is alphabetical). See Perl Code from Formulas above for examples.
\$f->isConstant Returns true if \$f contains no variables (i.e., is constant-valued), and undef otherwise.
\$f->usesOneOf("x",...) Returns 1 if any of the variables listed appear in \$f, and 0 otherwise.

There are additional methods for a Formula that are for internal use during the parsing of the formula. These are in the pg/lib/Parser.pm file, and are not documented here.

Properties

The Formula class supports the Common MathObject Properties, and the following additional ones:

Property Description Default
\$f->{limits} A reference to an array of values that represent the lower and upper limits for the variables used in \$f when producing random points for comparisons. If there is more than one variable, then either the limits apply to all of them, or the array should contain references to an array of limits for each variable (in alphabetical order). For example
\$f = Formula("sqrt(x-10)")->with(limits=>[10,12]);
\$f = Formula("e^x-y")->with(limits=>[[-1,1],[-2,-1]]);

If not set, it will be taken from the answer checker options, or from the Context. The Context default is [-2,2].

undef
\$f->{test_points} A reference to an array of values to use for the variables in \$f when comparing \$f to another Formula. The value in the array are themselves references to arrays whose values are the values for the variables in \$f listed in alphabetical order. For example,
\$f = Formula("ln(|x|)")->with(test_points => [[-3],[-2],[-1],,,]);

sets \$f so that both positive and negative values are used; this means \$f will not match Formula("ln(x)"), for instance.

Note that the number of coordinates in the points needs to match the number of variables in the current context (even if they are not all used in the formula). The order of the variables is alphabetical by variable name, so if the context includes variables x and C, there should be two entries in the points with the first being the value for C, and the second for x.

If not set, it will be created automatically from random points when \$f is first compared to another Formula. If set, no random points will be used.

undef
\$f->{test_at} A reference to an array of values to use for test points for \$f in addition to the randomly chosen ones. The format is the same as for test_points above. E.g.,
\$f = Formula("ln(|x|)")->with(test_at => [[-1],]);

will cause \$f to use [math]x=-1[/math] and [math]x=1[/math] along with the usual random points when it is compared to another Formula.

undef
\$f->{test_values} A reference to an array of values produced by \$f at the \$f->{test_points}. You should not set this yourself; it is generated automatically when \$f is compared to another Formula. produced from \$f
\$f->{checkUndefinedPoints} This determines whether points where \$f is not defined are allowed to be used when another function is compared to this one. When false (or undefined), random points where the function isn't defined are discarded and new ones chosen. When this value is true, such points (or points from test_values or test_points above where the function is undefined) are retained, and the student's function must also be undefined at these points. undef
\$f->{checkUndefinedPoints} This determines whether points where \$f is not defined are allowed to be used when another function is compared to this one. When false (or undefined), random points where the function isn't defined are discarded and new ones chosen. When this value is true, such points (or points from test_values or test_points above where the function is undefined) are retained, and the student's function must also be undefined at these points. undef
\$f->{max_undefined} When checkUndefinedPoints is true, this is the maximum number of undefined points that are allowed. You can use this to limit the number of undefined points so that you are sure that some points are actually where the function is defined. If not provided, there is no limit to the number of undefined points allowed. undef
\$f->{parameters} When \$f includes adaptive parameters, this is a reference to the array of the adapted values for those parameters (in alphabetical order). You should not set this yourself; it is generated automatically when \$f is compared to another Formula. produced automatically
\$f->{variables} A reference to a hash whose keys are the names of the variables used in \$f (and whose values are 1). You should not set this yourself; it is maintained automatically. produced automatically
\$f->{values} A reference to a hash whose keys are the names of variables whose values are being set during an eval() or substitute() call, and whose values are the values to which each variable is being set. You should not set this yourself; it is maintained automatically by the eval() and substitute() methods, but if you implement your own parser objects, you may need to read these values to perform the requires substitutions. produced automatically
\$f->{f} An anonymous code reference used to evaluate \$f during comparisons to other Formulas. You should not set this value yourself; it is generated automatically when \$f is compared to another Formula. \$f->perlFunction
\$f->{autoFormula} When set, this indicates that \$f was generated implicitly rather than explicitly via Formula() or Compute() (e.g., by adding two Formulas together, or calling a function like sin() on a Formula). You should not set this value yourself; it is managed automatically. undef
\$f->{domainMismatch} When \$f is compared to another Formula, this is set to 1 if the other Formula can't be computed at all the test points for \$f, and 0 if it can be. You should not set this value yourself; it is generated automatically when \$f is compared to another Formula. produced automatically
\$f->{tree} This is a reference to the root node of the parse tree for the Formula. The tree is made up of nodes that represent things like binary operators, function calls, variable references, and so on. The various types of nodes are implemented by the files in the pg/lib/Parser directory, with pg/lib/Parser/Item.pm being the base class from which others are subclassed. produced automatically
\$f->{string} The original string from which the Formula was generated, when it was created by parsing a string (e.g., via Compute() or Formula()). undef
\$f->{tokens} A reference to the array of "tokens" produced by parsing the string for \$f. These are themselves references to arrays of four or five elements: the first is a string indicating the type of token (e.g., "var", "num", "fn", etc.), the second is a string representing the instance of that type for this token (e.g., "x", 3.14, "sin", etc.), and the next two are the starting and ending positions of the token in the original string (used for syntax error highlighting); if present, the fifth is true when there are spaces preceding the given token in the string (used for experimental non-standard operator precedences). produced automatically