## Forum archive 2000-2006

by Arnold Pizer -
Number of replies: 0
 PGanswermacros.pl topic started 5/22/2000; 9:57:29 PMlast post 7/17/2000; 10:47:29 AM
5/22/2000; 9:57:29 PM (reads: 4410, responses: 1)

# NAME

    PGanswermacros.pl -- located in the courseScripts directory

# SYNPOSIS

    Number Answer Evaluators:        num_cmp()   --  uses an input hash to determine parameters
        std_num_cmp(), std_num_cmp_list(), std_num_cmp_abs, std_num_cmp_abs_list()        frac_num_cmp(), frac_num_cmp_list(), frac_num_cmp_abs, frac_num_cmp_abs_list()        arith_num_cmp(), arith_num_cmp_list(), arith_num_cmp_abs, arith_num_cmp_abs_list()        strict_num_cmp(), strict_num_cmp_list(), strict_num_cmp_abs, strict_num_cmp_abs_list()        numerical_compare_with_units()  --  requires units as part of the answer        std_num_str_cmp()   --  also accepts a set of strings as possible answers
    Function Answer Evaluators:        fun_cmp()   --  uses an input hash to determine parameters
        function_cmp(), function_cmp_abs()        function_cmp_up_to_constant(), function_cmp_up_to_constant_abs()        multivar_function_cmp()
    String Answer Evaluators:        str_cmp()   --  uses an input hash to determine parameters
        std_str_cmp(), std_str_cmp_list(), std_cs_str_cmp(), std_cs_str_cmp_list()        strict_str_cmp(), strict_str_cmp_list()        ordered_str_cmp(), ordered_str_cmp_list(), ordered_cs_str_cmp(), ordered_cs_str_cmp_list()        unordered_str_cmp(), unordered_str_cmp_list(), unordered_cs_str_cmp(), unordered_cs_str_cmp_list()
    Miscellaneous Answer Evaluators:        checkbox_cmp()        radio_cmp()

# DESCRIPTION

This file adds subroutines which create "answer evaluators" for checking answers. Each answer evaluator accepts a single input from a student answer, checks it and creates an output hash %ans_hash with seven or eight entries (the preview_latex_string is optional). The output hash is now being created with the AnswerHash package "class", which is located at the end of this file. This class is currently just a wrapper for the hash, but this might change in the future as new capabilities are added.

                    score           =>  $correctQ, correct_ans =>$originalCorrEqn,                    student_ans     =>  $modified_student_ans original_student_ans =>$original_student_answer,                    ans_message     =>  $PGanswerMessage, type => 'typeString', preview_text_string =>$preview_text_string,                    preview_latex_string    =>  $preview_latex_string $ans_hash{score}            --  a number between 0 and 1 indicating                                        whether the answer is correct. Fractions                                        allow the implementation of partial                                        credit for incorrect answers.    $ans_hash{correct_ans} -- The correct answer, as supplied by the instructor and then formatted. This can be viewed by the student after the answer date.$ans_hash{student_ans}          --  This is the student answer, after reformatting;                                        for example the answer might be forced                                        to capital letters for comparison with                                        the instructors answer. For a numerical                                        answer, it gives the evaluated answer.                                        This is displayed in the section reporting                                        the results of checking the student answers.    $ans_hash{original_student_ans} -- This is the original student answer. This is displayed on the preview page and may be used for sticky answers.$ans_hash{ans_message}          --  Any error message, or hint provided by the      answer evaluator.                                        This is also displayed in the section reporting                                        the results of checking the student answers.    $ans_hash{type} -- A string indicating the type of answer evaluator. This helps in preprocessing the student answer for errors. Some examples: 'number_with_units' 'function' 'frac_number' 'arith_number'$ans_hash{preview_text_string}      --  This typically shows how the student      answer was parsed. It is                                        displayed on the preview page. For a student                                          answer of 2sin(3x)                                        this would be 2*sin(3*x). For string answers                                          it is typically the                                        same as $ans_hash{student_ans}.$ans_hash{preview_latex_string}     --  THIS IS OPTIONAL. This is latex version      of the student answer                                        which is used to show a typeset view on the                                          answer on the preview                                        page. For a student answer of 2/3, this would                                          be \frac{2}{3}.

Technical note: the routines in this file are not actually answer evaluators. Instead, they create answer evaluators. An answer evaluator is an anonymous subroutine, referenced by a named scalar. The routines in this file build the subroutine and return a reference to it. Later, when the student actually enters an answer, the problem processor feeds that answer to the referenced subroutine, which evaluates it and returns a score (usually 0 or 1). For most users, this distinction is unimportant, but if you plan on writing your own answer evaluators, you should understand this point.

Number answer evaluators take in a numerical answer, compare it to the correct answer, and return a score. In addition, they can choose to accept or reject an answer based on its format, closeness to the correct answer, and other criteria. There are two types of numerical answer evaluators: num_cmp(), which takes a hash of named options as parameters, and the "mode"_num_cmp() variety, which use different functions to access different sets of options. In addition, there is the special case of std_num_str_cmp(), which can evaluate both numbers and strings.

Numerical Comparison Options

    correctAnswer       --  This is the correct answer that the student answer will                        be compared to. However, this does not mean that the                        student answer must match this exactly. How close the                        student answer must be is determined by the other                        options, especially tolerance and format.
    tolerance       --  These options determine how close the student answer                        must be to the correct answer to qualify. There are two                        types of tolerance: relative and absolute. Relative                        tolerances are given in percentages. A relative                        tolerance of 1 indicates that the student answer must                        be within 1% of the correct answer to qualify as correct.                        In other words, a student answer is correct when                            abs(studentAnswer - correctAnswer) <= abs(.01*relpercentTol*correctAnswer)                        Using absolute tolerance, the student answer must be a                        fixed distance from the correct answer to qualify.                        For example, an absolute tolerance of 5 means that any                        number which is +-5 of the correct answer qualifies as correct.                            Final (rarely used) tolerance options are zeroLevel                        and zeroLevelTol, used in conjunction with relative                        tolerance. if correctAnswer has absolute value less than                        or equal to zeroLevel, then the student answer must be,                        in absolute terms, within zeroLevelTol of correctAnswer,                          i.e.,                            abs(studentAnswer - correctAnswer) <= zeroLevelTol.                        In other words, if the correct answer is very near zero,                        an absolute tolerance will be used. One must do this to                        handle floating point answers very near zero, because of                        the inaccuracy of floating point arithmetic. However, the                        default values are almost always adequate.
    mode            --  This determines the allowable methods for entering an                        answer. Answers which do not meet this requirement will                        be graded as incorrect, regardless of their numerical                        value. The recognized modes are:                            'std' (default) --  allows any expression which evaluates                                                to a number, including those using                                                elementary functions like sin() and                                                exp(), as well as the operations                                                  of                                                arithmetic (+, -, *, /, ^)                            'strict'    --  only decimal numbers are allowed                            'frac'      --  whole numbers and fractions are allowed                            'arith'     --  arithmetic expressions are allowed, but                                                no functions                        Note that all modes allow the use of "pi" and "e" as                        constants, and also the use of "E" to represent scientific                        notation.
    format          --  The format to use when displaying the correct and                        submitted answers. This has no effect on how answers are                        evaluated; it is only for cosmetic purposes. The                        formatting syntax is the same as Perl uses for the sprintf()                        function. Format strings are of the form '%m.nx' or '%m.nx#',                        where m and n are described below, and x is a formatter.                            Esentially, m is the minimum length of the field                        (make this negative to left-justify). Note that the decimal                        point counts as a character when determining the field width.                        If m begins with a zero, the number will be padded with zeros                        instead of spaces to fit the field.                            The precision specifier (n) works differently, depending                        on which formatter you are using. For d, i, o, u, x and X                        formatters (non-floating point formatters), n is the minimum                        number of digits to display. For e and f, it is the number                          of                        digits that appear after the decimal point (extra digits                          will                        be rounded; insufficient digits will be padded with spaces--see                        '#' below). For g, it is the number of significant digits                            to                        display.                            The full list of formatters can be found in the manpage                        for printf(3), or by typing "perldoc -f sprintf" at a                        terminal prompt. The following is a brief summary of the                        most frequent formatters:                            d   --  decimal number                            ld  --  long decimal number                            u   --  unsigned decimal number                            lu  --  long unsigned decimal number                            x   --  hexadecimal number                            o   --  octal number                            e   --  floating point number in scientific notation                            f   --  floating point number                            g   --  either e or f, whichever takes less space                        Technically, g will use e if the exponent is less than -4                          or                        greater than or equal to the precision. Trailing zeros are                        removed in this mode.                            If the format string ends in '#', trailing zeros will                                                             be                        removed in the decimal part. Note that this is not a standard                        syntax; it is handled internally by WeBWorK and not by Perl                        (although this should not be a concern to end users).                        The default format is '%0.5f#', which displays as a floating                        point number with 5 digits of precision and no trailing zeros.                        Other useful format strings might be '%0.2f' for displaying                        dollar amounts, or '%010d' to display an integer with leading                        zeros. Setting format to an empty string ( " ) means no                        formatting will be used; this will show 'arbitrary' precision                        floating points.

Default Values (As of 7/24/2000) (Option -- Variable Name -- Value)

    Format                  --  $numFormatDefault -- "%0.5f#" Relative Tolerance --$numRelPercentTolDefault    --  .1    Absolute Tolerance      --  $numAbsTolDefault -- .001 Zero Level --$numZeroLevelDefault        --  1E-14    Zero Level Tolerance    --  $numZeroLevelTolDefault -- 1E-12 ### num_cmp() Compares a number or a list of numbers, using a named hash of options to set parameters. This can make for more readable code than using the "mode"_num_cmp() style, but some people find one or the other easier to remember. ANS( num_cmp( answer or answer_array_ref, options_hash ) );  1. the correct answer, or a reference to an array of correct answers 2. a hash with the following keys (all optional): mode -- 'std' (default) (allows any expression evaluating to a number) 'strict' (only numbers are allowed) 'frac' (fractions are allowed) 'arith' (arithmetic expressions allowed) format -- '%0.5f#' (default); defines formatting for the correct answer tol -- an absolute tolerance, or relTol -- a relative tolerance units -- the units to use for the answer(s) strings -- a reference to an array of strings which are valid answers (works like std_num_str_cmp() ) zeroLevel -- if the correct answer is this close to zero, then zeroLevelTol applies zeroLevelTol -- absolute tolerance to allow when answer is close to zero  debug -- if set to 1, provides verbose listing of hash entries throughout fliters.  Returns an answer evaluator, or (if given a reference to an array of answers), a list of answer evaluators. Note that a reference to an array of answers results is just a shortcut for writing a separate <code>num_cmp()</code> for each answer. EXAMPLES:  num_cmp( 5 ) -- correct answer is 5, using defaults for all options num_cmp( [5,6,7] ) -- correct answers are 5, 6, and 7, using defaults for all options num_cmp( 5, mode => 'strict' ) -- correct answer is 5, mode is strict num_cmp( [5,6], relTol => 5 ) -- correct answers are 5 and 6, both with 5% relative tolerance num_cmp( 6, strings => ["Inf", "Minf", "NaN"] ) -- correct answer is 6, "Inf", "Minf", and "NaN" recognized as valid, but incorrect answers. num_cmp( "-INF", strings => ["INF", "-INF"] ) -- correct answer is "-INF", "INF" and numerical expressions recognized as valid, but incorrect answers. ### "mode"_num_cmp() functions There are 16 functions total, 4 for each mode (std, frac, strict, arith). Each mode has one "normal" function, one which accepts a list of answers, one which uses absolute rather than relative tolerance, and one which uses absolute tolerance and accepts a list. The "std" family is documented below; all others work precisely the same.  std_num_cmp($correctAnswer) OR std_num_cmp($correctAnswer,$relPercentTol) OR std_num_cmp($correctAnswer,$relPercentTol, $format) OR std_num_cmp($correctAnswer, $relPercentTol,$format, $zeroLevel) OR std_num_cmp($correctAnswer, $relPercentTol,$format, $zeroLevel,$zeroLevelTol)
    $correctAnswer -- the correct answer$relPercentTol  --  the tolerance, as a percentage (optional)    $format -- the format of the displayed answer (optional)$zeroLevel  --  if the correct answer is this close to zero, then zeroLevelTol      applies (optional)    $zeroLevelTol -- absolute tolerance to allow when correct answer is close to zero (optional)  std_num_cmp() uses standard mode (arithmetic operations and elementary functions allowed) and relative tolerance. Options are specified by one or more parameters. Note that if you wish to set an option which is later in the parameter list, you must set all previous options.  std_num_cmp_abs($correctAnswer) OR std_num_cmp_abs($correctAnswer,$absTol) OR std_num_cmp_abs($correctAnswer,$absTol, $format) $correctAnswer      --  the correct answer    $absTol -- an absolute tolerance (optional)$format         --  the format of the displayed answer (optional)
    std_num_cmp_abs() uses standard mode and absolute tolerance. Options    are set as with std_num_cmp(). Note that $zeroLevel and$zeroLevelTol    do not apply with absolute tolerance.
 std_num_cmp_list($relPercentTol,$format, @answerList)
    $relPercentTol -- the tolerance, as a percentage$format         --  the format of the displayed answer(s)    @answerList     --  a list of one or more correct answers
    std_num_cmp_list() uses standard mode and relative tolerance. There    is no way to set $zeroLevel or$zeroLevelTol. Note that no    parameters are optional. All answers in the list will be    evaluated with the same set of parameters.
 std_num_cmp_abs_list($absTol,$format, @answerList)
    $absTol -- an absolute tolerance$format     --  the format of the displayed answer(s)    @answerList --  a list of one or more correct answers
    std_num_cmp_abs_list() uses standard mode and absolute tolerance.    Note that no parameters are optional. All answers in the list will be    evaluated with the same set of parameters.
 arith_num_cmp(), arith_num_cmp_list(), arith_num_cmp_abs(), arith_num_cmp_abs_list() strict_num_cmp(), strict_num_cmp_list(), strict_num_cmp_abs(), strict_num_cmp_abs_list() frac_num_cmp(), frac_num_cmp_list(), frac_num_cmp_abs(), frac_num_cmp_abs_list()

Examples:

    ANS( strict_num_cmp( 3.14159 ) )    --  The student answer must be a number        in decimal or scientific notation which is within .1 percent of 3.14159.        This assumes $numRelPercentTolDefault has been set to .1. ANS( strict_num_cmp($answer, .01 ) )   --  The student answer must be a        number within .01 percent of $answer (e.g. 3.14159 if$answer is 3.14159        or $answer is "pi" or$answer is 4*atan(1)).    ANS( frac_num_cmp( $answer) ) or ANS( frac_num_cmp($answer,.01 ))  --        The student answer can be a number or fraction, e.g. 2/3.    ANS( arith_num_cmp( $answer) ) or ANS( arith_num_cmp($answer,.01 ))    --        The student answer can be an arithmetic expression, e.g. (2+3)/7-2^.5 .    ANS( std_num_cmp( $answer) ) or ANS( std_num_cmp($answer,.01 ))    --        The student answer can contain elementary functions, e.g. sin(.3+pi/2)

### std_num_str_cmp()

 NOTE: This function is maintained for compatibility. num_cmp() with the 'strings' parameter is slightly preferred.

std_num_str_cmp() is used when the correct answer could be either a number or a string. For example, if you wanted the student to evaluate a function at number of points, but write "Inf" or "Minf" if the function is unbounded. This routine will provide error messages that do not give a hint as to whether the correct answer is a string or a number. For numerical comparisons, std_num_cmp() is used internally; for string comparisons, std_str_cmp() is used. String answers must consist entirely of letters except that an initial minus sign is allowed. E.g. "inf" and "-inf" are valid strings where as "too-big" is not.

 std_num_str_cmp( $correctAnswer ) OR std_num_str_cmp($correctAnswer, $ra_legalStrings ) OR std_num_str_cmp($correctAnswer, $ra_legalStrings,$relPercentTol ) OR std_num_str_cmp( $correctAnswer,$ra_legalStrings, $relPercentTol,$format ) OR std_num_str_cmp( $correctAnswer,$ra_legalStrings, $relPercentTol,$format, $zeroLevel ) OR std_num_str_cmp($correctAnswer, $ra_legalStrings,$relPercentTol, $format,$zeroLevel, $zeroLevelTol ) $correctAnswer      --  the correct answer    $ra_legalStrings -- a reference to an array of legal strings, e.g. ["str1", "str2"]$relPercentTol      --  the error tolerance as a percentage    $format -- the display format$zeroLevel      --  if the correct answer is this close to zero, then zeroLevelTol      applies    $zeroLevelTol -- absolute tolerance to allow when correct answer is close to zero  Examples: ANS( std_num_str_cmp($ans, ["Inf", "Minf", "NaN"] ) ); ANS( std_num_str_cmp( $ans, ["INF", "-INF"] ) ); ## Function Answer Evaluators Function answer evaluators take in a function, compare it numerically to a correct function, and return a score. They can require an exactly equivalent function, or one that is equal up to a constant. They can accept or reject an answer based on specified tolerances for numerical deviation. Function Comparison Options  correctEqn -- The correct equation, specified as a string. It may include all basic arithmetic operations, as well as elementary functions. Variable usage is described below.  Variables -- The independent variable(s). When comparing the correct equation to the student equation, each variable will be replaced by a certain number of numerical values. If the student equation agrees numerically with the correct equation, they are considered equal. Note that all comparison is numeric; it is possible (although highly unlikely and never a practical concern) for two unequal functions to yield the same numerical results.  Limits -- The limits of evaluation for the independent variables. Each variable is evaluated only in the half-open interval [lower_limit, upper_limit). This is useful if the function has a singularity or is not defined in a certain range. For example, the function "sqrt(-1-x)" could be evaluated in [-2,-1).  Tolerance -- Tolerance in function comparisons works exactly as in numerical comparisons; see the numerical comparison documentation for a complete description. Note that the tolerance does applies to the function as a whole, not each point individually.  Number of -- Specifies how many points to evaluate each variable at. This Points is typically 3, but can be set higher if it is felt that there is a strong possibility of "false positives."  Maximum -- Sets the maximum size of the constant of integration. For Constant of technical reasons concerning floating point arithmetic, if Integration the additive constant, i.e., the constant of integration, is greater (in absolute value) than maxConstantOfIntegration AND is greater than maxConstantOfIntegration times the correct value, WeBWorK will give an error message saying that it can not handle such a large constant of integration. This is to prevent e.g. cos(x) + 1E20 or even 1E20 as being accepted as a correct antiderivatives of sin(x) since floating point arithmetic cannot tell the difference between cos(x) + 1E20, 1E20, and -cos(x) + 1E20. Technical note: if you examine the code for the function routines, you will see that most subroutines are simply doing some basic error-checking and then passing the parameters on to the low-level FUNCTION_CMP(). Because this routine is set up to handle multivariable functions, with single-variable functions as a special case, it is possible to pass multivariable parameters to single- variable functions. This usage is strongly discouraged as unnecessarily confusing. Avoid it. Default Values (As of 7/24/2000) (Option -- Variable Name -- Value)  Variable --$functVarDefault            --  'x'    Relative Tolerance      --  $functRelPercentTolDefault -- .1 Absolute Tolerance --$functAbsTolDefault         --  .001    Lower Limit         --  $functLLimitDefault -- .0000001 Upper Limit --$functULimitDefault         --  1    Number of Points        --  $functNumOfPoints -- 3 Zero Level --$functZeroLevelDefault          --  1E-14    Zero Level Tolerance        --  $functZeroLevelTolDefault -- 1E-12 Maximum Constant --$functMaxConstantOfIntegration      --  1E8        of Integration

### fun_cmp()

Compares a function or a list of functions, using a named hash of options to set parameters. This can make for more readable code than using the function_cmp() style, but some people find one or the other easier to remember.

    1. a string containing the correct function, or a reference to an        array of correct functions    2. a hash containing the following items (all optional):        var                     --  either the number of variables or a reference          to an                                            array of variable names (see below)        limits                      --  reference to an array of arrays of limits          (see below), or:        mode                        --  'std' (default) (function must match exactly),          or:                                        'antider' (function must match up to a constant)        relTol                      --  (default) a relative tolerance (as a percentage),          or:        tol                     --  an absolute tolerance for error        numPoints                   --  the number of points to evaluate the function          at        maxConstantOfIntegration            --  maximum size of the constant of integration        zeroLevel                   --  if the correct answer is this close to zero,          then                                            zeroLevelTol applies        zeroLevelTol                    --  absolute tolerance to allow when answer          is close to zero        test_points -- a list of points to use in checking the function, or a list          of lists when there is more than one variable.        params                          an array of "free" parameters which can be          used to adapt                                    the correct answer to the submitted answer. (e.g.                                      ['c'] for                                    a constant of integration in the answer x^3/3                                      + c.        debug                       --  when set to 1 this provides extra information          while checking the                                    the answer.
    Returns an answer evaluator, or (if given a reference to an array    of answers), a list of answer evaluators

    The answer must be in the form of a string. The answer can contain    functions, pi, e, and arithmetic operations. However, the correct answer    string follows a slightly stricter syntax than student answers; specifically,    there is no implicit multiplication. So the correct answer must be "3*x" rather    than "3 x". Students can still enter "3 x".

VARIABLES:

    The var parameter can contain either a number or a reference to an array of    variable names. If it contains a number, the variables are named automatically    as follows: 1 variable  --  x            2 variables --  x, y            3 variables --  x, y, z            4 or more   --  x_1, x_2, x_3, etc.    If the var parameter contains a reference to an array of variable names, then    the number of variables is determined by the number of items in the array. A    reference to an array is created with brackets, e.g. "var => ['r', 's', 't']".    If only one variable is being used, you can write either "var => ['t']" for    consistency or "var => 't'" as a shortcut. The default is one variable, x.

LIMITS:

    Limits are specified with the limits parameter. You may NOT use llimit/ulimit.    If you specify limits for one variable, you must specify them for all variables.    The limit parameter must be a reference to an array of arrays of the form    [lower_limit. upper_limit], each array corresponding to the lower and upper    endpoints of the (half-open) domain of one variable. For example,    "vars => 2, limits => [[0,2], [-3,8]]" would cause x to be evaluated in [0,2)      and    y to be evaluated in [-3,8). If only one variable is being used, you can write    either "limits => [[0,3]]" for consistency or "limits => [0,3]" as a shortcut.

TEST POINTS:

    In some cases, the problem writer may want to specify the points    used to check a particular function.    For example, if you want to    use only integer values, they can be specified. With one variable,    you can specify "test_points => [1,4,5,6]" or "test_points => [[1,4,5,6]]".    With more variables, specify the list for the first variable, then the    second, and so on: "vars=>['x','y'], test_points => [[1,4,5],[7,14,29]]".
    If the problem writer wants random values which need to meet some special    restrictions (such as being integers), they can be generated in the problem:    "test_points=>[random(1,50), random(1,50), random(1,50), random(1,50)]".
    Note that test_points should not be used for function checks which involve    parameters  (either explicitly given by "params", or as antiderivatives).

EXAMPLES:

    fun_cmp( "3*x" )    --  standard compare, variable is x    fun_cmp( ["3*x", "4*x+3", "3*x**2"] )   --  standard compare, defaults used for      all three functions    fun_cmp( "3*t", var => 't' )    --  standard compare, variable is t    fun_cmp( "5*x*y*z", var => 3 )  --  x, y and z are the variables    fun_cmp( "5*x", mode => 'antider' ) --  student answer must match up to constant      (i.e., 5x+C)    fun_cmp( ["3*x*y", "4*x*y"], limits => [[0,2], [5,7]] ) --  x evaluated in [0,2)                                                                y evaluated in [5,7)

### Single-variable Function Comparisons

There are four single-variable function answer evaluators: "normal," absolute tolerance, antiderivative, and antiderivative with absolute tolerance. All parameters (other than the correct equation) are optional.

 function_cmp( $correctEqn ) OR function_cmp($correctEqn, $var ) OR function_cmp($correctEqn, $var,$llimit, $ulimit ) OR function_cmp($correctEqn, $var,$llimit, $ulimit,$relPercentTol ) OR function_cmp( $correctEqn,$var, $llimit,$ulimit,                $relPercentTol,$numPoints ) OR function_cmp( $correctEqn,$var, $llimit,$ulimit,                $relPercentTol,$numPoints, $zeroLevel ) OR function_cmp($correctEqn, $var,$llimit, $ulimit,$relPercentTol, $numPoints,$zeroLevel,$zeroLevelTol ) $correctEqn     --  the correct equation, as a string    $var -- the string representing the variable (optional)$llimit         --  the lower limit of the interval to evaluate the                            variable in (optional)    $ulimit -- the upper limit of the interval to evaluate the variable in (optional)$relPercentTol  --  the error tolerance as a percentage (optional)    $numPoints -- the number of points at which to evaluate the variable (optional)$zeroLevel      --  if the correct answer is this close to zero, then                            zeroLevelTol applies (optional)    $zeroLevelTol -- absolute tolerance to allow when answer is close to zero  function_cmp() uses standard comparison and relative tolerance. It takes a string representing a single-variable function and compares the student answer to that function numerically.  function_cmp_up_to_constant($correctEqn ) OR function_cmp_up_to_constant( $correctEqn,$var ) OR function_cmp_up_to_constant( $correctEqn,$var, $llimit,$ulimit ) OR function_cmp_up_to_constant( $correctEqn,$var, $llimit,$ulimit,                                $relpercentTol ) OR function_cmp_up_to_constant($correctEqn, $var,$llimit, $ulimit,$relpercentTol, $numOfPoints ) OR function_cmp_up_to_constant($correctEqn, $var,$llimit, $ulimit,$relpercentTol, $numOfPoints,$maxConstantOfIntegration ) OR function_cmp_up_to_constant( $correctEqn,$var, $llimit,$ulimit,                                $relpercentTol,$numOfPoints,                                $maxConstantOfIntegration,$zeroLevel)  OR function_cmp_up_to_constant( $correctEqn,$var, $llimit,$ulimit,                                $relpercentTol,$numOfPoints,                                $maxConstantOfIntegration,$zeroLevel, $zeroLevelTol ) $maxConstantOfIntegration   --  the maximum size of the constant of                                    integration
    function_cmp_up_to_constant() uses antiderivative compare and relative    tolerance. All options work exactly like function_cmp(), except of course    $maxConstantOfIntegration. It will accept as correct any function which differs from$correctEqn by at most a constant; that is, if        $studentEqn =$correctEqn + C    the answer is correct.
 function_cmp_abs( $correctFunction ) OR function_cmp_abs($correctFunction, $var ) OR function_cmp_abs($correctFunction, $var,$llimit, $ulimit ) OR function_cmp_abs($correctFunction, $var,$llimit, $ulimit,$absTol ) OR function_cmp_abs( $correctFunction,$var, $llimit,$ulimit, $absTol,$numOfPoints )
    $absTol -- the tolerance as an absolute value  function_cmp_abs() uses standard compare and absolute tolerance. All other options work exactly as for function_cmp().  function_cmp_up_to_constant_abs($correctFunction ) OR function_cmp_up_to_constant_abs( $correctFunction,$var ) OR function_cmp_up_to_constant_abs( $correctFunction,$var, $llimit,$ulimit ) OR function_cmp_up_to_constant_abs( $correctFunction,$var, $llimit,$ulimit,                                    $absTol ) OR function_cmp_up_to_constant_abs($correctFunction, $var,$llimit, $ulimit,$absTol, $numOfPoints ) OR function_cmp_up_to_constant_abs($correctFunction, $var,$llimit, $ulimit,$absTol, $numOfPoints,$maxConstantOfIntegration )
    function_cmp_up_to_constant_abs() uses antiderivative compare    and absolute tolerance. All other options work exactly as with    function_cmp_up_to_constant().

Examples:

    ANS( function_cmp( "cos(x)" ) ) --  Accepts cos(x), sin(x+pi/2),        sin(x)^2 + cos(x) + cos(x)^2 -1, etc. This assumes        $functVarDefault has been set to "x". ANS( function_cmp($answer, "t" ) ) --  Assuming $answer is "cos(t)", accepts cos(t), etc. ANS( function_cmp_up_to_constant( "cos(x)" ) ) -- Accepts any antiderivative of sin(x), e.g. cos(x) + 5. ANS( function_cmp_up_to_constant( "cos(z)", "z" ) ) -- Accepts any antiderivative of sin(z), e.g. sin(z+pi/2) + 5. ### multivar_function_cmp  NOTE: this function is maintained for compatibility. fun_cmp() is slightly preferred. usage:  multivar_function_cmp($answer, $var_reference, options)$answer             --  string, represents function of several variables        $var_reference -- number (of variables), or list reference (e.g. ["var1","var2"] ) options:$limit_reference    --  reference to list of lists (e.g. [[1,2],[3,4]])        $relPercentTol -- relative percent tolerance in answer$numPoints          --  number of points to sample in for each variable        $zeroLevel -- if the correct answer is this close to zero, then zeroLevelTol applies$zeroLevelTol       --  absolute tolerance to allow when answer is close          to zero

String answer evaluators compare a student string to the correct string. Different filters can be applied to allow various degrees of variation. Both the student and correct answers are subject to the same filters, to ensure that there are no unexpected matches or rejections.

String Filters

    remove_whitespace   --  Removes all whitespace from the string.                        It applies the following substitution                        to the string:                            $filteredAnswer =~ s/\s+//g;  compress_whitespace -- Removes leading and trailing whitespace, and replaces all other blocks of whitespace by a single space. Applies the following substitutions:$filteredAnswer =~ s/^\s*//;                            $filteredAnswer =~ s/\s*$//;                            $filteredAnswer =~ s/\s+/ /g;  trim_whitespace -- Removes leading and trailing whitespace. Applies the following substitutions:$filteredAnswer =~ s/^\s*//;                            $filteredAnswer =~ s/\s*$//;
    ignore_case         --  Ignores the case of the string. More accurately,                        it converts the string to uppercase (by convention).                        Applies the following function:                            $filteredAnswer = uc$filteredAnswer;
    ignore_order        --  Ignores the order of the letters in the string.                        This is used for problems of the form "Choose all                        that apply." Specifically, it removes all                        whitespace and lexically sorts the letters in                        ascending alphabetical order. Applies the following                        functions:                            $filteredAnswer = join( "", lex_sort( split( /\s*/,$filteredAnswer ) ) );

### str_cmp()

Compares a string or a list of strings, using a named hash of options to set parameters. This can make for more readable code than using the "mode"_str_cmp() style, but some people find one or the other easier to remember.

    1. the correct answer or a reference to an array of answers    2. either a list of filters, or:        a hash consisting of        filters - a reference to an array of filters
    Returns an answer evaluator, or (if given a reference to an array of answers),    a list of answer evaluators

FILTERS:

    remove_whitespace   --  removes all whitespace    compress_whitespace --  removes whitespace from the beginning and end of the      string,                            and treats one or more whitespace characters in a row                              as a                            single space (true by default)    trim_whitespace     --  removes whitespace from the beginning and end of the      string    ignore_case     --  ignores the case of the letters (true by default)    ignore_order        --  ignores the order in which letters are entered

EXAMPLES:

    str_cmp( "Hello" )  --  matches "Hello", "  hello" (same as std_str_cmp() )    str_cmp( ["Hello", "Goodbye"] ) --  same as std_str_cmp_list()    str_cmp( " hello ", trim_whitespace )   --  matches "hello", " hello    "    str_cmp( "ABC", filters => 'ignore_order' ) --  matches "ACB", "A B C", but not      "abc"    str_cmp( "D E F", remove_whitespace, ignore_case )  --  matches "def" and "d      e f" but not "fed"

### "mode"_str_cmp functions

The functions of the the form "mode"_str_cmp() use different functions to specify which filters to apply. They take no options except the correct string. There are also versions which accept a list of strings.

 std_str_cmp( $correctString ) std_str_cmp_list( @correctStringList ) Filters: compress_whitespace, ignore_case  std_cs_str_cmp($correctString ) std_cs_str_cmp_list( @correctStringList )    Filters: compress_whitespace
 strict_str_cmp( $correctString ) strict_str_cmp_list( @correctStringList ) Filters: trim_whitespace  unordered_str_cmp($correctString ) unordered_str_cmp_list( @correctStringList )    Filters: ignore_order, ignore_case
 unordered_cs_str_cmp( $correctString ) unordered_cs_str_cmp_list( @correctStringList ) Filters: ignore_order  ordered_str_cmp($correctString ) ordered_str_cmp_list( @correctStringList )    Filters: remove_whitespace, ignore_case
 ordered_cs_str_cmp( $correctString ) ordered_cs_str_cmp_list( @correctStringList ) Filters: remove_whitespace Examples  ANS( std_str_cmp( "W. Mozart" ) ) -- Accepts "W. Mozart", "W. MOZarT", and so forth. Case insensitive. All internal spaces treated as single spaces. ANS( std_cs_str_cmp( "Mozart" ) ) -- Rejects "mozart". Same as std_str_cmp() but case sensitive. ANS( strict_str_cmp( "W. Mozart" ) ) -- Accepts only the exact string. ANS( unordered_str_cmp( "ABC" ) ) -- Accepts "a c B", "CBA" and so forth. Unordered, case insensitive, spaces ignored. ANS( unordered_cs_str_cmp( "ABC" ) ) -- Rejects "abc". Same as unordered_str_cmp() but case sensitive. ANS( ordered_str_cmp( "ABC" ) ) -- Accepts "a b C", "A B C" and so forth. Ordered, case insensitive, spaces ignored. ANS( ordered_cs_str_cmp( "ABC" ) ) -- Rejects "abc", accepts "A BC" and so forth. Same as ordered_str_cmp() but case sensitive. ## Miscellaneous Answer Evaluators (Checkboxes and Radio Buttons) These evaluators do not fit any of the other categories. checkbox_cmp($correctAnswer )

    $correctAnswer -- a string containing the names of the correct boxes, e.g. "ACD". Note that this means that individual checkbox names can only be one character. Internally, this is largely the same as unordered_cs_str_cmp(). radio_cmp($correctAnswer )

    $correctAnswer -- a string containing the name of the correct radio button, e.g. "Choice1". This is case sensitive and whitespace sensitive, so the correct answer must match the name of the radio button exactly. ## Filters A filter is a short subroutine with the following structure. It accepts an AnswerHash, followed by a hash of options. It returns an AnswerHash $ans_hash = filter($ans_hash, %options); See the AnswerHash.pm file for a list of entries which can be expected to be found in an AnswerHash, such as 'student_ans', 'score' and so forth. Other entries may be present for specialized answer evaluators. The hope is that a well designed set of filters can easily be combined to form a new answer_evaluator and that this method will produce answer evaluators which are are more robust than the method of copying existing answer evaluators and modifying them. Here is an outline of how a filter is constructed:  sub filter{ my$rh_ans = shift;        my %options = @_;        assign_option_aliases(\%options,                'alias1'    => 'option5'                'alias2'    => 'option7'        );        set_default_options(\%options,                '_filter_name'  =>  'filter',                'option5'       =>  .0001,                'option7'       =>  'ascii',                'allow_unknown_options  =>  0,        }        .... body code of filter .......            if ($error) {$rh_ans->throw_error("FILTER_ERROR", "Something went wrong");                # see AnswerHash.pm for details on using the throw_error method.

The comparison function should have $dim_of_params_space more input variables than the test function. #### calculate_difference_vector  calculate_difference_vector($ans_hash, %options);
                    {rf_student_ans},   # a reference to the test function                    {rf_correct_ans},   # a reference to the correct answer function                    {evaluation_points},    # an array of row vectors indicating                                               the points                                # to evaluate when comparing the functions                    {ra_parameters} # these are the (optional) additional inputs                                       to                                # the comparison function which adapt it properly                                # to the problem at hand.
                    %options        # mode => 'rel' specifies that each element in                                       the                                # difference matrix is divided by the correct answer.                                # unless the correct answer is nearly 0.                    )

#### phase_pi I often discovered that the answers I was getting, when using the arctan function would be off by phases of pi, which for the tangent function, were equivalent values. This method allows for this. =cut

sub phase_pi { my ($num,%options) = @_; my$process_ans_hash = ( ref( $num ) eq 'AnswerHash' ) ? 1 : 0 ; my ($rh_ans); if ($process_ans_hash) {$rh_ans = $num;$num = $rh_ans->{correct_ans}; } while( ($rh_ans->{correct_ans}) > 3.14159265358979/2 ){ $rh_ans->{correct_ans} -= 3.14159265358979; } while( ($rh_ans->{correct_ans}) <= -3.14159265358979/2 ){ $rh_ans->{correct_ans} += 3.14159265358979; }$rh_ans; }