Quick Reference for WeBWorK

All of the following require load("PGstandard.pl");

Text Formatting
Special Characters
Special Values
Ordered and Unordered Lists
Tables
Random Number Generators
Roundings
Number Format
Integer Functions
Array Functions
Two-dimensional Arrays
Sorting
MathObject Matrices
Conditional Statements
Loops
MathObjects
MathObject Context Settings
Standard Answer Checkers
Additional Answer Checkers
Multiple Choice Problems
Answer Checker Post Filters
Problem Graders
Graphing
Numerical Methods
GeoGebra Integration
R Commands

Text Formatting:

$BR
Line break
$PAR
Paragraph break, slightly smaller than "$BR $BR"
$REVBR Reverse line break for decreasing vertical spacing. Only affects printouts.
Requires loadMacros("BCITmacros.pl");
$HR Horizontal rule
$NEWPAGE Page break. Only affects printouts.
Requires loadMacros("BCITmacros.pl");
$NEWPAGESOL Page break only if the solution is printed. Only affects printouts.
Requires loadMacros("BCITmacros.pl");
$BBOLD / $EBOLD
Begin/end bold typeface
$BITALIC / $EITALIC
Begin/end italic typeface
$BUL / $EUL Begin/end underlined typeface
$BCENTER / $ECENTER
Begin/end centred typeface
$Blarge / $Elarge / $BLARGE / $ELARGE Begin/end large (125%) or LARGE (150%) font size
Requires loadMacros("BCITmacros.pl");
$BSUP / $ESUP
Begin/end superscript typeface. To display cm2, use cm${BSUP}2${ESUP}.
Requires loadMacros("BCITmacros.pl");
$BSUB / $ESUB
Begin/end subscript typeface. To display O2, use O${BSUB}2${ESUB}.
Requires loadMacros("BCITmacros.pl");
$BCODE / $ECODE Begin/end code (monospace) typeface
Requires loadMacros("BCITmacros.pl");
$BRED / $ERED
$BBLUE / $EBLUE
$BGREEN / $EGREEN
$BGRAY / $EGRAY

  OR

\{BCOLOR("HTML color name", "LaTeX color name")\} / \{ECOLOR()\}
Begin/end colour in text.

For HTML colour names, refer to https://www.w3schools.com/tags/ref_colornames.asp
For LaTeX colour names, refer to https://en.wikibooks.org/wiki/LaTeX/Colors

Requires loadMacros("BCITmacros.pl");
\{htmlLink("http://www.bcit.ca/", "this page")\}
HTML link

Special Characters:

$SPACE
Space character (for extra spaces)
$NBSP
Non-breaking space character

To display 5 cm, use 5${NBSP}cm to prevent a line break between "5" and "cm".
$DOLLAR Dollar sign. To display $5 without a space in between, use ${DOLLAR}5.
$PERCENT Percentage sign % (required for printouts)
$NUMSIGN Number sign #
Requires loadMacros("BCITmacros.pl");
$DEG Degree sign. Only works in text mode. Use ^\circ in LaTeX mode.
Requires loadMacros("BCITmacros.pl");
$ALPHA, $BETA, $GAMMA, $THETA, $PISIGN, $PHI, $OMEGA Greek alphabets α, β, γ, θ, π, ϕ, Ω
Requires loadMacros("BCITmacros.pl");
$NEQSIGN, $LESIGN, $GESIGN Inequality signs ≠, ≤, ≥
Requires loadMacros("BCITmacros.pl");
$OVERHAT, $OVERTILDE, $OVERLINE, $OVERBAR, $OVERDOT, $OVERDOTDOT, $OVERRIGHTARROW Accents. Mainly used for graphs.
Requires loadMacros("BCITmacros.pl");
$US
Underscore (required for printout)

Special Values:

$PI 3.14159265358979
$E
2.71828182845905
$studentID Student ID
$studentName Student name
$problemNumber Displays "Problem #:" in bold. Useful for printouts.
Requires loadMacros("BCITmacros.pl");
$problemSeed Problem seed

Ordered and Unordered Lists:

Requires loadMacros("BCITmacros.pl");

\{BeginOL\}

  OR

\{BeginOL(type=>'a', start=>1)\}
Begins an ordered list.
type: '1', 'a', 'A', 'i', 'I'. Optional. If skipped, default is 'a'.
start: The list starts at this value. Optional. If skipped, default is 1.
boldMarkers: Whether or not to bold the list markers. Optional. If skipped, default is 0.
noPAR: Whether or not to insert a line break before the start of the list. Optional. If skipped, default is 0.
\{EndOL\} Ends the ordered list.
\{BeginUL\}

  OR

\{BeginUL(type=>'disc')\}
Begins an unordered list.
type: 'disc', 'circle', 'square'. Optional. If skipped, default is 'disc'.
\{EndUL\}
Ends the unordered list.
$ITEM
Begins an item.
$ITEMPAR Paragraph break inside an item (proper spacing adjusted for both HTML and printouts).
$ITEMSEP
Vertical space separating the items (proper spacing adjusted for both HTML and printouts).

Tables:

@cells = (
  [$cell00, $cell01, $cell02],
  [$cell10, $cell11, $cell12]
);

$table = CreateTable([@cells]);

  OR

$table = CreateTable([@cells],
  width=>"70%",
  border=>1,
  borderstyle=>"solid",
  vrules=>1,
  vrulestyle=>"solid",
  hrules=>1,
  hrulestyle=>"solid",
  headerrow=>0,
  headercolumn=>0,
  vpad=>10,
  hpad=>10,
  valign=>"middle",
  halign=>"center",
  haligntex=>"|ccr|",
  nowrap=>0,
  colspanning=>1,
)

BEGIN_TEXT
$table
END_TEXT
Creates a table.

width: Optional. Width of table. If skipped, default is automatic. Only affects HTML.
border: Optional. Border thickness. Use border=>0 for borderless tables. If skipped, default is 1. Use an array if the thickness of each side of the outer border is different. For example, border=>[1, 2, 3, 0] means the thicknesses of the top, right, bottom and left are 1, 2, 3 and 0, respectively.
borderstyle: Optional. Can be "solid" or "double". Use an array if the style of each side of the outer border is different. If skipped, default is "solid".
vrules: Optional. Thickness of vertical rules. Use an array if the thickness of each rule is different. For example, vrules=>[1, 0, 0]. If skipped, default is border.
vrulestyle: Optional. Style of vertical rules. Can be "solid" or "double". Use an array if the style of each rule is different. For example, vrulestyle=>["double", "solid", "solid"]. If skipped, default is "solid".
hrules: Optional. Thickness of horizontal rules. Can be "solid" or "double". Use an array if the thickness of each rule is different. For example, hrules=>[1, 0, 0]. If skipped, default is border.
hrulestyle: Optional. Style of horizontal rules. Use an array if the style of each rule is different. For example, hrulestyle=>["double", "solid", "solid"]. If skipped, default is "solid".
headerrow: Optional. Whether ot not to bold the first row. If skipped, default is 0.
headercolumn: Optional. Whether ot not to bold the first column. If skipped, default is 0.
vpad: Optional. Padding between rows in pixels. If skipped, default is 5. Only affects HTML.
hpad: Optional. Padding between columns in pixels. If skipped, default is 20. Only affects HTML.
valign: Optional. Vertical alignment in cells. Can be "top", "bottom", "middle" or "baseline". valign=>"top" applies to the entire table. valign=>["top", "middle", "top"] applies to each row. If skipped, default is "middle".
halign: Optional. Horizontal alignment in cells. Can be "left", "right" or "center". halign=>"left" applies to the entire table. halign=>["left", "center", "right"] applies to each row. If skipped, default is "center".
haligntex: Optional. Horizontal alignment for printouts. Use LaTeX tabular settings. This overrides halign.
nowrap: Optional. Whether or not to disable text wrapping. If skipped, default is 0. If text wrapping is disabled only in some cells, use $NOBR at the beginning of each of those cells. Only affects HTML.
colspanning: Optional. Whether or not to enable column spanning. For colspanning=>1, if the cell in the next column is undef, then the content of the cell will be spanned to the next column. If skipped, default is 1.

Requires loadMacros("BCITmacros.pl");
loadMacros("niceTables.pl");

@cells = (
  [['Names', headerrow=>1], 'Title1', 'Title2'],
  ['name1', $cell11, $
cell12],
  ['name2', $
cell21, $cell22],
  ['name3', $
cell31, $cell32]
);

$table =
DataTable([@cells],
  caption=>"Caption",
  midrules=>1,
  align=>"|l|c|c|",
  center=>1,
  rowheaders=>0,
);


BEGIN_TEXT
$table
END_TEXT

For fancier tables.

headerrow: Bold the entire row. Optional.
caption: Caption at the top of the table. Optional. No caption if skipped.
midrules: Horizontal lines in the table. Optional. If skipped, default is 0.
align: Alignment for each column: l, c, r, (left, centre, right), | (vertical lines in the table).
center: Table is centred on the page. Optional. If skipped, default is 1.
rowheaders: Bold the first column. Optional. If skipped, default is 0.

Requires loadMacros("niceTables.pl");
For more details: https://webwork.maa.org/wiki/Tables or https://github.com/openwebwork/pg/blob/master/macros/niceTables.pl
$table = ColTable($ncol, $col1, ..., $coln);

  OR

$table = ColTable($ncol, $col1, ..., $coln,
  valign=>"middle",
  separation=>[0, ..., 10],
 
allowLineBreak=>[0, ..., 0],
)
Creates a table with one row. Useful if answer boxes are placed above or below the baseline or a line where line breaks are not allowed.

$ncol: Total number of columns
$col1, ..., $coln: Contents of each column
valign: Optional. Vertical alignment. Can be "top", "middle" or "bottom". If skipped, default is "middle".
separation: Optional. Separation between the columns. separation=>0 means separation between all columns are 0. If skipped, default is 0.
allowLineBreak: Optional. Whether of not line break is allowed. Only affects HTML. If skipped, default is 0.

Requires loadMacros("BCITmacros.pl");

Random Number Generators:

$num = random($initial, $final, $increment); Generates one random number between $initial and $final in steps of $increment.
$num = non_zero_random($initial, $final, $increment); Same as random except the output is a non-zero value.
$num = list_random(@array); Randomly picks an entry from @array.
@list = random_multi($N, $initial, $final, $increment); Generates a list of $N possibly repeated random numbers between $initial and $final in steps of $increment.
Requires loadMacros("BCITmacros.pl");
@list = random_multi_unique($N, $initial, $final, $increment); Generates a list of $N distinct random numbers between $initial and $final in steps of $increment.
Requires loadMacros("BCITmacros.pl");
@list = non_zero_random_multi($N, $initial, $final, $increment); Generates a list of $N possibly repeated non-zero random numbers between $initial and $final in steps of $increment.
Requires loadMacros("BCITmacros.pl");
@list = non_zero_random_multi_unique($N, $initial, $final, $increment); Generates a list of $N distinct non-zero random numbers between $initial and $final in steps of $increment.
Requires loadMacros("BCITmacros.pl");
@list = list_random_multi($N, @array); Randomly picks $N possibly repeated entries from @array.
Requires loadMacros("BCITmacros.pl");
@list = list_random_multi_unique($N, @array); Randomly picks $N distinct entries from @array.
Requires loadMacros("BCITmacros.pl");
@list = urand($mean, $sd, $N, $digits);
Generates a list of $N normally distributed random numbers rounded to $digits digits.
Requires loadMacros("PGstatisticsmacros.pl");
@array_new = random_signs(@array); Assigns a random sign to each entry in @array.
Requires loadMacros("BCITmacros.pl");
@array_shuffled = shuffle(@array); Shuffles the entries in @array.
Requires loadMacros("BCITmacros.pl");
($a, $b, $c) = pythagoreanTriple();

  OR

($a, $b, $c) = pythagoreanTriple(factor=>0.1);
Generates a random set of Pythagorean triple where $a \(<\) $b \(<\) $c \(\le\) 999

factor: Optional. Multiply the outputs by this factor. If skipped, default is 1.
@choices = NchooseK($n, $k);
Select $k distinct entries from the list (0 .. $n-1) and output as @choices.
@choices_inv = invert(@choices);
Invert the entries of @choices to its indices.

If @array has $n entries and the following lines are executed
  @choices = NchooseK($n, $n);
  @array_new = @array[@choices];
  @choices_inv = invert(@choices);

then @array_new[@choices_inv] is the same as @array.

Roundings:

$num_rounded = Round($num); Rounds $num to the nearest integer.
$num_rounded = Round($num, $N);
Rounds $num to $N decimal places. $N can be negative if rounding is before the decimal point.
$num_rounded = RoundDigits($num, $N); Rounds $num to $N significant digits. $N must be \(\ge\) 1.
Requires loadMacros("BCITmacros.pl");
$nDecimalPlaces = countDecimalPlaces($num); Counts the number of decimal places when displaying $num.
Requires loadMacros("BCITmacros.pl");
$nDigits = countDigits($num); Counts the number of digits when displaying $num. Leading and trailing zeros are excluded.
Requires loadMacros("BCITmacros.pl");
($sig, $exp) = sigexp($num); Separates $num into significand $sig and exponent $exp (as in scientific notation)
Requires loadMacros("BCITmacros.pl");
$num_rounded = floor($num); Rounds $num to the nearest integer \(\le\) $num
$num_rounded = ceil($num); Rounds $num to the nearest integer \(\ge\) $num
$num_rounded = sprintf("%0.2f", $num);
Rounds $num to 2 decimal places, similar to Round($num, 2) but outputs as a string. (for 3 decimal place, use "%0.3f", etc)
$num_rounded = sprintf("%0.2e", $num); Rounds $num to 2 decimal places in scientific notation (for 3 decimal place, use "%0.3e", etc)
$num_rounded = sprintf("%0.2g", $num); Rounds $num to 2 significant digits, similar to RoundDigits($num, 2) but outputs as a string. (for 3 significant digits, use "%0.3g", etc)
For more details: https://perldoc.perl.org/functions/sprintf
($mean_rounded, $uncertainty_rounded) = roundUncertainty($mean, $uncertainty, $N); Rounds $uncertainty to $N significant figures. Rounds $mean to the same number of decimal places as $uncertainty_rounded. Default value of $N is 1 if skipped.
Requires loadMacros("BCITmacros.pl");
$power_ten = decimalplace($num, $sf);

  OR

$power_ten = lsu($num, $sf);
Outputs the decimal place (\(10^?\)) of the $sf-th digit of $num. Default value of $sf is 1 if skipped.
Requires loadMacros("BCITmacros.pl");
$modulo = $dividend % $divisor;
Modulo. Returns the remainder of $dividend/$divisor.
For integers only.
$modulo = fmod($dividend, $divisor); Floating point modulo. Returns the remainder of $dividend/$divisor.  For floating points and integers.
Requires loadMacros("BCITmacros.pl");

Number Format:

Requires loadMacros("BCITmacros.pl");

$numdisp = commify($num);
$numdisp = integerGrouping($num);
$numdisp = decimalGrouping($num);
$numdisp = digitGrouping($num);
commify: Add commas to the integer part of $num. For example, commify(1234567.7654321) gives 1,234,567.7654321.
integerGrouping: Add spaces to the integer part of $num. For example, integerGrouping(1234567.7654321) gives 1 234 567.7654321.
decimalGrouping: Add spaces to the fractional part of $num. For example, decimalGrouping(1234567.7654321) gives 1234567.765 432 1.
digitGrouping: Add spaces to both the integer and the fractional parts of $num. For example, digitGrouping(1234567.7654321) gives 1 234 567.765 432 1.

Options:
TeX=>0: Whether or not to display in LaTeX mode. Default is 0.
$numdisp = disp($num, $N);

  OR

$numdisp = scinot($num, $N);
For displaying $num rounded to at most $N significant digits in scientific notation.

disp: Shows $num rounded to at most $N significant digits without trailing zeros. By default, scientific notations will be used when $num \(\ge 10^6\) or $num \(\le 10^{-6}\).

scinot: Shows $num rounded to at most $N significant digits without trailing zeros. By default, scientific notations will be used when |$num| \(\ge 10^1\) or |$num| \(\le 10^{-1}\).

Note: disp(0, $N) and scinot(0, $N) will output 0.

Options:
power=>[-6, 6]: The exponents where scientific notation will be used. [-6, 6] means \(\le 10^{-6}\) or \(\ge 10^6\).

nonSigZeros=>1: Whether or not non-significant zeros at the end will be displayed. For example, 210 at 2 sig figs with nonSigZeros=>0 will be displayed as "\(2.1 \times 10^2\)", whereas the same with nonSigZeros=>1 will be displayed as "210".

TeX=>1: Whether or not to display scientific notations using \(\times 10^?\). For example, 1.230E4 with TeX=>0 will be displayed as "1.230E4", whereas the same with TeX=>1 will be displayed as "\(1.230 \times 10^4\)". Default is 1.
$numdisp = sigfig($num, $N);

  OR

$numdisp = sigfig($num, $N, power=>3, barSigZero=>0, nonSigZero=>0);

  OR

$numdisp = sigfig0($num, $N);


  OR

$numdisp = sigfig0($num, $N
, power=>3);
sigfig: Shows $num rounded to exactly $N significant figures. By default, scientific notations will be used when |$num| \(\ge 10^3\) or |$num| \(\le 10^{-3}\).

sigfig0: Overlines last significant 0's and shows non-significant 0's. Equivalent to sigfig($num, $N, barSigZeros=>1, nonSigZeros=>1);

Note: sigfig(0, $N) will output 0.00...0 (a total of $N 0's including the leading 0).


Options:
power=>[-3, 3]: The exponents where scientific notation will be used. [-3, 3] means \(\le 10^{-3}\) or \(\ge 10^3\).
power=>3 is equivalent to power=>[-3, 3]. Default is 3.
To force scientific notation, use power=>0 or power=>1.

barSigZeros: Whether or not to overline the 0 if it is the last significant digit. Default is 0 for sigfig, 1 for sigfig0.

nonSigZeros: Whether or not to include the non-significant 0's before a decimal point. Default is 0 for sigfig, 1 for sigfig0.

For example, sigfig(100.046, $N, options)
$N
default
(no options)
barSigZeros=>1,
nonSigZeros=>0
barSigZeros=>0,
nonSigZeros=>1

barSigZeros=>1,
nonSigZeros=>1

equivalent to
sigfig0(100.046, $N)
7 sig figs \(100.0460\) \(100.0460\)
\(100.0460\) \(100.0460\)
5 sig figs \(100.05\)
\(100.05\) \(100.05\) \(100.05\)
4 sig figs \(100.0\)
\(100.0\) \(100.0\) \(100.0\)
3 sig figs \(1.00 \times 10^2\)
\(10\overline{0}\)
\(1.00 \times 10^2\)
\(10\overline{0}\)
2 sig figs \(1.0 \times 10^2\)
\(1.0 \times 10^2\) \(1.0 \times 10^2\)
\(1\overline{0}0\)
1 sig fig \(1 \times 10^2\) \(1 \times 10^2\) \(100\) \(100\)

TeX=>1: Whether or not to display scientific notations using \(\times 10^?\). For example, 1.230E4 with TeX=>0 will be displayed as "1.230E4", whereas the same with TeX=>1 will be displayed as "\(1.230 \times 10^4\)". Default is 1.
$numdisp = fixdec($num, $N); Shows $num rounded to exactly $N decimal places.
$numdisp = trunc($num, $N); For truncating $num at the $N-th decimal place without rounding. $N can be negative for truncating before the decimal point.

Options:
trailingZeros=>0: Whether or not trailing zeros will be displayed.
end=>"...": Add "..." at the end if $num is truncated.
$numdisp = numWithUncertainty($mean, $uncertainty, $N); Display $mean \(\pm\) $uncertainty, where $uncertainty is rounded to $N significant figures and $mean is rounded to the same number of decimal places as $uncertainty.
$string = frac($a, $b);

  OR

$string = frac($a, $b, factor=>3, TeX=>1, plus=>0, coef=>0);

  OR

$string = frac($a, $b, num=>"x+1", den=>"x+2", brackets=>1);
For displaying fractions $a/$b in reduced form (by default) in LaTeX or in text mode. $a and $b can be integers or decimals. If $a or $b is decimal, frac will find a fraction that equals to the value of $a/$b. If $a or $b is a string, frac will output the fraction in LaTeX form with $a in the numerator or $b in the denominator.

Options:
TeX: Optional. Shows in text mode or in LaTeX mode. If skipped, default is 1.
e.g. frac(1+2, -9) gives "-\dfrac{1}{3}", whereas frac(1+2, -9, TeX=>0) gives "-1/3".

plus: Optional. Whether or not to put a "+" sign in front of a positive fraction. If skipped, default is 0.
e.g. frac(1+2, 9) gives "\dfrac{1}{3}", whereas frac(1+2, -9, plus=>1) gives "+1/3".

coef: Optional. Whether or not to display 1 if fraction = 1 or -1. If skipped, default is 0.
e.g. frac(1+2, -3) gives "-1", whereas frac(1+2, -3, coef=>1) gives "-".

reduce: Optional. Whether or not to reduce the fraction to its simplest form. If skipped, default is 0.
denmax: Optional. The highest denominator used when converting decimals to fractions. If skipped, default is 10000.
tol: Optional. The maximum relative error allowed when converting decimals to fractions. If skipped, default is \(2^{-50}\).
num: Optional. String added to the numerator after reducing. If skipped, default is ''.
den: Optional. String added to the denominator after reducing. If skipped, default is ''.
brackets: Optional. Add brackets to num (and/or den) if the numerator (and/or the denominator) is not 1 after reducing. If skipped, default is 1.

Integer Functions:

$num = gcd($a, $b);

  OR

$num = gcd($a, $b, $c, ...);
Greatest common divisor.

Requires loadMacros("BCITmacros.pl"); if more than 2 inputs.
$num = maxGCD($a, $b, $c, ...); Finds the greatest common divisor of all pairs of inputs and outputs the highest.

Requires loadMacros("BCITmacros.pl");
$num = lcm($a, $b);

  OR

$num = lcm($a, $b, $c, ...);
Least common multiple.

Requires loadMacros("BCITmacros.pl"); if more than 2 inputs.
($num, $den) = reduce($a, $b);
Reduce $a/$b and outputs the reduced numerator and denominator.

Array Functions:

@array = ($num1, $num2, $num3);
Defines an array.
@array = (...some array...);

$first_entry = $array[0];
$second_entry = $array[1];
$last_entry = $array[$#array];
Extracts an entry in @array. Index starts at 0.

$#array: Index of the last entry of @array.
For example, if @array consists of 10 entries, then the value of $#array is 9.

Note: Use $ when calling a single entry.
@subarray = @array[2..6];

  OR

@subarray = @array[2, 3, 6..9];
Extracts part of @array and outputs a new subarray.

Note: Use @ for a part of or the entire array.
@array2 = ($numA, $numB, @array);

  OR

@array2 = ($numA, @array, $numB);
Adds entries in the beginning or at the end of @array and outputs a new array.
splice(@array, $i, $n);

  OR

@
removed_subarray = splice(@array, $i, $n);
Removes $n entires starting at $array[$i] (i.e. the ($i+1)st entry of @array).

Removed entries can be saved in a new array by assigning the output to @removed_subarray.
@array_riffled = riffle(@array); Riffle @array. @array must have an even number of entries.

For example,
 @array1 = (1, 2, 3, 4);
 @array2 = (A, B, C, D);
 @array_riffled = riffle(@array1, @array2);

gives @array_riffled = (1, A, 2, B, 3, C, 4, D).

Requires loadMacros("BCITmacros.pl");
TEXT(join(", ", @array));

  OR

BEGIN_TEXT
\{join(", ", @array)\}
END_TEXT
Displays @array with a comma and a space separating each entry.
@array = (0) x $N;
An array of $N zeros.
@array = (@smaller_array) x $N; An array of $N repetitions of @smaller_array.
@array = ($initial_integer .. $final_integer); A sequence of values from $initial_integer to $final_integer at increments of 1.
@array = linspace($initial, $final, incr=>$increment);

  OR

@array = linspace($initial, $final, num=>$N);
Linearly spaced list of values from $initial to $final
incr=>$increment: at increments of $increment
num=>$N: a total of $N entries in the output

Requires loadMacros("BCITmacros.pl");
@array_reversed = reverse(@array) Reverse the order of the entries in @array.
$num = max(@array);
Maximum value in @array.
$num = min(@array);
Minimum value in @array.
$num = sum(@array);
Sum of all entries in @array.
Requires loadMacros("BCITmacros.pl");
$num = product(@array);
Product of all entries in @array.
Requires loadMacros("BCITmacros.pl");
$num = minDiff(@array);
Minimum difference between any two values in @array.
Requires loadMacros("BCITmacros.pl");
$num = minRelDiff(@array); Minimum relative difference between any two values in @array.
Requires loadMacros("BCITmacros.pl");
$num = maxDiff(@array); Difference between the highest and the lowest values in @array.
Requires loadMacros("BCITmacros.pl");
$num = maxGap(@array);
The maximum difference between two consecutive entries in @array after sorted.
Requires loadMacros("BCITmacros.pl");
$num = countDistinct(@array); Number of distinct values in @array.
Requires loadMacros("BCITmacros.pl");
$num = countPos(@array); Number of positive values among all entries in @array.
Requires loadMacros("BCITmacros.pl");
$num = countNeg(@array); Number of negative values among all entries in @array.
Requires loadMacros("BCITmacros.pl");
$num = countZeros(@array); Number of zeros among all entries in @array.
Requires loadMacros("BCITmacros.pl");
$num = countEqual([@array1], [@array2]);
Number of entries in @array1 that are equal to some entries in $array2.
Requires loadMacros("BCITmacros.pl");
@array_absval = array_abs(@array);
Finds the absolute value of each entry in @array.
Requires loadMacros("BCITmacros.pl");

Two-dimensional Arrays:

@array = ([$num00, $num01], [$num10, $num11], [$num20, $num21], [$num30, $num31]);
Defines a two-dimensional array as an array of arrays (rows).
@array_new = array2DCreate($nRow, $nCol); Creates a $nRow \(\times\) $nCol array of 0.
@array_new = arrayCopy(@array);
Copies all entries of @array to a new array @array_new.

Note:
@array_new = @array copies the references to the rows of @array. If @array changes afterwards, @array_new also changes.

@array_new = arrayCopy(@array) copies the values of each entry in @array. Later changes of @array will not affect @array_new.

Requires loadMacros("BCITmacros.pl");
TEXT(CreateTable([@array]));

  OR

BEGIN_TEXT
\{CreateTable([@array])\}
END_TEXT
Displays all entries in two-dimensinal array in a table.
Requires loadMacros("BCITmacros.pl");
@array2D = array1Dto2D([@array1D], $nRow, $nCol); Converts a 1D array to a 2D array with $nRow rows and $nCol columns.
Requires loadMacros("BCITmacros.pl");
@array1D = arrayFlatten(@array2D); Flattens a multidimensional array to a 1D array.
Requires loadMacros("BCITmacros.pl");
@arrayT = arrayTranspose(@array);
Transposes @array.
Requires loadMacros("BCITmacros.pl");
$array[1][0] = $num; Assign an entry in @array.
$entry = $array[1][0];
Extracts an entry of @array.

Note: row and column indices start at 0.
@row = @{@array[1]};
Extracts a row of @array and outputs a 1-dimensional array.

For example, @{@array[1]} output the 2nd row of @array.
@arrayT = arrayTranspose(@array);
@column =
@{@arrayT[1]};
Extracts a column of @array and outputs a 1-dimensional array.

For example, @{@arrayT[1]} gives the 2nd row of @arrayT, which is the 2nd column of @array.
@subarray = @array[0..2];

  OR

@subarray = @array[0, 2];

  OR

@subarray = @array[0..1, 3];
Extracts rows from @array and outputs a 2-dimensional subarray.

For example:
@array[0..2] outputs the first three rows of @array.
@array[0, 2] outputs the first and third rows of @array.
@array[0..1, 3] outputs the first two and the fourth rows of @array.

To extract columns, transpose the array and extract rows.
@array2 = ([$num0, $num1], @array);

  OR

@array2 =
(@array, [$num0, $num1]);
Adds a row at the top or at the bottom of @array and outputs a new 2-dimensional array.

To add columns, transpose the array and add rows.
splice(@array, $i, $n);

  OR

@
removed_subarray = splice(@array, $i, $n);
Removes $n rows starting at @{@array[$i]} (i.e. the ($i+1)st row of @array).

Removed rows can be saved in a new 2-dimensional array by assigning the output to @removed_subarray.

To remove columns, transpose the array and remove rows.

Sorting:

@array_sorted = num_sort(@array);
Sorts @array in ascending order and outputs a new sorted array.
To sort in descending order, use reverse(num_sort(@array)).

For 2D arrays, the first column is sorted first, then the second column, etc.
@ind = ind_sort(@array); Sorts @array in ascending order and outputs the indices of @array.

For example, if
 @array = (2, 5, 1, 7, 5, 9, 4);
 @ind = ind_sort(@array);
then @ind will have values (2, 0, 6, 1, 4, 3, 5) so that
($array[$ind[0]], $array[$ind[1]], $array[$ind[2]], ..., $array[$ind[6]])
gives @array sorted in ascending order.

$array[$ind[0]] gives the minimum value and $array[$ind[$#ind]] gives the maximum value.

Requires loadMacros("BCITmacros.pl");
@array_sorted = lex_sort(@array); Sorts @array in lexicographic order and outputs a new sorted array.
$str_sorted = str_sort($str) Sorts the characters in $str in lexicographic order and outputs a new sorted string.

Requires loadMacros("BCITmacros.pl");
@array_sorted = merge_sort(&sort_subroutine, @array); Sorts @array using Merge Sort based on the condition given as a subroutine.

&sort_subroutine: a subroutine that defines the comparison performed in Merge Sort. The output must be 0 or 1.
For example, sub{$_[0] < $_[1]} means preceding terms are less than subsequent terms, i.e. in ascending order.

MathObject Matrices:

Requires loadMacros("BCITmacros.pl");

$A = Matrix([[$a11, $a12], [$a21, $a22], [$a31, $a32]]);

  OR

$A = Matrix([@Aarray]);
Creates a MathObject matrix.
@array: a 2D array

Requires Context("Matrix"); for matrix operations.
For more details: https://webwork.maa.org/wiki/Matrix_(MathObject_Class)
@Aarray = $A->value;
Convert the matrix $A to a 2D array @Aarray.
For more details about 2D arrays: Two-dimensional Arrays
$M = matrixCombineCol($A, $B);
$M = matrixCombineRow($A, $B);
Create a matrix $M by combining the columns/rows of matrices $A and $B.
$B = matrixDeleteCol($A, $col1, $col2, ...);
$B = matrixDeleteRow($A, $row1, $row2, ...);
Outputs a matrix $B by taking the matrix $A with columns $col1, $col2, ... or rows $row1, $row2, ... removed.
$Afrac = matrixFraction($A);

  OR

$Afrac = matrixFraction($A, denmax=>10000, tol=>2**-45);
Outputs a matrix $Afrac by taking the matrix $A with all entries converted to MathObject fractions.

denmax: Optional. The highest denominator used when converting decimals to fractions. If skipped, default is 10000.
tol: Optional. The maximum relative error allowed when converting decimals to fractions. If skipped, default is \(2^{-45}\).

Requires Context("Fraction");
$ATeX = matrixIntFactor($A);
Outputs the LaTeX string $ATeX which displays the matrix $A as a product of a fraction and a matrix with integer entries.
$ATeX = augMatrixTeX($A, $col);
Outputs the LaTeX string $ATeX which displays the matrix $A with a vertical line after the $col-th column.
$systemTeX = matrixToSystem($Aaug, ['x', 'y', ...]);
Converts the augmented matrix $Aaug to a linear system and outputs as a LaTeX string $systemTeX.
$boolean = containsParallelRows($A);
Determines whether the matrix $A contains parallel rows.
$X = solveLinearSystem($A, $B);

  OR

@X = solveLinearSystem([@A], [@B]);
Solve a linear system \(A\mathbf{x} = \mathbf{b}\).

For matrices:
$A: \(N \times N\) square matrix
$B: \(N \times 1\) matrix
$X: outputs \(N \times 1\) matrix

For arrays:
@A: \(N \times N\) 2D array
@B: an array with \(N\) entries (1D or 2D)
@X: outputs a 1D array with \(N\) entries.
$Ainv = matrixInverse($A);

  OR

@Ainv = matrixInverse([@A]);
Find the matrix inverse of the matrix $A or the 2D array @A.
$Anew = matrixSwapRO($A, $a, $b);
$Anew = matrixScaleRO($A, $a, $s);
$Anew = matrixAddRO($A, $a, $b, $s);
Applies row operations to the matrix $A and outputs as a matrix $Anew.

matrixSwapRO: \(R_\mathtt{\$a} \leftrightarrow R_\mathtt{\$b}\)
matrixScaleRO: \(\mathtt{$s}\cdot R_\mathtt{\$a} \rightarrow R_\mathtt{\$a}\)
matrixAddRO: \(R_\mathtt{\$a} + \mathtt{$s}\cdot R_\mathtt{\$b} \rightarrow R_\mathtt{\$a}\)
$Areduced = GaussElim($A);

  OR

$Areduced = GaussElim($A, frac=>1, denmax=>10000, fractol=>2**-45, rref=>0, reducePivots=>0);
Reduce the matrix $A by Gaussian Elimination and outputs as a matrix $Areduced.

frac: Optional. Whether or not to converts entries to MathObject fractions if Context("Fraction") is used. If skipped, default is 1.
denmax: Optional. The highest denominator used when converting decimals to fractions. If skipped, default is 10000.
fractol: Optional. The maximum relative error allowed when converting decimals to fractions. If skipped, default is \(2^{-45}\).
rref: Optional. Whether or not to reduce $A to reduced row echelon form. If set to 0, $A will only be reduced to an upper triangular form. If skipped, default is 0.
reducePivots: Optional. Whether or not to reduce pivot entries to 1. No effect if rref=>1. If skipped, default is 0.
tol: Optional. Treats entries within tol as 0. If skipped, default is \(2^{-45} \cdot \|\mathtt{$A}\|_1\).
($pivotCol, $op_ref, $E_ref, $E, $Areduced) = GaussElim($A, options);
$stepsTeX = GaussElimSteps($A, $E_ref, $op_ref, augMatrix=>0, frac=>1);
Outputs a LaTeX string $stepsTeX that shows the Gaussian Elimination step by steps.
$E: The transformation matrix for which $E $A = $Areduced.
$E_ref, $op_ref: References for elementary matrices and row operations.

augMatrix: Optional. Add a vertical line to all matrices after this column. If skipped, default is 0 (no vertical line).
frac: Optional. Display entries as fractions if Context("Fraction") is used. If skipped, default is 1.

Conditional Statements:

if (condition) {
  ...codes...
} elsif (condition) {
  ...codes...
} else {
  ...codes...
}
If ... then... else... statement.
$num = (condition) ? $true_val : $false_val;
If condition is met, $num = $true_val. Otherwise, $num = $false_val.
<, >, <=, >=, ==, !=
Comparison operators for numbers.

Note: MathObjects use fizzy comparisons for non_zero values. To avoid fuzzy comparisons, use 0 on the right side.
For example, if the default relative tolerance is 0.5%, then
Real(1.001) > Real(1) is false (because 1.001 and 1 are within 0.5% and are considered equal).
Real(1.001) - Real(1) > 0 is true because relative tolerance is not used if 0 is on the right side.
eq, ne Comparison operators for strings.
&&, ||
And, Or
!(condition)
Not
$boolean = isNumber($a)
Determines whether $a is a number.
Requires loadMacros("BCITmacros.pl");
$boolean = isInArray($a, [@array]);

  OR

$boolean = isEqualOneOf($a, [@array]);


  OR

$boolean = isEqualOneOf($a, [$b1, $b2, ...]);
Determines whether $a is equal to one of the entries in @array or one of the numbers $b1, $b2, ...

Requires loadMacros("BCITmacros.pl");
$boolean = areDistinctArrays([@array1], [@array2], ...); Check if @array1, @array2, ... are all distinct arrays.
Requires loadMacros("BCITmacros.pl");

Loops:

for (my $i=$initial; $i<$final; $i++) {
  ...codes...
}
For loop, starts at $i=$initial, continues as long as $i<$final
$i++ means $i increases by 1 after each iteration.
If $i needs to increase by 2 after each iteration, use $i+=2.
If $i needs to decrease by 1 after each iteration, use $i--.
foreach my $i (@array) {
  ...codes...
}
Iterates for $i= each entry in @array.
until (condition) {
  ...codes...
};

  OR

do {
  ...codes...
} until (condition);
Do loop, depends on whether the condition is checked before or after each iteration
Can replace until with while for different purposes.

MathObjects:

Requires loadMacros("MathObjects.pl");
For more details: https://webwork.maa.org/wiki/Introduction_to_MathObjects and https://webwork.maa.org/wiki/Specialized_contexts

Context("Numeric");
Defines the MathObjects environment.
Common contexts: https://webwork.maa.org/wiki/Common_Contexts
Specialized contexts: https://webwork.maa.org/wiki/Specialized_contexts
$num = Real($a);
Creates a MathObject with the value $a.
Required for answer checking.
For more details: https://webwork.maa.org/wiki/Real_(MathObject_Class)
$num = $a->value; Generates the Perl value from a Real MathObject $a.
toReal(@array); Change all values in @array to Real MathObjects.
Requires loadMacros("BCITmacros.pl");
toValue(@array); Change all Real MathObjects in @array to Perl values.
Requires loadMacros("BCITmacros.pl");
$func = Formula("2*x + 3");
$x = Formula("x");
Creates a formula.
Variables other than x need to be defined first.
Context()->variables->are(x=>'Real', y=>'Real');
Context()->noreduce('(-x)-y','(-x)+y'); Modifies reduction rules.
For more details: https://webwork.maa.org/wiki/Reduction_rules_for_MathObject_Formulas
$list = List($a, $b);
Creates a list of MathObjects (e.g. the list List(2, 3) consists of two entries, 2 and 3)
This is required for answers that accept a list.
For more details: https://webwork.maa.org/wiki/List_(MathObject_Class)
Context("Interval");

$interval = Interval("[$a, $b]");
$interval = Interval("(-inf, $a] U [$b, inf)");
$interval = Interval("($a, $b) U {$c}");
Creates an interval.
Requires Context("Interval");
For more details: https://webwork.maa.org/wiki/Interval_(MathObject_Class)
$pt = Point($a, $b);
Creates a point.
For more details: https://webwork.maa.org/wiki/Point_(MathObject_Class)
$v = Vector($a, $b);
$v = Vector($a, $b, $c);
Creates a vector.
Requires Context("Vector"); for vector operations.
For more details: https://webwork.maa.org/wiki/Vector_(MathObject_Class)
Context()->lists->set(Vector=>{open=>'(', close=>')'}); Changes the brackets for vectors from the default < > to ( )
Context()->flags->set(ijk=>1);
Context()->constants->set(
  i=>{TeX=>"\hat{\mathbf{i}}"},
  j=>{TeX=>"\hat{\mathbf{j}}"},
  k=>{TeX=>"\hat{\mathbf{k}}"}
);
Displays vectors in ijk form.
Requires Context("Vector");
$A = Matrix([[$a, $b], [$c, $d], [$e, $f]]); Creates a matrix.
Requires Context("Matrix"); for matrix operations.
For more details: https://webwork.maa.org/wiki/Matrix_(MathObject_Class)
Context()->lists->set(Matrix=>{open=>'(', close=>')'}); Changes the brackets for matrices from the default [ ] to ( ).
$z = Complex($Re, $Im); Creates a complex number.
Requires Context("Complex"); for complex operations.
For more details: https://webwork.maa.org/wiki/Complex_(MathObject_Class)
Context("Fraction");

$frac = Fraction($num, $den);
Creates a fraction.
Requires loadMacros("contextFraction.pl",);
Requires Context("Fraction");
For more details: https://webwork.maa.org/wiki/FractionAnswer1
toFraction(@array); Change all entries in @array to fractions.
Requires loadMacros("BCITmacros.pl");
Requires loadMacros("contextFraction.pl",);
Requires Context("Fraction");

MathObject Context Settings:

For more details: https://webwork.maa.org/wiki/Introduction_to_Contexts and https://webwork.maa.org/wiki/Modifying_Contexts_(advanced)

Context()->flags->set(tolType=>"relative", tolerance=>5E-3); Changes the default tolerance for the current problem.
For other flags: https://webwork.maa.org/wiki/Context_flags
Context()->flags->set(zeroLevel=>1E-30, zeroLevelTol=>1E-30); Change the smallest value for relative tolerance and the smallest value before setting to 0.

zeroLevel: Numbers smaller than zeroLevel will only be compared using absolute tolerance.
zeroLeveltol: The absolute tolerance when comparing numbers smaller than zeroLevel. This is also the smallest number treated as a non-zero value.
Context()->{format}{number} = "%0.2f";
Changes the number format. By default, 6 significant digits are displayed for MathObjects (default format: "%g")

"%0.nf": n decimal places (e.g. "%0.3f" means 3 decimal places)
"%0.ne": n decimal places in scientific notation (e.g. "%0.3e" means 3 decimal places, i.e. 4 significant digits)
"%0.ng": n significant digits (e.g. "%0.3g" means 3 significant digits)

For more details: https://perldoc.perl.org/functions/sprintf
Context()->variables->are(x=>'Real', y=>'Real');

  OR

Context()->variables->are(x=>['Real', limits=>[1,2]], y=>['Real', limits=>[3,4]]);
Defines all variables (and their ranges) that will be used in the current problem (Default: x).
Context()->variables->set(x=>{limits=>[1,2]}, y=>{limits=>[3,4]}); Set the ranges of the variables when comparing formulas (e.g. in answer checkers).
Context()->strings->add(und=>{}, undefined=>{alias=>"und"}); Defines new strings so that when students enter these strings the system will not complain.
Built-in strings: none, dne, inf
Context()->constants->add(a=>Real("exp(1)"), m=>Real(2)); Adds constants to the current problem.
Built-in constants: pi
Context()->constants->remove('pi'); Remove pi so that students cannot use pi in the answers.
Available options: 'pi', 'e', 'i', 'j', 'k', '_0'
Context()->parens->remove('|'); Removes | | so that students cannot enter |a| as an answer (student will need to calculate absolute values or vector norms).
Available options: '(', '[', '{', '<', '|'
Context()->operators->undefine('><');
Removes >< so that students cannot enter their answer with the cross product sign (students will need to calculate the cross product).
Available options: ',', '+', '-', '*', ' *','* ', ' ', '/', ' /', '/ ', '//', '**', '^', '!', 'u+', 'fn', '.', '><', '_', 'U'
To re-enable a removed operator, use Context()->operators->redefine(...);
Context()->functions->disable('All');
Disable all functions for student inputs (i.e. no sin, ln, etc...).
To re-enable a removed function, use Context()->functions->enable(...);
For more details: https://webwork.maa.org/wiki/DisableFunctions
Parser::Number::NoDecimals(); Does not accept numbers with decimal points.

Standard Answer Checkers:

ANS(Real($a)->cmp(tolType=>'relative', tolerance=>5E-3));

For lists:
ANS(List(Real($a), Real($b))->cmp(
    ordered=>0,
    showHints=>0,
    showLengthHints=>0,
    showTypeWarnings=>0,
    partialCredit=>0,
    tolType=>'relative',
    tolerance=>5E-3,
));
ANS(List(Real($a))->cmp(...));
ANS(List("none")->cmp(typeMatch=>'Value::Real'));
For numerical answers. Will accept expressions like 1+2*3 in answers.
tolType: relative or absolute

List: Allows students to enter more than one value as a comma-separated list.
If the correct answer is an empty list, use "none". No error messages will be displayed if student enters a non-empty list.
ordered: Whether or not the order of the entries in the list is important.
showHints: Whether or not to tell student which entry is incorrect.
showLengthHints: Whether or not to tell student if they entered an incorrect number of entries.
showTypeWarnings: Tells student if their answer is of an incorrect type (e.g if students entered a point when numbers are expected)
partialCredit: Whether or not to give partial credit if part of student's answer is correct.
Context("LimitedNumeric");
ANS(
Real($a)->cmp(tolType=>'relative', tolerance=>5E-3));

For lists:
Context("LimitedNumeric")->operators->redefine(",");
ANS(List(Real($a), Real($b))->cmp(
    ordered=>0,
    showHints=>0,
    showLengthHints=>0,
    showTypeWarnings=>0,
    partialCredit=>0,
    tolType=>'relative',
    tolerance=>5E-3,
));
ANS(List(Real($a))->cmp(...));
ANS(List("none")->cmp());
For numerical answers. Do not accept operators in answers.
Only works if $ans is defined after Context("LimitedNumeric").

For integer answers, use
Context("LimitedNumeric");
Parser::Number::NoDecimals();
loadMacros("parserNumberWithUnits.pl");

BEGIN_TEXT
\{helpLink('unit')\} or \{helpLink('units')\}
END_TEXT

ANS(
NumberWithUnits(Real($a), "cm/s")->cmp(tolType=>'relative', tolerance=>5E-3));

  OR

$newUnits = ['apple', {name=>'apples', conversion=>{factor=>1, apple=>1}}];
ANS(NumberWithUnits(Real($a), "apples", {newUnit=>$newUnits})->cmp(tolType=>'relative', tolerance=>5E-3));
For numerical answers with unit.
\{helpLink('unit')\}
or \{helpLink('units')\}: Provides help with units in the question.
See https://mathwebwork.bcit.ca/webwork2_files/helpFiles/Units.html for commonly used units.

newUnit: For adding or modifying units. See https://github.com/openwebwork/pg/blob/main/macros/parserNumberWithUnits.pl for more details.
To disable frequency units, use {newUnit=>$noFrequencyUnits}. To disable angle units, use {newUnit=>$noAngleUnits}.

For periodic answers, see Additional Answer Checkers below.

Requires loadMacros("parserNumberWithUnits.pl",);
loadMacros("contextFraction.pl");

Context("Fraction");
$ans = Fraction($a, $b);  # defined before answer checker

Context("LimitedFraction")->flags->set(requirePureFractions=>0, showMixedNumbers=>0);
ANS(
Compute($ans)->cmp(studentsMustReduceFractions=>0, showFractionReduceWarnings=>0));
Only fractions or integers are allowed in the answer.
requirePureFractions: Whether or not mixed numbers are accepted in answers.
showMixedNumbers: Show mixed numbers or improper fraction in case if the fraction > 1.

studentsMustReduceFractions: Whether or not unreduced fractions are accepted.
showFractionReduceWarnings: Whether or not a warning is given if the fraction is not fully reduced.

Requires loadMacros("contextFraction.pl",);
Requires Context("Fraction");  or  Context("LimitedFraction");
For more details: https://webwork.maa.org/wiki/FractionAnswer1
Context("Complex");
$ans = Complex($a, $b);  # defined before answer checker

loadMacros("contextLimitedComplex.pl",);
Context("LimitedComplex-strict");

ANS(Compute($ans)->cmp(tolType=>'relative', tolerance=>5E-3));
For complex numbers in answers. Will accept expressions like 1+2i or 2*e^(4i) in answers.

For answers specifically requiring cartesian or polar form, use Context("LimitedComplex-cartesian-strict"); or Context("LimitedComplex-polar-strict");
$ans = Formula("...");
$ans->{limits} = [$a, $b];
$ans->{test_at} = [[5.00001], [100], [10000]]; 

ANS($ans->cmp(
    tolType=>'relative',
    tolerance=>5E-3,
    zeroLevel=>.1,
    zeroLevelTol=>.1*5E-3,
    checkUndefinedPoints=>1,
    showDomainErrors=>0,
    showTestPointErrors=>0,
#    diagnostics=>($permissionLevel>0),
));

For lists:
ANS(List(Formula("..."), Formula("..."))->cmp(...));
ANS(List(Formula("..."))->cmp(...));
ANS(List("none")->cmp());  # do not include typeMatch
For formula answers.
limits: Domain for answer checkers.
test_at: Ensure that these additional test points are also checked in answer checkers.

zeroLevel: Only absolute tolerance is used below this value (if the value of the function is too small at some test points, relative tolerance can becomes too strict).
zeroLevelTol: Absolute tolerance level below zeroLevel.
checkUndefinedPoints: Whether or not to check if the correct formula is undefined at a point, student's answer is also undefined at the same point.
showDomainErrors: Whether or not a warning is given if the domain of student's answer has a different domain than the correct formula.
showTestPointErrors: Whether or not a warning is given if there are problems evaluating student's answer (e.g. if student enters sqrt(-1-x^2)).
diagnostics: For diagnostic use only. It compares student's answer with the correct formula.

For details on lists, refer to numerical answers given above.
Context()->variables->are(s=>'Real', T=>'Real', u=>'Real');
$ans = Formula("s*T*u");
$ans->{limits} = [[$Ta, $Tb], [$sa, $sb], [$ua, $ub]];
For multivariable formulas.
limits: Intervals are listed in this order: upper case in alphabetical order first, then lower case in alphabetical order.

Other options for formulas listed above can also be used here.
loadMacros("parserFormulaUpToConstant.pl");

$ans1 = Formula("sin(x)");
ANS($ans1->cmp(upToConstant=>1, ...));

$ans2 = FormulaUpToConstant("sin(x) + C");
ANS($ans2->cmp(...));
For formulas up to a constant.
upToConstant: Any answer only differ from the correct formula by a constant is accepted. E.g. sin(x) - 1, sin(x) + 5 are all accepted.

FormulaUpToConstant: This requires a +C (or +c or +k etc) at the end of student's answer.
FormulaUpToConstant requires loadMacros("parserFormulaUpToConstant.pl");

Other options for formulas listed above can also be used in place of "...".
For more details: https://webwork.maa.org/wiki/FormulasToConstants
loadMacros("parserImplicitPlane.pl");

Context("ImplicitPlane");  # right before answer checkers
Context()->variables->are(x=>'Real',y=>'Real');
$ans = ImplicitPlane("x+2y=3");
ANS($ans->cmp());
For linear equations (2 or more variables) in answers.

Requires loadMacros("parserImplicitPlane.pl");
Requires Context("ImplicitPlane");
For more details: https://webwork.maa.org/wiki/ImplicitPlane, https://webwork.maa.org/wiki/ImplicitPlane1
loadMacros("parserImplicitEquation.pl");

Context("ImplicitEquation");  # right before answer checkers
Context()->variables->are(x=>'Real', y=>'Real');

$lhs = Formula("x^2/4 + y^2/9");
$ans = ImplicitEquation("$lhs = 1", tolerance=>0.001, limits=>[[-2,2],[-3,3]], solutions=>[[2,3], [-2,3], [-2,-3], [2,-3]]);
ANS($ans->cmp(showEqualErrors=>0));
For non-linear equations (2 or more variables) in answers.
tolerance: Absolute tolerance for answer checking
limits: The range of x and y (in this example, x in [-2,2], y in [-3,3])
solutions: Extra solutions (if you wish to include) for answer checking (in this example, (x,y) = (2,3), (-2,3), (-2,-3) and (2,-3)).

showEqualErrors: Whether or not to display error messages.

Requires loadMacros("parserImplicitEquation.pl");
Requires Context("ImplicitEquation");
For more details: https://webwork.maa.org/wiki/EquationEvaluators
BEGIN_TEXT
\{helpLink('interval notation')\}
END_TEXT

Context("Interval");  #right before answer checkers

$ans = Interval("[1, 2] U (3,inf)");
ANS($ans->cmp(
   
tolType=>'relative',
    tolerance=>1E-14,
    requireParenMatch=>1,
    showEndpointHints=>0,
    showEndTypeHints=>0,
    showHints=>0,
    showLengthHints=>0,
    partialCredit=>0,
));
For interval answers.
\{helpLink('interval notation')\}: Provides help with interval notation in the question.

requireParenMatch: Whether or not to require the open/closed status of the endpoints to match with the correct answer.
showEndpointHints: Whether or not to tell student if their endpoints are incorrect.
showEndTypeHints: Whether or not to tell student if their brackets are incorrect.
showHints: Whether or not to tell student which part of their answer is incorrect (for unions).
showLengthHints: Whether or not to tell student if there are more intervals in the correct answer.
partialCredit: Whether or not to give partial credit to a partially correct answer.
Context("Point");

$ans = Point(1, 2);

BEGIN_TEXT
\{ans_rule(20)\}
or \{$ans->ans_array\}
END_TEXT

loadMacros("contextLimitedPoint.pl");
Context("LimitedPoint");
ANS(Compute($ans)->cmp(
    tolType=>'relative',
    tolerance=>5E-3,
    showDimensionHints=>0,
    showCoordinateHints=>0,
    showTypeWarnings=>1,
));

For lists:
$ans = List(Point($x1,$y1), Point($x2,$y2));
ANS($ans->cmp(ordered=>0, showHints=>0, showLengthHints=>0, showTypeWarnings=>0, partialCredit=>0, ...));
For points.
$ans->ans_array: Gives separate answer box for each coordinate of $ans.

showDimensionHints: Whether or not to tell student about incorrect number of coordinates.
showCoordinateHints: Whether or not to tell student about which coordinate is incorrect.
showTypeWarnings: Whether or not to tell student if their answer is not a point.

For details on lists, refer to numerical answers given above.
Context("Vector");

$ans = Vector(1, 2);

BEGIN_TEXT
\{ans_rule(20)\}
or \{$ans->ans_array\}
END_TEXT

loadMacros("contextLimitedVector.pl");
Context("LimitedVector");
ANS(Compute($ans)->cmp(
    tolType=>'relative',
    tolerance=>5E-3,
    promotePoints=>1,
    parallel=>0,
    sameDirection=>0,
    showDimensionHints=>0,
    showCoordinateHints=>0,
    showTypeWarnings=>1,
));

For lists:
$ans = List(Vector($x1,$y1), Vector($x2,$y2));
ANS($ans->cmp(ordered=>0, showHints=>0, showLengthHints=>0, showTypeWarnings=>0, partialCredit=>0, ...));
For vectors.
$ans->ans_array: Gives separate answer box for each coordinate of $ans.

promotePoints: Whether or not to allow student to enter a point to represent a vector (i.e. use ( ) rather than < >).
parallel: Whether or not to accept all non-zero vector parallel to the correct answer.
sameDirection: Whether or not to accept all vectors in the same direction as the correct answer.
showDimensionHints: Whether or not to tell student about incorrect number of coordinates.
showCoordinateHints: Whether or not to tell student about which coordinate is incorrect.
showTypeWarnings: Whether or not to tell student if their answer is not a vector.
Context("Matrix");

$ans = Matrix([[1, 2], [3, 4], [5, 6]]);

BEGIN_TEXT
Enter your answer using \{helpLink('matrix notation')\}.
\{ans_rule(50)\}
or \{ans_box(2, 20)\} or
\{$ans->ans_array\}
END_TEXT

ANS(Compute($ans)->cmp(
    tolType=>'relative',
    tolerance=>5E-12,
    showDimensionHints=>0,
    showTypeWarnings=>0,
));
For matrices.
\{helpLink('matrix notation')\}: Provides help with matrix notation in the question.
$ans->ans_array: Gives separate answer box for each coordinate of $ans.

showDimensionHints: Whether or not to tell student if the dimension of their matrix is incorrect.
showTypeWarnings: Whether or not to tell student if their answer is not a matrix.
loadMacros("PGessaymacros.pl");

BEGIN_TEXT
\{essay_box()\}
END_TEXT

ANS(essay_cmp());
For essay questions.

Requires loadMacros("PGessaymacros.pl");

loadMacros("parserPopUp.pl");

$popup = PopUp(["?", "one", "two", "three"], "three");

BEGIN_TEXT
\{$popup->menu()\}
END_TEXT

ANS($popup->cmp());
For pop-up lists.
PopUp: Choices are given in square brackets. The correct answer is the last entry outside the brackets.

Requires loadMacros("parserPopUp.pl");
For more details: https://webwork.maa.org/wiki/PopUpLists

Additional Answer Checkers:

Requires loadMacros("BCITmacros.pl");

ANS(sigfig_cmp(Real($a), $N));

  OR

ANS(sigfig_cmp(Real($a), $N, requireSciNot=>0, tolerance=>0));
For answers requiring exactly $N significant figures.

requireSciNot: Optional. Whether or not scientific notation is required/accepted. 1: required, 0: optional, -1: not accepted. If skipped, default is 0.
tolerance: Optional. The tolerance at the last significant digit. For example, tolerance=>1 means the last significant digit in the answer can be off by 1. If skipped, the default is 0.
ANS(fixdec_cmp(Real($a), $N));

  OR

ANS(fixdec_cmp(Real($a), $N, tolerance=>0));
For answers requiring exactly $N decimal places.

tolerance: Optional. The tolerance at the last digit. For example, tolerance=>1 means the last digit in the answer can be off by 1. If skipped, the default is 0.
loadMacros("contextFraction.pl");
Context("LimitedFraction")->flags->set(showMixedNumbers=>0, reduceFractions=>0);
Context()->operators->redefine(",");
$ans1 = Fraction(1, 2)->reduce;
$ans2 = Fraction(3, 4)->reduce;

ANS(List($ans1, $ans2)->cmp(   
    ordered=>0,
    showHints=>0,
    showLengthHints=>0,
    partialCredit=>0,
    showFractionReductionWarnings=>1,
    checker=>~~&chkReduceFractionsInList
));
For list of fraction. Require students to reduce all fractions.

ordered: Whether or not the order of the entries in the list is important.
showHints: Whether or not to tell student which entry is incorrect.
showLengthHints: Whether or not to tell student if they entered an incorrect number of entries.
partialCredit: Whether or not to give partial credit if part of student's answer is correct.
showFractionReductionWarning: Whether or not to tell students if they entered unreduced fractions.

Requires loadMacros("contextFraction.pl");
Requires Context("Fraction");  or  Context("LimitedFraction");
$ans = Compute("2*(x+1)^2*(2*x+3)");

ANS($ans->cmp(
    checkSigns=>0,
    roundBrackets=>0,
    noDecimals=>0,
    noFractions=>0,
    checker=>~~&chkFactoredForm
));
For answers factored in exactly the same form as $ans.
Only positive integer powers are allowed.

checkSigns: Optional. Whether or not to check the sign of each factor. If skipped, default is 0.
roundBrackets: Optional. Whether or not to require students to use round brackets only (instead of square or curly brackets). If skipped, default is 0.
noDecimals: Optional. Whether or not to restrict students from entering decimals. If skipped, default is 0.
noFractions: Optional. Whether or not to restrict students from entering fractions. If skipped, default is 0.
loadMacros("parserNumberWithUnits.pl");

BEGIN_TEXT
\{helpLink('unit')\} or \{helpLink('units')\}
END_TEXT

$ans = NumberWithUnits(Real($PI), "rad", {newUnit=>$noFrequencyUnits})->with(period=>$PI/2);

ANS(NumberWithUnits($ans->cmp(tolType=>'relative', tolerance=>5E-3, checker=>~~&chkNumberWithUnits));
For numerical answers with unit.
\{helpLink('unit')\}
or \{helpLink('units')\}: Provides help with units in the question.
See https://mathwebwork.bcit.ca/webwork2_files/helpFiles/Units.html for commonly used units.

newUnit: For adding or modifying units. To disable frequency units, use {newUnit=>$noFrequencyUnits}. To disable angle units, use {newUnit=>$noAngleUnits}. To allow rad only, use {newUnit=>$onlyRad}.
See https://github.com/openwebwork/pg/blob/main/macros/parserNumberWithUnits.pl for more details.

period: For periodic answers. The period is adjusted if students use different units.

Requires loadMacros("parserNumberWithUnits.pl");
loadMacros("parserMultiAnswer.pl");

$multians = MultiAnswer(Real($ans1), Real($ans2));

  OR

$multians = MultiAnswer(Real($ans1), Real($ans2))->with(
    singleResult=>0,
    allowBlankAnswers=>0,
    checkTypes=>1,
);

BEGIN_TEXT
\{$multians->ans_rule(20)\}
\{$multians->ans_rule(20)\}
END_TEXT

ANS($multians->cmp(checker=>chkMultiAnswer()));

  OR

ANS($multians->cmp(checker=>chkMultiAnswer(
    tolType=>'relative',
    tolerance=>5E-3,
    partialCredit=>0,
   
showAnsHints=>0,
    ordered=>1,
    incorrectMessage=>"",
)));
For 2 or more linked answer boxes.
singleResult: Optional. Whether or not to combine all answer boxes into one single answer. If skipped, default is 0.
allowBlankAnswers: Optional. Whether or not answers are checked only if all answer boxes are filled. If skipped, default is 1.
checkTypes: Optional. Whether or not answer types are checked first because the answers are checked. If skipped, default is 1.

chkMultiAnswer: The answer checker that checks whether all student answers are equal to the correct answers.
partialCredit: Optional. Whether or not partial credits are granted if only some of the answers are correct. If skipped, default is 0.
showAnsHints: Optional. Whether or not to indicate which answers are correct and which are not. Only enabled if singleResult=>1 and partialCredit=>1. If skipped, default is 0.
ordered: Optional: Whether students' answers should be in the same order as the correct answers. If skipped, default is 1.
incorrectMessage: The message displayed if students' answers are incorrect. Only enabled if partialCredit=>0.

Other custom answer checkers can be used. For more details, https://webwork.maa.org/wiki/MultiAnswerProblems.
loadMacros("parserMultiAnswer.pl");

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

$multians = MultiAnswer(Vector(1,1,1), Vector(1,2,3), Vector(0,0,0))->with(singleResult=>0, checkTypes=>0);


BEGIN_TEXT
\{$multians->ans_rule(20)\}
\{$multians->ans_rule(20)\}
END_TEXT

ANS($multians->cmp(checker=>chkBasis()));

  OR

ANS($multians->cmp(checker=>chkBasis(
    partialCredit=>0,
    orthogonal=>0,
    orthonormal=>0,
    showHints=>0,
    errorMessage=>"",
    tol=>1E-3,
)));
Check if student's vectors span the correct vector space. Use zero vectors if more answer boxes are provided than the number of basis vectors. Students can enter "none" in replacement of zero vectors. Zero vectors will not be checked unless all non-zero vectors are correct.

partialCredit: Optional. Whether or not partial credits are granted if only some of the answers are correct. Zero vectors will not be graded unless all non-zero vectors are correct. If skipped, default is 0.
orthogonal: Optional. Whether or not to require students to enter an orthogonal set. If skipped, default is 0.
orthonormal: Optional. Whether or not to require students to enter an orthonormal set. This overrides orthogonal. If skipped, default is 0.
showHints: Optional. Whether or not to provide hints if some answers are not in the correct vector space or are in the span of earlier answers. If skipped, default is 0.
errorMessage: Optional. The message displayed if students' answers are incorrect. Only enable if partialCredit=>0.
tol: Optional. The maximum relative tolerance to consider student's vectors are in the correct vector space. If skipped, default is 1E-3.
minnorm: Optional. The minimum norm for a vector to be considered non-zero. If skipped, default is 1E-14.

Answer Checker Post Filters:

Requires loadMacros("BCITmacros.pl");

ANS($ans->cmp()->withPostFilter(changeMessage("Message 1"=>"New message 1", "Message 2"=>"New message 2")));

  OR

ANS($ans->cmp()->withPostFilter(changeMessageContaining("Phrase 1"=>"New message 1", "Phrase 2"=>"New message 2")));
Changes the output messages after answer submission.

changeMessage("Message 1"=>"New message 1", "Message 2"=>"New message 2")
Replaces "Message 1" with "New message 1", etc

changeMessageContaining("Phrase 1"=>"New message 1", "Phrase 2"=>"New message 2")
Replaces any message containing "Phrase 1" with a new message "new message 1", etc.
ANS($ans->cmp(...)->withPostFilter(previewCustom(sub {"x =" . $_[0]})));

  OR

$multians = MultiAnswer($ans1, $ans2)->with(singleResult=>1);

ANS(($multians->cmp(...))[0]->withPostFilter(previewCustom(sub {$_[0] . "< x \le" . $_[1]})));

Change the preview format after answer submission.

Use $_[0] represents student's answer. For MultiAnswer, use $_[0], $_[1], $_[2], etc.

For example,
ANS($ans->cmp(...)->withPostFilter(previewCustom(sub {"x =" . $_[0]})));
If student's entered 2 in the answer box, the preview will display \(x = 2\) after submission.
ANS($ans->cmp(...,
    conditions=>sub {$_ + 5 < 0 || $_ - 5 > 0},
    conditionHints=>"Make sure all your answers are within \([-5, 5]\)"
)->withPostFilter(~~&conditionHints));


For multiple conditions:

ANS($ans->cmp(...,
    conditions=>[sub {$_ + 5 < 0}, sub {$_ - 5 > 0}],
    conditionHints=>["Too low", "Too high"],
)->withPostFilter(~~&conditionHints));
Displays a messages if student's answer satisfies some conditions or not.

conditions: A list of subroutines that check whether each of the desired conditions is satisfied. The variable $_ represents student's answer.

Note: Any comparison with a non-zero value on the right hand side is a fuzzy comparison.
For example, the condition "$_ > 5" is true only if $_ > 5 and |$_ - 5| > tol, where tol is the tolerance level set in the context.
The condition "$_ - 5 > 0" is true whenever $_ > 5. When the right side is 0, the comparison will use zeroLevel (1E-14 by default) as the absolute tolerance.

Note: For numberWithUnits, do not include units in the conditions.

conditionHints: The messages to display if the corresponding conditions are met.
singleHint
: Optional. Whether or not to display only one message even if multiple conditions are met. If skipped, default is 1.
ANS($ans->cmp(
    tolType=>"relative",
    tolerance=>5E-5,
    tolHint=>5E-3,
    tolHintMessage=>"Close but not accurate enough",
    partialCredit=>0.5,
)->withPostFilter(~~&realAccuracyHint));
Display a message if student's answer is close but not accuracy enough.

tolHint: The tolerance level that triggers the hint.
tolHintMessage: The message to display if the error of student's answer is within tolHint but is greater than tolerance.
partialCredit: Partial credit if student's answer is accurate within tolHint but not tolerance.

Multiple Choice Problems:

Requires loadMacros("BCITmacros.pl");

$mc = MultipleChoice(
    ques=>["Ques 1", "Ques 2", "Ques 3"],
    ans=>["Ans for Ques 1", "Ans for Ques 2", "Ans for Ques 3", "Extra choice 1", "Extra choice 2"],
    ansLast=>["All of the above", "None of the above"],
    popupChoices=>"ABC",
    sol=>["Sol 1", "Sol 2", "Sol 3"],
    numQues=>2,
    shuffleQues=>1,
    showQuesNum=>0,
    numAns=>4,
    border=>0,
    numQuesInRow=>0,
    numAnsInRow=>0,
    quesInTeX=>0,
    ansInTeX=>0,
    showQuesNumInSol=>1,
    showQuesInSol=>1,
    showAnsInSol=>1,
    width=>"90%",
    colwidth=>["60%", "40%"],
    colsep=>200,
    hpad=>20,
    colwidthtex=>["0.5\linewidth", "0.3\linewidth"],
    colseptex=>50,
    hpadtex=>6,
);
For multiple choice, multiple select or matching problems.

ques: List of questions.
ans: Corresponding answers to ques. Include extra choices at the end.
ansLast: Optional. List of choices displayed exactly in this order at the end. Choices can be shuffled by using [].
For example, ansLast=>["Choice 1", ["Choice 2a", "Choice 2b"], ["Other choice 3a", "Choice 3b"], "Last choice"] gives "Choice 1" as the first choice, then "Choice 2a" and "Choice 2b" shuffled, then "Choice 3a" and "Choice 3b" shuffled, then "Last choice" as the last choice.
For example, ansLast=>["Choice 1", [["Choice 2a", "Choice 2b"], ["Other choice 3a", "Choice 3b"]], "Last choice"] gives "Choice 1" as the first choice, then the groups ["Choice 2a", "Choice 2b"] and ["Choice 3a", "Choice 3b"] shuffled, the the last choice.

popupChoices: Optional. Specify the choices in popup lists. By default, "A", "B", "C", etc are in popup lists. Set popupChoices=>"ans" to use entries in ans and ansLast as choices. To specify custom choices, set popupChoices=>["Popup choice 1", "Popup choice 2", ...].

sol: Optional. The corresponding solutions to ques.
numQues: Optional. Number of questions picked from ques. If skipped, all questions from ques will be used.
shuffleQues: Optional. Whether or not to shuffle the questions. If skipped, default is 1.
showQuesNum: Optional. Whether or not to display question numbers. If skipped, default is 0.
numAns: Optional. Number of answers displayed. All correct answers and all entries from ansLast will be used regardless of numAns.
border: Optional. For questions and/or answers displayed in 2 columns.

numQuesInRow: Optional. Number of questions in a row if the questions are displayed in a table. Enter 0 to display all questions in one row. If skipped, default is 0.
numAnsInRow: Optional. Number of answers in a row if the answers are displayed in a table. Enter 0 to display all answers in one row. If skipped, default is 0.

quesInTeX: Optional. Add "\(" and "\)" to each of the questions. If skipped, default is 0.
ansInTeX: Optional. Add "\(" and "\)" to each of the answer choices. If skipped, default is 0.

showQuesNumInSol: Optional: Displays the question number in the solution.
showQuesInSol: Optional. Displays the question in the solution.
showAnsInSol: Optional. Displays the correct answer in the solution.

width: Optional. Width when questions and/or answers are displayed in 2 columns. If skipped, default is "100%". Only affects HTML.
colwidth: Optional. Width of each column when questions and/or answers are displayed in 2 columns. Only affects HTML.
colsep: Optional. Separation in pixels between the columns when questions and/or answers are displayed in 2 columns. For $mc->{qaInColumns} and $mc->{ansInColumns}. Only affects HTML. If skipped, default is 250.
hpad: Optional. Horizontal padding when the questions and the answers are displayed in tables. For $mc->{quesInTable} and $mc->{ansInTable}. Only affects HTML. If skipped, default is 20.

colwidthtex: Optional. Width of each column when questions and/or answers are displayed in 2 columns. Only affects printouts.
colseptex: Optional. Separation in pixels between the columns when questions and/or answers are displayed in 2 columns. For $mc->{qaInColumns} and $mc->{ansInColumns}. Only affects printouts. If skipped, default is 250.
hpadtex: Optional. Horizontal padding when the questions and the answers are displayed in tables. For $mc->{quesInTable} and $mc->{ansInTable}. Only affects printouts. If skipped, default is 6.
$mc = MultipleChoice(
    ques=>["\(2 + 2 = ?\)"],
    ans=>["4", "0", "1", "2", "3"]
);

BEGIN_TEXT
$mc->{quesText}
$PAR
$mc->{ansText}
END_TEXT

  OR

BEGIN_TEXT
$mc->{ques}[0]
$PAR
Correct answer: $mc->{popup}[0]
$PAR
$mc->{ansText}
END_TEXT

ANS(str_cmp($mc->{correct}));
Multiple choice problem

$mc: Contains all information about the multiple choice question.

$mc->{quesText}: The question from "ques" with a pop-up box on the left.
$mc->{ansText}: The choices shuffled from "ans". Use $mc->{ansInColumns} to display the choices in two columns.

$mc->{ques}[0]: The question from "ques".
$mc->{popup}[0]: The pop-up box.

$mc->{correct}: The correct answers.
$mc = MultipleChoice(
    ques=>["\(2 + 2 = 4\)", "\(2 - 2 = 4\)", "\(2 \times 2 = 4\)", "\(2 \div 2 = 4\)"],
    ans=>["True", "False", "True", "False"],
    sol=>["\(2 + 2 = 4 \;\Rightarrow\;\) True", "\(2 - 2 = 0 \;\Rightarrow\;\) False", "\(2 \times 2 = 4 \;\Rightarrow\;\) True", "\(2 \div 2 = 1 \;\Rightarrow\;\) False"],
    popupChoices=>"ans"
);

BEGIN_TEXT
Which of the following is true?
$PAR
$mc->{quesText}
END_TEXT

BEGIN_SOLUTION
$mc->{solText}
END_SOLUTION
 
ANS(str_cmp($mc->{correct}));
Multiple Select problem

$mc->{solText}: The solutions to all questions.

To display individual solutions, use $mc->{sol}[0], $mc->{sol}[1], etc.
$mc = MultipleChoice(
    ques=>["\(2 + 2\)", "\(2 - 2\)", "\(2 \times 2\)", "\(2 \div 2\)"],
    ans=>["4", "0", "4", "1", "2", "3"],
    sol=>"\(2 + 2 = 4\)", "\(2 - 2 = 0\)", "\(2 \times 2 = 4\)", "\(2 \div 2 = 1\)"]
);

BEGIN_TEXT
Match each of the following expressions with their results.
$PAR
$mc->{qaInColumns}
END_TEXT

BEGIN_SOLUTION
$mc->{solText}
END_SOLUTION

ANS(str_cmp($mc->{correct}));
Matching problem

$mc->{qaInColumns}: Question on the left and choice on the right.
@ques = (... some graphs from initGraph ...)
@ans = (... some graphs from initGraph ...)

  OR

@ques = (displayImage("fig1.jpg"), displayImage("fig2.jpg"), ...)
@ans = (displayImage("ansfig1.jpg"), displayImage("ansfig2.jpg"), ...)

$mc = MultipleChoice(ques=>[@ques], ans=>[@ans]);

BEGIN_TEXT
Match the following expressions with their results.
$PAR
$mc->{ansInTable}
$PAR
$mc->{quesInTable}
END_TEXT

ANS(str_cmp($mc->{correct}));
Matching graphs or diagrams

$mc->{ansInTable}: Choices in a table with their corresponding letters below the choices.
$mc->{quesInTable}: Questions in a table with popup boxes below the questions.

Problem Graders:

install_problem_grader(~~&avg_problem_grader);
$showPartialCorrectAnswers = 1;
Default grader. Not needed to include in problems.
Same weighting for all answer boxes.

$showPartialCorrectAnswers: Whether or not to tell students which answers are correct and which are not.
install_problem_grader(~~&std_problem_grader);
$showPartialCorrectAnswers = 0;
Full mark only if all answers are correct. 0 marks otherwise.

$showPartialCorrectAnswers = 0: useful for a few True/False problems or multiple-choice problems so students won't know which answer is incorrect. No effect for instructors.

An example: https://webwork.maa.org/wiki/WeightedGrader
loadMacros("PGgraders.pl");

install_problem_grader(~~&custom_problem_grader_fluid);
$ENV{'grader_numright'} = [3, 5];
$ENV{'grader_scores'} = [0.5, 1];
$ENV{'grader_message'} = "You can earn 50$PERCENT partial credit for 3 - 4 correct answers.";
$showPartialCorrectAnswers = 0;
Gives marks based on the number of correct answers.

In this case, 50% if 3 answers are correct, and 100% if 5 (all) answers are correct.

$showPartialCorrectAnswers = 0: useful for a few True/False problems or multiple-choice problems so students won't know which answer is incorrect. No effect for instructors.

An example: https://webwork.maa.org/wiki/ManyMultipleChoice1
loadMacros("PGgraders.pl");

install_problem_grader(~~&full_partial_grader);
$showPartialCorrectAnswers = 1;
100% if the final answer is correct regardless of other answers. Otherwise, a partial mark will be given.

An example: https://webwork.maa.org/wiki/WeightedGrader
loadMacros("weightedGrader.pl",);
install_weighted_grader();

WEIGHTED_ANS($ans->cmp(), 40);
WEIGHTED_ANS($ans->cmp(), 40);
WEIGHTED_ANS($ans->cmp(), 20);
Assigns a different weighting for each answer.

An example: https://webwork.maa.org/wiki/WeightedGrader

Graphing:

Requires loadMacros("BCITmacros.pl");

$yfunc = Formula("...");

$graph = plotFunction($yfunc, domain=>[$xmin, $xmax]);

BEGIN_TEXT
\{displayGraph($graph)\}
END_TEXT
Creates the graph of a function \(y = f(x)\) in one step.

domain: Optional. The plotting range of x. If skipped, default is [-10, 10].
xrange: Optional. The range of x in the graph area. If skipped, default is domain.
yrange: Optional. The range of y in the graph area. If skipped, the y-range will be determined by the minimum and maximum values of \(f(x)\) in the plotting range.

See initGraph, addAxes, addGrid, addCurve for other options.
$graph = initGraph(
  xrange=>[$xmin, $xmax],
  yrange=>[$ymin, $ymax],
);

  OR

$graph = initGraph(
  xrange=>[$xmin, $xmax],
  yrange=>[$ymin, $ymax],
  xextra=>[0, 0],
  yextra=>[0, 0],
  size=>[300, 300],
  xyratio=>0,
  transparent=>0,
  background=>"",
  bgopacity=>100,
  bgratio=>1;
);

  OR

$graph = initGraph(use=>$another_graph, transparent=>1);
Initiate a graphing area.

xrange, yrange: Ranges of x and y in the graph area.
xextra, yextra: Optional. Extra margins in x and y as fractions of ($xmax-$xmin) and ($ymax-$ymin). Useful if a specific region of the graph is intended to be placed at the centre of the image. If skipped, default is [0, 0]. For example, if xrange=>[0, 10] and xextra=>[.5, 1], the true x-range of the resulting graph is [-5, 20].
size: Optional. Horizontal and vertical size of the plot area in pixels. If skipped, default is [300, 300].
xyratio: Optional. The scale length along y-axis per length of 1 unit along x-axis. 0 for no scale constraint. If skipped, no scale constraint.
transparent: Optional. Whether or not to set the background transparent. This is useful if the drawing are copied to another graph. If skipped, default is 0.
background: Optional. File name of the png, jpg or gif file used for the background. The image and the problem file must be in the same directory.
bgopacity: Optional. Opacity of the background image. Can be between 0 and 100. If skipped, default is 100.
bgratio: Optional. Crop the graph based on the size of the background image. If skipped, default is 1.
scaling: Optional. Used when generating the graph at a higher resolution. If skipped, default is 4, i.e. when size is 300, the true resolution of the image is 1200.

use: Copy the parameters and colors defined in another graph $another_graph to this new graph.
copyImage($graph, $graph2); Copy the image in $graph2 and paste it on top of $graph. $graph2 should have the same size as $graph. Original image on $graph will still show if $graph2 is transparent.
$new_graph = copyGraph($graph);
Create a new graph by making a copy of $graph.
$xmin = $graph->xmin;
$xmax = $graph->xmax;
$ymin = $graph->ymin;
$ymax = $graph->ymax;
Outputs the x- and y- values at the borders of $graph.
($xpx, $ypx) = xyPixel($graph);
Outputs the size of one pixel in $graph in units of x and y.

By default, this gives a scaled pixel (using scaling in createGraph). If true pixel lengths are needed, add the option truepixel=>1.
($uxpx, $uypx, $vxpx, $vypx) = perpPixel($graph, $x1, $y1, $x2, $y2); Outputs the vectors u = ($uxpx, $uypx) and v = ($vxpx, $vypx) that are 1 pixel long for which u is in the same direction as ($x2-$x1, $y2-$y1) and v is 90°counterclockwise to u on the graph, regardless of the scales in x- and y-directions.
$graph->new_color("green", 0, 153, 0);
$graph->new_color("midgreen", 127, 204, 127);
$graph->new_color("lightgreen", 223, 243, 223);
Defines a new color only for $graph. Numbers represent RGB scale from 0 to 255.

Standard colors (already defined): "black", "blue", "darkblue", "midblue", "lightblue", "green", "darkgreen", "midgreen", "lightgreen", "red", "darkred", "midred", "lightred", "grey", "darkgrey", "midgrey", "lightgrey", "orange", "yellow", "white".
addAxes($graph);

  OR

addAxes($graph,
  xaxisrange=>[$xaxismin, $xaxismax],
  yaxisrange=>[$yaxismin, $yaxismax],
  axistitles=>["x", "y"],
  color=>"default",
  thickness=>1,
  axes=>[0, 0],
  arrow=>[1, 1],
  backarrow=>[0, 0],
  axisticks=>[-8, -8],
  minorticks=>[0, 0],
  tickataxis=>[0, 0],
  ticklabelformat=>"%g",
  ticklabelpi=>[0, 0],
  xticks=>[$x1, $x2, $x3],
  xticklabels=>[$xlbl1, $xlbl2, $xlbl3],
  yticks=>[$y1, $y2, $y3],
  yticklabels=>[$ylbl1, $ylbl2, $ylbl3],
  font=>"medium",
);
Adds the coordinate axes. Add the axes at the last step if the axes are to be placed on top of everything else in the graph.

$graph: The graph created using initGraph.
xaxisrange, yaxisrange: Optional. Ranges of the coordinate axes in case if the axes do not use the entire length of the plot area. Entire length of graph if skipped.
axistitles: Optional. Titles of the x- and y-axes. No titles if skipped or if axistitles=>["", ""].
color: Optional. Color of the axes. Grey (127, 127, 127) if skipped or if color=>"axiscolor";
thickness: Optional. Thickness of the axes in pixels. If skipped, default is 1.
axes: Optional. Location of the horizontal and vertical axes. If skipped, default is [0, 0]. No x-axis: set axes=>["", 0]. No y-axis: set axes=>[0, ""].
arrow: Optional. Whether or not to add arrow heads at the end of the x- and y-axes. If skipped, default is [1, 1].
backarrow: Optional. Whether or not to add arrow heads in the beginning of the x- and y-axes. If skipped, default is [0, 0].
axisticks: Optional. Tickmark spacing along the x- and y-axes. Use negative integers for auto scale. Bigger negative integers means more tickmarks. No tickmarks if axisticks=>[0, 0].
minorticks: Optional. Minor tickmark spacing along the x- and y-axes. No minor tickmarks if minorticks=>[0, 0].
tickataxis: Optional. Whether or not to put a tick mark with label at the x- and y-axes. If skipped, default is [0, 0].
ticklabelformat: Optional. Format of tick labels. Can be "frac" for fractions or any format from https://perldoc.perl.org/functions/sprintf. For example, ticklabelformat=>"%0.3f" means numbers are rounded to 3 decimal places. If skipped, default is "%g", which is the same as "%0.6g", meaning 6 significant digits.
ticklabelpi: Optional. Whether or not to display tick labels in multiples of ? for each axis. If skipped, default is [0, 0].
xticks, yticks: Optional. Extra tickmarks on the x- and y-axes. If skipped, only autogenerated tickmarks from axisticks will be displayed.
xticklabels, yticklabels: Optional. Labels at extra tickmarks. Use "" for blank labels. If skipped, the actual values will be displayed.
font: Optional. Can be "tiny", "small", "medium", "large" or "giant". If skipped, default is "medium".
addAxesxy($graph); Adds the coordinate axes with no tick marks and "x" and "y" as the axis titles. All options from addAxes also apply here.
addGrid($graph);

  OR

addGrid($graph,
  xaxisrange=>[$xaxismin, $xaxismax],
  yaxisrange=>[$yaxismin, $yaxismax],
  gridspacing=>[-8, -8],
  minorspacing=>[0, 0],
  gridcolor=>"default",
  minorcolor=>"default",
  thickness=>0.5,
  dotspacing=>0,
  dashspacing=>3,
);
Adds grid to the graph.

$graph: The graph created using initGraph.
xaxisrange, yaxisrange: Optional. Ranges of the coordinate axes. Entire length of graph if skipped.
gridspacing: Optional. Size of the grid in x- and y-directions. Use negative integers for auto scale. Bigger negative integers means more tickmarks. If skipped, default is [-8, -8]. Use 0 if no grid in one direction.
minorspacing: Optional. Size of minor grid in x- and y-directions. If skipped, default is no minor grid.
gridcolor: Optional. Color of the grid. If skipped, default is light grey.
minorcolor: Optional. Color of the minor grid. If skipped, default is very light grey.
thickness: Optional. Thickness of grid lines in pixels. If skipped, default is 0.5.
dotspacing: Optional. Spacing between dots in pixels if the grid lines are dotted lines. Solid grid lines if dotspacing=>0 and dashspacing=>0.
dashspacing: Optional. Spaces between dashes in pixels for dashed lines. 0 for solid line. Ignored if dotspacing has a non-zero value. If skipped, default is 3.
axisskip: Optional. Skip the grid at the locations where coordinate axes are present. Need to input the location of the axes (see addAxes). Not applied if skipped.
addLine($graph, $x1, $y1, $x2, $y2);

  OR

addLine($graph, $x1, $y1, $x2, $y2,
  color=>"black",
  thickness=>1.5,
  end=>"round",
  dotspacing=>0,
  dashspacing=>0,
  arrow=>0,
  backarrow=>0,
  arrowwid=>6,
  offset=>0,
  length=>0,
  extend=>[0, 0],
  font=>"large",
  label=>"",
  labeldist=>10,
  labelloc=>0.5,
  labeloffset=>[0, 0],
  labelrot=>"parallel",
  startlabel=>"",
  startlabeldist=>12,
  startlabeloffset=>[0, 0],
  startlabeldir=>0
  startlabelrot=>0,
  endlabel=>"",
  endlabeldist=>12,
  endlabeloffset=>[0, 0],
  endlabelrot=>0,
  symbol=>"",
  symbolsize=>6,
  symbollocs=>0.5,
  output=>"",
);

  OR

$graph->moveTo($x1, $y1);
addLineTo($graph, $x2, $y2,
  ...same options as addLine...);
Plots a line.

addLine: Draws a line from ($x1, $y1) to ($x2, $y2).
moveTo: Put the pen at ($x1, $y1).
addLineTo: Draws a line from the previous location to ($x2, $y2).

$graph: The graph created using initGraph.
color: Optional. Standard color or user-defined colors. If skipped, default is black.
thickness: Optional. Thickness of the line in pixels. If skipped, default is 1.5.
end: Optional. End style of the line. Can be "round" or "flat". If skipped, default is "round".
dotspacing: Optional. Spacing between dots in pixels for dotted line. 0 for solid line. If skipped, default is 0.
dashspacing: Optional. Spacing between dashes in pixel for dashed line. 0 for solid line. Ignored if dotspacing has a non-zero value. If skipped, default is 0.
arrow: Optional. Whether or not to put an arrowhead at the end. If skipped, default is 0.
backarrow: Optional. Whether or not to put an arrowhead at the start. If skipped, default is 0.
arrowwid: Optional. Width of arrowheads. If skipped, default is 4*thickness.
offset: Optional. Perpendicular offset in pixels from the original line. Can be positive or negative. If skipped, default is 0.
length: Optional. Length of the line in pixels. The line starts at ($x1, $y1) and extends to the direction of ($x2, $y2). Can be positive or negative. Ignored if the value is 0. If skipped, default is 0.
extend: Optional. Extend the line beyond the endpoints in pixels. Can be positive (longer) or negative (shorter). If skipped, default is [0, 0].
font: Optional. Can be "tiny", "small", "medium", "large", "giant". If skipped, default is "large".
label: Optional. Label beside the line. If skipped, default is "".
labeldist: Optional. Distance in pixels between the line and the label. Can be negative. If skipped, default is 10.
labelloc: Optional. Location of the label along the line. 0 at start, 1 at end. If skipped, default is 0.5 (midpoint).
labeloffset: Optional. Label moved in horizontal and vertical directions from the default location in pixels. If skipped, default is "[0, 0]".
labelrot: Optional. Label rotated counterclockwise in degrees. Can also be "parallel" or "perpendicular". If skipped, default is "parallel".
startlabel, endlabel: Optional. Labels at the ends of the line.
startlabeldist, endlabeldist: Optional. Distance in pixel between an endpoint of the line and the label. Default is the same as labeldist.
startlabeloffset, endlabeloffset: Optional. Label moved in horizontal and vertical directions from the default location in pixels. If skipped, default is "[0, 0]".
startlabeldir, endlabeldir: Optional. Direction in degrees counterclockwise from an endpoint of the line to the label. If skipped, default is 0.
stattlabelrot, endlabelrot: Optional. Label rotated counterclockwise in degree. If skipped, default is 0.
symbol: Optional. Add a symbol along the arrow. Can be "arrow", "backarrow", "congruent" or "parallel". For double/triple congurent/parallel symbols, use "congruent2", "congruent3", "parallel2" or "parallel3". If skipped, no symbols are added.
symbolsize: Optional. Size of the symbol in pixels. If skipped, default is arrowwid.
symbolloc: Optional. Location of the symbol along the arrow. 0 at start, 1 at end. If skipped, default is 0.5 (midpoint). Multiple symbols can be added by a list, e.g. symbolloc=>[0.2, 0.4, 0.8].

Outputs:
($xstart, $ystart, $xend, $yend) = addLine(..., output=>"endpoints") outputs the locations of the endpoints.
($xlabel, $ylabel) = addLine(..., output=>"labelloc") outputs the location of the label (aligned center and middle).
($xsymbol, $ysymbol) = addLine(..., output=>"symbolloc") outputs the location of the first symbol.
addEllipse($graph, $xcent, $ycent, $a, $b)

  OR

addEllipse($graph, $xcent, $ycent, $a, $b,
  angle=>[0, 360],
  steps=>120,
  color=>"black",
  thickness=>1.5,
  dotspacing=>0,
  dashspacing=>0,
  arrow=>0,
  backarrow=>0,
  arrowwid=>6,
);
Plots an ellipse with centre at ($xcent, $ycent), horizontal semiaxis of $a and vertical semiaxis of $b.

$graph: The graph created using initGraph.
angle: Optional. The plotting range in degrees measured counterclockwise. 0 means the right direction. If skipped, default is "[0, 360]".
steps: Optional. Number of points used to plot the ellipse. If skipped, default is 1 for every 3 degrees in angle.
color: Optional. Standard color or user-defined colors. If skipped, default is black.
thickness: Optional. Thickness of the curve in pixels. If skipped, default is 1.5.
dotspacing: Optional. Spacing between dots in pixels for dotted line. 0 for solid curve. If skipped, default is 0.
dashspacing: Optional. Spacing between dashes in pixel for dashed line. 0 for solid line. Ignored if dotspacing has a non-zero value. If skipped, default is 0.
arrow: Optional. Whether or not to put an arrowhead at the end. If skipped, default is 0.
backarrow: Optional. Whether or not to put an arrowhead at the start. If skipped, default is 0.
arrowwid: Optional. Width of arrowheads. If skipped, default is 4*thickness.
$xfunc = Formula("...");
$yfunc = Formula("...");

addCurve($graph, $xfunc, $yfunc, domain=>[-1, 1]);

  OR

addCurve($graph, $xfunc, $yfunc,
  domain=>[-1, 1],
  steps=>100,
  color=>"blue",
  thickness=>1.5,
  end=>"round",
  dotspacing=>0,
  dashspacing=>0,
  arrow=>0,
  backarrow=>0,
  arrowwid=>6,
  extend=>[0, 0],
  offset=>0,
  label=>"",
  font=>"large",
  labeldist=>10,
  labelloc=>0.5,
  labeloffset=>[0, 0],
  symbol=>"",
  symbolsize=>6,
  symbollocs=>0.5,
  output=>"",
);

Plots a parametric curve ($xfunc, $yfunc). For functions, use $xfunc=Formula("x") or the symbol of the independent variable.

$graph: The graph created using initGraph.
domain: The plotting range of the independent variable in $xfunc and $yfunc.
steps: Optional. Number of points used to plot the curve. If skipped, default is 100.
color: Optional. Standard color or user-defined colors. If skipped, default is blue.
thickness: Optional. Thickness of the curve in pixels. If skipped, default is 1.5.
end: Optional. End style of the line. Can be "round" or "flat". If skipped, default is "round".
dotspacing: Optional. Spacing between dots in pixels for dotted curve. 0 for solid curve. If skipped, default is 0.
dashspacing: Optional. Spacing between dashes in pixel for dashed curve. 0 for solid curve. Ignored if dotspacing has a non-zero value. If skipped, default is 0.
arrow: Optional. Whether or not to put an arrowhead at the end. If skipped, default is 0.
backarrow: Optional. Whether or not to put an arrowhead at the start. If skipped, default is 0.
arrowwid: Optional. Width of arrowheads. If skipped, default is 4*thickness.
extend: Optional. Extend the curve beyond the endpoints in pixels. Can be positive (longer) or negative (shorter). If skipped, default is [0, 0].
offset: Optional. Perpendicular offset in pixels from the original curve. Can be positive or negative. If skipped, default is 0.
label: Optional. Label beside the curve. If skipped, default is "".
font: Optional. Can be "tiny", "small", "medium", "large" or "giant". If skipped, default is "large".
labeldist: Optional. Distance in pixels between the curve and the label. Can be negative. If skipped, default is 12.
labelloc: Optional. Location of the label along the curve. 0 at start, 1 at end. If skipped, default is 0.5 (midpoint).
labeloffset: Optional. Label moved in horizontal and vertical directions from the default location in pixels. If skipped, default is "[0, 0]".
symbol: Optional. Add a symbol along the arrow. Can be "arrow" or "backarrow". If skipped, no symbols are added.
symbolsize: Optional. Size of the symbol in pixels. If skipped, default is arrowwid.
symbolloc
: Optional. Location of the symbol along the curve. 0 at start, 1 at end. If skipped, default is 0.5 (midpoint). Multiple symbols can be added by a list, e.g. symbolloc=>[0.2, 0.4, 0.8].

Outputs:
($xstart, $ystart, $xend, $yend) = addCurve(..., output=>"endpoints") outputs the locations of the endpoints.
($xlabel, $ylabel) = addCurve(..., output=>"labelloc") outputs the location of the label (aligned center and middle).
($xsymbol, $ysymbol) = addCurve(..., output=>"symbolloc") outputs the location of the first symbol.
$yfunc = Formula("...");

addFunction($graph, $yfunc, domain=>[-1, 1]);
Plots a function $yfunc. See addCurve for options.
addPoint($graph, $xpos, $ypos);

  OR

addPoint($graph, $xpos, $ypos,
  type=>"circle",
  size=>6,
  color=>"black",
  dir=>0,
  label=>"",
  font=>"large",
  labeldist=>10,
  labeldir=>0,
  labeloffset=>[0, 0],
);
Add a point (symbol) at ($xpos, $ypos).

$graph: The graph created using initGraph.
$xpos, $ypos: Location of the centre of the symbol.
type: Optional. Type of symbol. Can be "circle", "opencircle", "emptycircle", "triangle", "square" and "cross". If skipped, default is "circle".
size: Optional. Size of the symbol in pixels. If skipped, default is 6.
color: Optional. Standard color or user-defined color. If skipped, default is black.
dir: Optional. The angle the symbol is rotated. If skipped, default is 0.
label: Optional. Label beside the point. If skipped, default is "".
font: Optional. Can be "tiny", "small", "medium", "large" or "giant". If skipped, default is "large".
labeldist: Optional. Distance in pixels between the point and the label. Can be negative. If skipped, default is 12.
labeldir: Optional. Direction in degrees counterclockwise from the point to the label. If skipped, default is 0.
labeloffset: Optional. Label moved in horizontal and vertical directions from the default location in pixels. If skipped, default is "[0, 0]".
addAngle($graph, $Ax, $Ay, $Bx, $By, $Cx, $Cy);

  OR

addAngle($graph, $Ax, $Ay, $Bx, $By, $Cx, $Cy,
  color=>"grey",
  rightangle=>0,
  forcerightangle=>0,
  reflex=>-1,
 
arcradius=>20,
  thickness=>1,
  dotspacing=>0,
  dashspacing=>0,
  arrow=>0,
  backarrow=>0,
  arrowwid=>6,
  cycles=>0,
  cyclespacing=>3,
  label=>"";
  font=>"large",
  labeldist=>10,
  fromvertex=>0,
  labeldir=>"default",
  labeloffset=>[0, 0],
);
Adds an arc for angle ABC, with A = ($Ax, $Ay), B = ($Bx, $By) and C = ($Cx, $Cy).

$graph: The graph created using initGraph.
color: Optional. Colour of the arc and the label. If skipped, default is grey.
rightangle: Optional. Whether or not to use the right angle symbol if the angle is 90°. If skipped, default is 0.
forcerightangle: Optional. Whether or not to use the right angle symbol regardless of angle size. If skipped, default is 0.
reflex: Optional. 0 for non-reflex angle. 1 for reflex angle. -1 for counterclockwise angle. If skipped, default is -1.
arcradius: Optional. Size of the angle indicator in pixels. If skipped, the size is automatically adjusted.
thickness: Optional. Thickness of the arc. 0 for not showing the arc. If skipped, default is 1.
dotspacing: Optional. Spacing between dots in pixels for dotted curve. 0 for solid curve. If skipped, default is 0.
dashspacing: Optional. Spacing between dashes in pixel for dashed curve. 0 for solid curve. Ignored if dotspacing has a non-zero value. If skipped, default is 0.
arrow: Optional. Whether or not to put an arrowhead at the end of the arc. If skipped, default is 0.
backarrow: Optional. Whether or not to put an arrowhead at the start of the arc. If skipped, default is 0.
arrowwid: Optional. Width of arrowheads. If skipped, default is 4*thickness.
cycles
: Optional. Number of complete cycles. If skipped, default is 0.
cyclespacing: Optional. Increase in arcradius after each complete cycle. If skipped, default is 3.
label: Optional. Add a label (at the middle of the angle by default).
font
: Optional. Can be "tiny", "small", "medium", "large" or "giant". If skipped, default is "large".
labeldist: Optional. Distance in pixels between the arc and the label. If skipped, default is 10.
fromvertex: Optional. If set to 1, labeldist represents the distance between the vertex of the angle and the label.
labeldir: Optional. Direction in degrees counterclockwise from the point to the label. If skipped, default is at the middle of the angle.
labeloffset: Optional. Label moved in horizontal and vertical directions from the default location in pixels. If skipped, default is "[0, 0]".
addLength($graph, $x1, $y1, $x2, $y2);

  OR

addLength($graph, $x1, $y1, $x2, $y2,
  color=>"grey",
  thickness=>1,
  dotspacing=>0,
  dashspacing=>0,
  arrow=>1,
  backarrow=>1,
  offset=>12,
  endlines=>["solid", "solid"],
  startextend=>[-5, 5],
  endextend=>[-5, 5],
  label=>"",
  font=>"large",
  labeldist=>10,
  labelloc=>0.5,
  labeloffset=>[0, 0]
  labelrot=>"parallel",
);
Adds a dimension line from ($x1, $y1) to ($x2, $y2).

$graph: The graph created using initGraph.
color: Optional. Standard color or user-defined colors. If skipped, default is grey.
thickness: Optional. Thickness of the dimension line in pixels. If skipped, default is 1.5.
dotspacing: Optional. Spacing between dots in pixels for dotted line. 0 for solid line. If skipped, default is 0.
dashspacing: Optional. Spacing between dashes in pixel for dashed line. 0 for solid line. Ignored if dotspacing has a non-zero value. If skipped, default is 0.
arrow: Optional. Whether or not to put an arrowhead at the end. If skipped, default is 1.
backarrow: Optional. Whether or not to put an arrowhead at the start. If skipped, default is 1.
offset: Optional. Perpendicular offset in pixels from the line ($x1, $y1) to ($x2, $y2). Can be positive or negative. If skipped, default is 12.
endlines: Optional. The style of the lines at the start and at the end. Can be "solid", "dotted", "dashed" or "none". If skipped, default is "solid".
startextend, endextend: Optional. For the extension lines at the endpoints. For example startextend=>[-5, 5], the first number -5 means the extension line will start 5 pixels from ($x1, $y1), and the second number 5 means the extension line will end 5 pixels after it reaches the dimension line. If skipped, default is [-5, 5].
label: Optional. Label beside the dimension line. If skipped, default is "".
font: Optional. Can be "tiny", "small", "medium", "large" or "giant". If skipped, default is "large".
labeldist: Optional. Distance in pixels between the dimension line and the label. Can be negative. If skipped, default is 12.
labelloc: Optional. Location of the label along the dimension line. 0 at start, 1 at end. If skipped, default is 0.5 (midpoint).
labeloffset: Optional. Label moved in horizontal and vertical directions from the default location in pixels. If skipped, default is "[0, 0]".
labelrot: Optional. Label rotated counterclockwise in degrees. Can also be "parallel" or "perpendicular". If skipped, default is "parallel".
$string = "some text";

addText($graph, $xpos, $ypos, $string);

  OR

addText($graph, $xpos, $ypos, $string,
  color=>"black",
  align=>["center", "middle"],
  font=>"large",
  bold=>0,
  rot=>0,
  offset=>[0, 0],
);

Adds a text.

$graph: The graph created using initGraph.
$xpos, $ypos: Location of the text.
$string: The text.
color: Optional. Standard color or user-defined colors. If skipped, default is "black".
align: Optional. Horizontal and vertical alignments. Horizontal alignment can be "left", "center", "right". Vertical alignment can be "top", "middle", "bottom". If skipped, default is ["center", "middle"].
font: Optional. Can be "tiny", "small", "medium", "large", "giant" or a number. If skipped, default is "large".
bold: Optional. Whether or not the text is displayed in boldface. If skipped, default is 0.
rot: Optional. Text rotated counterclockwise in degrees. If skipped, default is 0.
offset: Optional. Text moved in horizontal and vertical directions from the default location in pixels. If skipped, default is "[0, 0]".
fillRegion($graph, $xpos, $ypos);

  OR

fillRegion($graph, $xpos, $ypos,
  color=>"default",
  bordercolor=>"none",
);
Fills a region from ($xpos, $ypos) outwards until it hits a border.

color: Optional. The colour used to fill the region. Can be any standard color or user-defined colors. If skipped, default is light grey.
bordercolor: Optional. Defines the colour of the border. Skip or set "none" if any colour change is considered as border. If skipped, default is "none".

Will fill up the entire space if there is no closed border enclosing ($xpos, $ypos).
BEGIN_TEXT
$BCENTER \{displayGraph($graph)\} $ECENTER
END_TEXT
Outputs $graph as an image.

width: Optional. Width of the image displayed in pixels. If height is skipped, height will be determined by original aspect ratio.
height: Optional. Height of the image displayed in pixels. If width is skipped, width will be determined by original aspect ratio.
If both width and height are skipped, size from createGraph will be used.
tex_size: Optional. Width of the image on print-outs. 1000 = full page width. If skipped, default is 1.5*width.

e.g. \{displayGraph($graph, width=>300)\}
BEGIN_TEXT
$BCENTER \{displayImage("Diagram.png")\} $ECENTER
END_TEXT
Inserts a png, jpg or gif in text. The image and the problem file need to be in the same directory.

width: Optional. Width of the image displayed in pixels. If height is skipped, height will be determined by original aspect ratio.
height: Optional. Height of the image displayed in pixels. If width is skipped, width will be determined by original aspect ratio.
If both width and height are skipped, original size of the image will be used.
scale: Optional: For resizing the image. If skipped, default is 1.
tex_size: Optional. Width of the image on print-outs. 1000 = full page width. If skipped, default is 1.5*width.

e.g. \{displayImage("Diagram.png", width=>300)\}

Numerical Methods:

$func = Formula("...");

int = integrate($func, $xl, $xu, $tol);

  OR

int = integrate($func, $xl, $xu, $tol, showWarning=>0);
An adaptive scheme for \(\displaystyle \int_{x_l}^{x_u} f(x) \, dx\).

$func: \(f(x)\).
$xl, $xu: \(x_l\), \(x_u\).
$tol: Optional. Tolerance in the result.
showWarning: Optional. Whether or not to show the warning message if the error of the result may exceed $tol. If skipped, the default is 1.

Requires loadMacros("BCITmacros.pl");
$func = Formula("...");

$int = trapezoid($func->perlFunction, $xl, $xu, steps=>100);

  OR

$int =
simpson($func->perlFunction, $xl, $xu, steps=>100);

  OR

$int =
romberg($func->perlFunction,
$xl, $xu, level=>6);
Numerical integration methods for \(\displaystyle \int_{x_l}^{x_u} f(x) \, dx\).

$func: \(f(x)\).
$xl, $xu: \(x_l\), \(x_u\).

Requires loadMacros("PGnumericalmacros.pl");
$func = Formula("...");

$int = gauss_legendre($func, $xl, $xu, $N);
Gauss-Legendre quadrature for \(\displaystyle \int_{x_l}^{x_u} f(x) \, dx\). Exact if \(f(x)\) is a polynomial of degree \(\le 2N-1\).

$func: \(f(x)\).
$xl, $xu: \(x_l\), \(x_u\).
$N: Number of nodes \(N\). Faster if \(N\) = 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 250, 300, 400, 500.

Requires loadMacros("BCITmacros.pl");
$func = Formula("...");

$int = gauss_jacobi($func, $xl, $xu, $N, alpha=>$alpha, beta=>$beta);
Gauss-Jacobi quadrature for integrals in the form \(\displaystyle \int_{x_l}^{x_u} f(x) \;dx\), where \(f(x) = g(x) (x-x_l)^{\alpha} (x_u-x)^{\beta}\) for some \(\alpha > -1\) and \(\beta > -1\). Exact if \(g(x)\) is a polynomial of degree \(\le 2N-1\).

$func: \(f(x)\).
$xl, $xu: \(x_l\), \(x_u\).
$N: Number of nodes \(N\).
$alpha, $beta: \(\alpha\), \(\beta\).

Requires loadMacros("BCITmacros.pl");
$int = simpsons_double($func, "y", $ylfunc, $yufunc, $Ny, "x", $xl, $xu, $Nx);
 
  OR

$int =
simpsons_triple($func, "z", $zlfunc, $zufunc, $Nz, "y", $ylfunc, $yufunc, $Ny, "x", $xl, $xu, $Nx);

  OR

$int =
gauss_legendre_double($func, "y", $ylfunc, $yufunc, $Ny, "x", $xl, $xu, $Nx);

  OR

$int =
gauss_legendre_triple($func, "z", $zlfunc, $zufunc, $Nz, "y", $ylfunc, $yufunc, $Ny, "x", $xl, $xu, $Nx);
For \(\displaystyle \int_{x_l}^{x_u} \int_{y_l(x)}^{y_u(x)} f(x,y) \;dy\;dx \;\) or \(\;\displaystyle \int_{x_l}^{x_u} \int_{y_l(x)}^{y_u(x)} \int_{z_l(x,y)}^{z_u(x,y)} f(x,y,z) \;dz\;dy\;dx\)

$func: \(f(x,y)\). Use Formula("...") even if it is a constant function.
$zl, $zu: \(z_l(x,y)\), \(z_u(x,y)\). Use Formula("...") if the bounds are not constant.
$yl, $yu: \(y_l(x)\), \(y_u(x)\). Use Formula("...") if the bounds are not constant.
$xl, $xu: \(x_l\), \(x_u\).
$Nz, $Ny, $Nx: Number of nodes used for each variable.
Simpson's rule: Only even N allowed.
Gauss-Legendre: Only N = 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 30, 40, 50, 60, 70, 80, 90, 100 allowed.

Order of integration can be changed.

Requires loadMacros("BCITmacros.pl");
$func = Formula("...");  OR  sub {...};

$sol = bisection($func, $xl, $xu);

  OR

$sol = bisection($func, $xl, $xu, $tol, $Ftol);

  OR

$sol = secant($func, $x0, $x1);

  OR

$sol = secant($func, $x0, $x1, $tol, $Ftol);
Bisection and secant methods for solving \(f(x) = 0\).

$func: \(f(x)\) (MathObject Formula or Perl subroutine)
$xl, $xu: Bounds for \(x\) (for bisection method)
$x0, $x1: Initial estimates (for secant method)
$tol: Tolerance for \(x\) (optional)
$Ftol: Stops at this residual (optional)

More detailed output:
($count, $error, $residual, $sol) = bisection(...); or secant(...);
$count: Number of iterations completed.
$error: Error bound of $sol.
$residual: $func evaluated at $sol.

Requires loadMacros("BCITmacros.pl");
For single equations

$func = Formula("..."); OR sub {...};

$sol = newton($func, $x0);


  OR

$sol = newton($func, $x0, $tol, $Ftol);


For systems of equations

@func = (Formula("..."), Formula("..."), ...);
OR (sub {...}, ...);

@sol = newton([@func], [@x0], var=>['x', 'y', ...]);

  OR

@sol = newton([@func], [@x0], $tol, $Ftol,
var=>['x', 'y', ...]);
Newton's method for solving a single equation \(f(x) = 0\) or a system of equations \(\mathbf{F}(\mathbf{x}) = \mathbf{0}\).

$func or @func: \(f(x)\) or \(\mathbf{F}(\mathbf{x})\) entered as an array. Can be MathObject Formulas or Perl subroutines.
$x0 or @x0: Initial estimate
$tol: Tolerance for \(x\) or \(\mathbf{x}\)(optional)
$Ftol: Stops at this residual (optional)
var: The variables (only required for systems where @func are given as MathObject Formulas)

More detailed output:
($count, $error, $residual, $sol_k, $sol) = newton(..., diagnostics=>1);
$count: Number of iterations completed.
$error: Error bound of $sol. For systems, display as an array using the syntax @{$error}
$residual: $func evaluated at $sol. For systems, display as an array using the syntax @{$residual}
$sol_k: The approximate solution at each iteration. Display as an array using the syntax @{$sol_k}
$sol: The final result. For systems, display as an array using the syntax @{$sol}
($sol1, $sol2) = quadratic_zeros($a_2, $a_1, $a_0); Find the real zeros of the quadratic function \(a_2 x^2 + a_1 x + a_0\).

Requires loadMacros("BCITmacros.pl");
@sol_array = bkell_real_zeros_finder($a_n, ..., $a_0);
Numerical approximations of the real zeros of the polynomial \(a_nx^n + \cdots + a_1x + a_0\).

Requires loadMacros("freemanMacros.pl");
$interpFunc = linearSpline([$x0, $x1, ...], [$y0, $y1, ...]);

  OR

$interpFunc = hermiteSpline([$x0, $x1, ...], [$y0, $y1, ...], [$m0, $m1, ...]);

  OR

$interpFunc = cubicSpline([$x0, $x1, ...], [$y0, $y1, ...]);

  OR

$interpFunc = cubicSpline([$x0, $x1, ...], [$y0, $y1, ...],
  periodic=>0,
  monotone=>0,
  endSlope=>[undef, undef]
);

Generate a function that goes through the points ($x0, $y0), ($x1, $y1), ... using various interpolation methods. $x0, $x1, ... need to be in increasing order.

For hermiteSpline, [$m0, $m1, ...] represent the slope at each point and is required.

Use &$interpFunc($x) to evaluate the interpreted value at \(x =\) $x.
Use addFunction($graph, $interpFunc, domain=>[$xmin, $xmax]) to plot the interpolation on $graph.

Options for linearSpline and hermiteSpline:
periodic: Optional. Whether or not to repeat the function outside the endpoints. If skipped, default is 0.

Options for cubicSpline:
periodic: Optional. Whether or not to force the function to be smooth at the endpoints. If skipped, default is 0.
monotone: Optional. Whether or not to force the function to be monotonic between points. If skipped, default is 0.
endSlope: Optional. 1st derivatives at the endpoints. If undef, the 2nd derivative at the corresponding endpoint is set to be 0 (if monotone=>0). If skipped, default is [undef, undef].

Requires loadMacros("BCITmacros.pl");

Geogebra Integration:

Requires loadMacros("BCITmacros.pl");

$ggb = GGBApplet("QymqZJjg");

  OR

$ggb = GGBApplet("QymqZJjg",
  ggbName=>"ggbApp1",
  screenshot=>"screenshot.png",
  parameters=>"'width':400, 'height':300, 'showResetIcon':true"
);

BEGIN_TEXT
\{$ggb\}
END_TEXT
Displays GeoGebra Applet using GeoGebra Material ID. For example, "QymqZJjg".

ggbName: Optional. Javascript applet name. If skipped, the Material ID is used.
screenshot: Optional. Screenshot for printouts. If skipped, no image will be displayed in printouts.
parameters: Optional. Overrides the default settings of the applet. See https://wiki.geogebra.org/en/Reference:GeoGebra_App_Parameters for more details.
$a = 1;
$b = 2;

GGBInitialize("
 
ggbApp1.setValue('a', $a);
 
ggbApp1.setValue('b', $b);
");
For passing values from WeBWorK to GeoGebra when the applet is loaded.

Use Javascript syntax. ggbApp1 is the name of the applet defined in GGBApplet.

See https://wiki.geogebra.org/en/Reference:GeoGebra_Apps_API for more details.
$button = JSButton("
 
ggbApp1.setValue('a', 3);
 
ggbApp1.setValue('b', 4);
", label=>"Click here to change values");

BEGIN_TEXT
\{$button\}
END_TEXT
Creates a Javascript button that changes values in GeoGebra. Runs when the button is pressed.

To restore the initial state of the GeoGebra applet, use
$button = JSButton("ggbApp1.reset()", label=>"Reset");

To run the same code from GGBInitialize, use
$button = JSButton("ggbOnInit()", label=>"Return to initial values");

See https://wiki.geogebra.org/en/Reference:GeoGebra_Apps_API for more details.
GGBUpdate("
  var A =
ggbApp1.getValue('a');
 
var B = ggbApp1.getValue('b');
  var C = ggbApp1.getValue('c');
  getQE('
ansFromGGB').value = A + ',' + B + ',' + C;
");

BEGIN_TEXT
\{NAMED_HIDDEN_ANS_RULE("ansFromGGB")\}
END_TEXT

$ans = List(Real(1), Real(2));
NAMED_ANS("
ansFromGGB"=>$ans->cmp(list_checker=>~~&chkGeoGebra));
For passing values from GeoGebra to WeBWorK.

Use Javascript syntax. Runs whenever there are changes in the applet.
GetQE: Records the value in the answer box named "ansFromGGB". The name of the answer box can be changed.

NAMED_HIDDEN_ANS_RULE: For recording the values from GeoGebra.

NAMED_ANS: For grading the answer in the answer box "ansFromGGB" (passed from GeoGebra).
$ans: List answer. Can have fewer entries than ansFromGGB.
($a, $b) = (defined($inputs_ref->{ansFromGGB})) ?  split(",", $inputs_ref->{ansFromGGB}) : (1, 2);

GGBInitialize("
 
ggbApp1.setValue('a', $a);
 
ggbApp1.setValue('b', $b);
");

GGBUpdate("
  var A =
ggbApp1.getValue('a');
  var B =
ggbApp1.getValue('b');
  getQE('
ansFromGGB').value = A + ',' + B;
");

BEGIN_TEXT
\{NAMED_HIDDEN_ANS_RULE("ansFromGGB")\}
END_TEXT

$ans = List(Real(2), Real(4));
NAMED_ANS("ansFromGGB"=>$ans->cmp(list_checker=>~~&chkGeoGebra));
For grading from GeoGebra. The previous result from answer box "ansFromGGB" are passed to GeoGebra when loaded.

R Commands:

Requires loadMacros("RserveClient.pl");

rserve_eval("library(...R package...)");

@output = rserve_eval("...R code...");
Sends the R code to Rserve and gets the output.

rserve_eval: Sends the code to Rserve and retrieve the output from Rserve. The R code must be surrounded by " ".
@output: The output of the R command. It is always an array, even if there is only one output.

If @output is a 1-dimensional array, use $output[0], $output[1], etc to recall the output. If @output is a 2-dimensional array, refer to two-dimensional arrays for more details.

The problem seed is automatically sent to Rserve at the first call of rserve_eval. Random data generated by R will be the same as long as the seed number is not changed and if the sequence of random numbers generation is not changed.
$img = rserve_start_plot('png', 400, 250);

rserve_eval("...R code...");
rserve_eval("...R code...");

$image_path = rserve_finish_plot($img); 

BEGIN_TEXT
$BCENTER
\{ image($image_path, width=>400, height=>250) \}
$ECENTER
END_TEXT
Generates an R plot.

rserve_start_plot: Start of an R plot. The last two numbers represent the width and the height of the plot in pixels.
rserve_eval: All the R codes necessary for generating the plot.
rserve_finish_plot: End of the plot. It outputs the file name to $image_path.

image: The plot is placed in the question.
($remote_file) = rserve_eval('filename <- tempfile(fileext=".csv"); write.csv(???, filename); filename');

$local_file = rserve_get_file($remote_file);

($local_url = $local_file) =~ s|$tempDirectory|$tempURL|; 

BEGIN_TEXT
\{ htmlLink($local_url, "Download") \} the problem data (CSV file).
END_TEXT
Generates a CSV file from R and creates a URL for download.

($remote_file): The reference to the specific file R has regenerated. Brackets are necessary as it is an output from rserver_eval.

rserve_get_file: Creates a random file name for the file. $local_file records the file name.

($local_url = $local_file) =~ s|$tempDirectory|$tempURL|;: Generates the URL and stores in $local_url.

htmlLink: Place the URL in the question.