JME#
JME expressions are used by students to enter answers to algebraic questions, and by question authors to define variables. JME syntax is similar to what you’d type on a calculator.
Syntax#
Expressions are strings of text, made of variable names, literal values, grouped terms, function applications, operators, collections and indices.
Whitespace (space characters, tabs, newlines, etc.) can be used to separate literal values, for example a 2
is not interpreted the same as a2
.
For all other purposes, whitespace is ignored.
Variable names#
The first character of a variable name must be an alphabet letter; after that, any combination of letters, numbers and underscores is allowed, with any number of '
on the end.
- Examples:
x
x_1
time_between_trials
var1
row1val2
y''
This screencast describes which variable names are valid, and gives some advice on how you should pick names:
Variable name annotations#
Names can be given annotations to change how they are displayed. The following annotations are built-in:
verb
– does nothing, but names likei
,pi
ande
are not interpreted as the famous mathematical constants.op
– denote the name as the name of an operator — wraps the name in the LaTeX\operatorname
command when displayedv
orvector
– denote the name as representing a vector — the name is displayed in boldfaceunit
– denote the name as representing a unit vector — places a hat above the name when displayeddot
– places a dot above the name when displayed, for example when representing a derivativem
ormatrix
– denote the name as representing a matrix — displayed using a non-italic fontdiff
- denote the name as a differential - the name is prefixed with\mathrm{d}
when displayed, e.g. \(\mathrm{d}x\)degrees
- denote the name as representing an angle in degrees - the name has a suffix of^{\circ}
when displayed, e.g. \(x^{\circ}\)
Any other annotation is taken to be a LaTeX command.
For example, a name vec:x
is rendered in LaTeX as \vec{x}
, which places an arrow above the name.
You can apply multiple annotations to a single variable.
For example, v:dot:x
produces a bold x with a dot on top: \(\boldsymbol{\dot{x}}\).
Names with different annotations are considered to represent different values, for the purpose of simplification and evaluation.
For example, in the expression dot:x + x
, the two terms will not be collected together.
Literal values#
boolean
, integer
, number
and string
data types can be constructed with literal values.
Examples: true
, 1
, 4.3
, "Numbas"
There are also some built-in constants which are interpreted as number values:
pi
orπ
- the ratio of a circle’s circumference to its diameter;e
- the base of the natural logarithm;i
- the square root of -1;infinity
,infty
or∞
- infinity;nan
- “Not a number”, sometimes returned by JavaScript functions.
You can disable, override or define new constants in the question editor’s Constants tab.
Grouped terms#
Use parentheses ( )
to group terms.
For example:
(a+2)(a+1)
No other symbols can be used to group terms - square brackets [ ]
and curly braces { }
have other meanings in Numbas.
Function application#
A name followed immediately by a bracketed group is interpreted as a function application. Function names can be annotated similarly to variables.
A function takes one or more arguments, separated by commas. Each argument is a JME expression.
- Examples:
f(x)
g(a,b)
Anonymous functions#
An anonymous function consists of a sequence of named arguments, in parentheses if necessary, followed by the symbol ->
, and then an expression in terms of the arguments.
It can be used like a named function, or passed as an argument on its own to some functions.
You can match elements of lists passed to an anonymous function with names by putting the names inside square brackets.
- names -> expression#
- Examples:
(x -> x+1)(2)
→3
x -> x + 1
defines an anonymous function which adds one to its argument.() -> 2
defines an anonymous function which always returns2
.((x,y) -> sqrt(x^2 + y^2))(3, 4)
→5
(x,y) -> sqrt(x^2 + y^2)
defines an anonymous function which returns the hypotenuse of a right-angled triangle with sidesx
andy
.[a, b] -> a + b
defines an anonymous function which takes a single list argument, and adds the first two entries.([a,b] -> a + b)([1,2])
→3
Operators#
There are three kinds of operators:
- Binary#
A symbol written between two terms, for example
a + b
(”\(a\) plus \(b\)”). Each binary operator has a precedence which determines when it is evaluated in relation to other operators.- Prefix#
A symbol written to the left of a term, for example
!a
(“not \(a\)”).- Postfix#
A symbol written to the right of a term, for example
a!
(”\(a\) factorial”).
Relations#
Some binary operators are marked as relations.
Relations can be chained together, for example a<b<c
is interpreted as a<b and b<c
.
The relation operators are <
, <=
, >
, >=
, =
, <>
and in
.
Collections#
There are two kinds of collection: lists and dictionaries.
Both are written as a series of terms written between square brackets and separated by commas.
For a dictionary, each term is a keypair
: a variable name or string followed by a colon and an expression.
For example, [a: 1, "first name": "Owen"]
is a dictionary with keys "a"
and "first name"
.
A collection made of any other kind of term is interpreted as a list
.
An empty pair of brackets []
is interpreted as an empty list
.
To construct an empty dictionary, use dict()
.
- Examples:
[1,2,3]
[a]
[]
Indices#
Many JME data types support indexing.
An index is a single term inside square brackets immediately following another term.
The first element in a list has index 0
.
Negative indices read from the end: the index -1
corresponds to the last item.
- Examples:
[1,2,3][0]
produces the first element in the list,1
.x[3..7]
produces the fourth to the eighth elements of the listx
.id(4)[1]
produces the second row of a \(4 \times 4\) identity matrix,vector(0,1,0,0)
.info["name"]
returns the value corresponding to the key"name"
in the dictionaryinfo
."Numbas"[0]
produces the first letter of the string"Numbas"
,"N"
.
Implicit multiplication#
JME supports implicit multiplication in some cases, allowing you to omit the multiplication symbol:
- Examples:
(a+1)2 = (a+1)*2
(x+y)z = (x+y)*z
2x = 2*x
x y = x*y
Warning
Note that a name followed by a bracket is not always interpreted as implicit multiplication. Instead, it’s interpreted as a function application.
To interpret such expressions as products, in a mathematical expression part turn off the Allow unknown function names? option, and when dealing with expression
values, use expand_juxtapositions
.
Case-sensitivity#
The default behaviour of variable and function names in JME expressions is that they are considered case-insensitively: two names are considered equivalent if they are exactly equal when converted to lower-case.
You can force the JME system to be case-sensitive using the scope_case_sensitive
function.
Synonymous keywords and characters#
JME interprets some keywords and characters as synonyms for others, when there are multiple conventional ways of writing the same thing, and there’s no ambiguity about what they mean.
Often there is a single Unicode character for a mathematical symbol which can also be written in JME as a combination of ASCII characters.
Keyword |
Synonyms |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Superscript characters are interpreted as exponents, without the ^
character.
For example:
x⁻² = x^(-2)
The following superscript characters are recognised:
⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁽ ⁾ ⁺ ⁻ ⁼ ⁿ ⁱ
Data types#
JME expressions are composed of the following data types. Some extensions add new data types.
- number#
A real or complex floating-point number.
i
,e
,infinity
andpi
are normally defined as the imaginary unit, the base of the natural logarithm, ∞ and π, respectively. Within a question you can remove or override these using the Constants tab.Examples:
0.0
,-1.0
,0.234
,i
,e
,pi
Numbers of this type are represented using JavaScript’s built-in
Number
object, which is a 64-bit IEEE 754 floating-point number. This representation offers a very good compromise between precision and the range of values that can be stored, but can behave in unexpected ways. Accuracy is easily lost when dealing with very big or very small numbers, and on division.See functions related to Arithmetic, Number operations, Trigonometry and Number theory.
- Automatically converts to:
- integer#
An element of the set of integers, \(\mathbb{Z}\).
Examples:
0
,1
,-2
,431
.
- rational#
A fraction; an element of the set of rationals, \(\mathbb{Q}\). The numerator and denominator are integers.
Instances of this data type may be top-heavy, with numerator bigger than the denominator, and are not required to be reduced.
Examples:
1/1
,-34/2
,3/4
.
- decimal#
A number with a guaranteed level of precision, and arbitrary order of magnitude.
Numbers of this type are represented using the Decimal.js library. They’re guaranteed to be accurate to 40 significant figures. The order of magnitude is stored separately from the significant digits, so there’s no loss of precision for very big or very small numbers.
Examples:
dec(0)
,dec("1.23e-5")
,6.0221409*10^23
- Automatically converts to:
- boolean#
Booleans represent either truth or falsity. The logical operations and, or and xor operate on and return booleans.
Examples:
true
,false
See functions related to Logic and Control flow.
- string#
Use strings to create non-mathematical text. Either
'
or"
can be used to delimit strings.You can escape a character by placing a single backslash character before it. The following escape codes have special behaviour:
\n
New-line
\{
\{
\}
\}
If you want to write a string which contains a mixture of single and double quotes, you can delimit it with triple-double-quotes or triple-single-quotes, to save escaping too many characters.
Examples:
"hello there"
,'hello there'
,""" I said, "I'm Mike's friend" """
See functions related to Strings.
- list#
An ordered list of elements of any data type.
Examples:
[0,1,2,3]
,[a,b,c]
,[true,false,true]
See functions related to Lists.
- dict#
A ‘dictionary’, mapping key strings to values of any data type.
A dictionary is created by enclosing one or more key-value pairs (a string followed by a colon and any JME expression) in square brackets, or with the
dict
function.Key strings are case-sensitive.
Examples:
["a": 1, "b": 2]
["name": "Tess Tuser", "age": 106, "hobbies": ["reading","writing","arithmetic"] ]
dict("key1": 0.1, "key2": 1..3)
dict([["key1",1], ["key2",2]])
Warning
Because lists and dicts use similar syntax,
[]
produces an empty list, not an empty dictionary. To create an empty dictionary, usedict()
.See functions related to Dictionaries and JSON.
- range#
A range
a..b#c
represents (roughly) the set of numbers \(\{a+nc \: | \: 0 \leq n \leq \frac{b-a}{c} \}\). If the step size is zero, then the range is the continuous interval \([a,b]\).Examples:
1..3
,1..3#0.1
,1..3#0
See functions related to Ranges.
- set#
An unordered set of elements of any data type. The elements are pairwise distinct - if you create a set from a list with duplicate elements, the resulting set will not contain the duplicates.
Examples:
set(a,b,c)
,set([1,2,3,4])
,set(1..5)
See functions related to Sets.
- Automatically converts to:
- vector#
The components of a vector must be numbers.
When combining vectors of different dimensions, the smaller vector is padded with zeros to make up the difference.
Examples:
vector(1,2)
,vector([1,2,3,4])
See functions related to Vector and matrix arithmetic.
- matrix#
Matrices are constructed from lists of numbers, representing the rows.
When combining matrices of different dimensions, the smaller matrix is padded with zeros to make up the difference.
To retrieve the
n
th row of a matrixm
, writem[n]
. The row is returned as avector
value. To retrieve the cell in rowa
and columnb
, writem[a][b]
. Rows and columns are both numbered starting from zero.Examples:
matrix([1,2,3],[4,5,6])
,matrix(row1,row2,row3)
See functions related to Vector and matrix arithmetic.
- name#
A variable name. When an expression is evaluated, all variable names are replaced withe their corresponding value in the current scope.
- function#
An application of a function.
Examples:
f(x)
,sin(x)
- op#
An infix binary operation, or a pre-/post-fix unary operation.
Examples:
x+y
,n!
,a and b
- lambda#
-
Examples:
x -> 2x
,(x,y) -> x+y
.
- expression#
A JME sub-expression. Sub-expressions can be simplified, rearranged, pattern-matched, or evaluated using given values for their free variables.
See functions related to Sub-expressions.
Automatic data type conversion#
Some data types can be automatically converted to others when required.
For example, the number-like types such as integer
and decimal
can be automatically converted to number
values.
The data types of the arguments to a function application determine which version of the function is used. Ideally, this will do what you expect without you having to think about it. For reference, the process for deciding on what conversions to perform is as follows:
If there is a version of the function which takes exactly the given data types, that is used.
Otherwise, each definition of the function is compared by looking at each of the arguments, working from left to right.
A definition which does not convert an argument is preferred to one that does.
If both definitions being compared need to convert an argument, the type that occurs first in the input type’s list of automatic conversion methods is used. (This follows the order of the types under the “Automatically converts to” headers above)
The following examples illustrate how this works.
Expression |
Type of result |
Explanation |
---|---|---|
|
The |
|
|
||
|
|
|
|
|
|
|
|
Function reference#
Arithmetic#
- x+y#
Addition.
- Definitions:
dict
,dict
→dict
- merge two dictionaries, with values from the right-hand side taking precedence when the same key is present in both dictionaries.string
, anything →string
- convert the right-hand argument to a string, and concatenateanything,
string
→string
- convert the left-hand argument to a string, and concatenate
- Examples:
1+2
→3
vector(1,2)+vector(3,4)
→vector(4,6)
matrix([1,2],[3,4])+matrix([5,6],[7,8])
→matrix([6,8],[10,12])
[1,2,3]+4
→[1,2,3,4]
[1,2,3]+[4,5,6]
→[1,2,3,4,5,6]
"hi "+"there"
→"hi there"
- x-y#
Subtraction.
- Definitions:
- Examples:
1-2
→-1
vector(3,2)-vector(1,4)
→vector(2,-2)
matrix([5,6],[3,4])-matrix([1,2],[7,8])
→matrix([4,4],[-4,-4])
- x*y#
Multiplication.
- Definitions:
- Examples:
1*2
→2
2*vector(1,2,3)
→vector(2,4,6)
matrix([1,2],[3,4])*2
→matrix([2,4],[6,8])
matrix([1,2],[3,4])*vector(1,2)
→vector(5,11)
- x/y#
Division. Only defined for numbers.
- x^y#
Exponentiation.
exp(x)
is a synonym fore^x
.
Number operations#
- decimal(n)
- decimal(x)
- dec(x)#
Construct a
decimal
value. Any string accepted by Decimal.js is accepted.
- rational(n)
Convert
n
to a rational number, taking an approximation when necessary.
- int(n)#
Convert
n
to an integer, rounding to the nearest integer.
- abs(x)#
- len(x)#
- length(x)#
Absolute value, length, or modulus.
- Definitions:
- Examples:
abs(-8)
→8
abs(3-4i)
→5
abs("Hello")
→5
abs([1,2,3])
→3
len([1,2,3])
→3
len(set([1,2,2]))
→2
length(vector(3,4))
→5
abs(vector(3,4,12))
→13
len(["a": 1, "b": 2, "c": 1])
→3
- isint(x)#
Returns
true
ifx
is an integer - that is, it is real and has no fractional part.
- iszero(n)#
Returns
true
whenn
is exactly 0.
- log(x, b)#
Logarithm with base
b
, or base 10 ifb
is not given.
- radians(x)#
Convert degrees to radians.
- Example:
radians(180)
→pi
- max(a, b)#
Greatest of the given numbers.
- min(a, b)#
- min(numbers)
Least of the given numbers.
- clamp(x, a, b)#
Return the point nearest to
x
in the interval \([a,b]\).Equivalent to
max(a,min(x,b))
.
- precround(n, d)#
Round
n
tod
decimal places. On matrices and vectors, this rounds each element independently.- Definitions:
- Examples:
precround(pi,5)
→3.14159
precround(21.3,5)
→21.30000
precround(matrix([[0.123,4.56],[54,98.765]]),2)
→matrix([0.12,4.56],[54.00,98.77])
precround(vector(1/3,2/3),1)
→vector(0.3,0.7)
- siground(n, f)#
Round
n
tof
significant figures. On matrices and vectors, this rounds each element independently.
- with_precision(n, precision, precisionType)#
Add or remove a
number
value’s precision information. This function is used in the attempt suspend data process; it’s unlikely you’d want to use it in another context.- Definition:
with_precision(3.00, 2, "dp")
- imprecise(n)#
Remove a
number
value’s precision information. Equivalent towith_precision(n, nothing, nothing)
.This function is used in the attempt suspend data process; it’s unlikely you’d want to use it in another context.
- withintolerance(a, b, t)#
Returns
true
if \(b-t \leq a \leq b+t\).
- dpformat(n, d[, style])#
Round
n
tod
decimal places and return a string, padding with zeros if necessary.If
style
is given, the number is rendered using the given notation style. See the page on Number notation for more on notation styles.
- countdp(n)#
Assuming
n
is a string representing a number, return the number of decimal places used. The string is passed throughcleannumber
first.
- sigformat(n, d[, style])#
Round
n
tod
significant figures and return a string, padding with zeros if necessary.
- countsigfigs(n)#
Assuming
n
is a string representing a number, return the number of significant figures. The string is passed throughcleannumber
first.
- togivenprecision(str, precisionType, precision, strict)#
Returns
true
ifstr
is a string representing a number given to the desired number of decimal places or significant figures.precisionType
is either"dp"
, for decimal places, or"sigfig"
, for significant figures.If
strict
istrue
, then trailing zeroes must be included.
- togivenprecision_scientific(str, precisionType, precision)#
Returns
true
ifstr
is a string representing a number given to the desired number of decimal places or significant figures in scientific notation.This looks only at the significand part.
A significand of the form
D.DD
is considered to be given to 2 decimal places, or three significant figures.Trailing zeros must be given:
1.2
is only considered to be given to 1 decimal place, and1.20
is only considered to be given to 2 decimal places.precisionType
is either"dp"
, for decimal places, or"sigfig"
, for significant figures.If
strict
istrue
, then trailing zeroes must be included.- Definitions:
- Examples:
togivenprecision_scientific("1e2","dp",0)
→true
togivenprecision_scientific("1.0e2","dp",0)
→false
togivenprecision_scientific("1.0e2","dp",1)
→true
togivenprecision_scientific("1e2","sigfig",1)
→true
togivenprecision_scientific("1.0e2","sigfig",1)
→false
togivenprecision_scientific("1.0e2","sigfig",2)
→true
togivenprecision_scientific("1.23e2","sigfig",3)
→true
togivenprecision_scientific("1.23e2","dp",2)
→true
- tonearest(a, b)#
Round
a
to the nearest multiple ofb
.
- formatnumber(n, style)#
Render the number
n
using the given number notation style.See the page on Number notation for more on notation styles.
- scientificnumberlatex(n)#
Return a LaTeX string representing the given number in scientific notation, \(a \times 10^b\).
This function exists because scientific notation may use superscripts, which aren’t easily typeset in plain text.
- scientificnumberhtml(n)#
Return an HTML element representing the given number in scientific notation, \(a \times 10^b\).
This function exists because scientific notation may use superscripts, which aren’t easily typeset in plain text.
- cleannumber(str, styles)#
Clean a string potentially representing a number. Remove space, and then try to identify a notation style, and rewrite to the
plain-en
style.styles
is a list of notation styles. Ifstyles
is given,str
will be tested against the given styles. If it matches, the string will be rewritten using the matched integer and decimal parts, with punctuation removed and the decimal point changed to a dot.
- matchnumber(str, styles)#
Try to match a string representing a number in any of the given styles at the start of the given string, and return both the matched text and a corresponding
number
value.
- parsenumber(string, style)#
Parse a string representing a number written in the given style.
If a list of styles is given, the first that accepts the given string is used.
See the page on Number notation for more on notation styles.
- Examples:
parsenumber("1 234,567","si-fr")
→1234.567
parsenumber("1.001",["si-fr","eu"])
→1001
- parsenumber_or_fraction(string, style)#
Works the same as
parsenumber
, but also accepts strings of the formnumber/number
, which it interprets as fractions.- Example:
parsenumber_or_fraction("1/2")
→0.5
- parsedecimal(string, style)#
Parse a string representing a number written in the given style, and return a
decimal
value.If a list of styles is given, the first that accepts the given string is used.
See the page on Number notation for more on notation styles.
- parsedecimal_or_fraction(string, style)#
Works the same as
parsedecimal
, but also accepts strings of the formnumber/number
, which it interprets as fractions.
- tobinary(n)#
Write the given number in binary: base 2.
- tooctal(n)#
Write the given number in octal: base 8.
- tohexadecimal(n)#
Write the given number in hexadecimal: base 16.
- tobase(n, base)#
Write the given number in the given base.
base
can be any integer between 2 and 36.
- frombinary(s)#
Convert a string representing a number written in binary (base 2) to a
integer
value.
- fromhexadecimal(s)#
Convert a string representing a number written in hexadecimal (base 16) to a
integer
value.
Trigonometry#
Trigonometric functions all work in radians, and have as their domain the complex numbers.
- tan(x)#
Tangent: \(\tan(x) = \frac{\sin(x)}{\cos(x)}\)
- cosec(x)#
Cosecant: \(\csc(x) = \frac{1}{sin(x)}\)
- sec(x)#
Secant: \(\sec(x) = \frac{1}{cos(x)}\)
- cot(x)#
Cotangent: \(\cot(x) = \frac{1}{\tan(x)}\)
- arcsin(x)#
Inverse of
sin
. When \(x \in [-1,1]\),arcsin(x)
returns a value in \([-\frac{\pi}{2}, \frac{\pi}{2}]\).
- arctan(x)#
Inverse of
tan
. When \(x\) is non-complex,arctan(x)
returns a value in \([-\frac{\pi}{2}, \frac{\pi}{2}]\).
- atan2(y, x)#
The angle in radians between the positive \(x\)-axis and the line through the origin and \((x,y)\). This is often equivalent to
arctan(y/x)
, except when \(x \lt 0\), when \(pi\) is either added or subtracted from the result.
- sinh(x)#
Hyperbolic sine: \(\sinh(x) = \frac{1}{2} \left( \mathrm{e}^x - \mathrm{e}^{-x} \right)\)
- cosh(x)#
Hyperbolic cosine: \(\cosh(x) = \frac{1}{2} \left( \mathrm{e}^x + \mathrm{e}^{-x} \right)\)
- tanh(x)#
Hyperbolic tangent: \(\tanh(x) = \frac{\sinh(x)}{\cosh(x)}\)
- cosech(x)#
Hyperbolic cosecant: \(\operatorname{cosech}(x) = \frac{1}{\sinh(x)}\)
- sech(x)#
Hyperbolic secant: \(\operatorname{sech}(x) = \frac{1}{\cosh(x)}\)
- coth(x)#
Hyperbolic cotangent: \(\coth(x) = \frac{1}{\tanh(x)}\)
Number theory#
- x!#
- fact(x)
Factorial. When
x
is not an integer, \(\Gamma(x+1)\) is used instead.fact(x)
is a synonym forx!
.
- factorise(n)#
Factorise
n
. Returns the exponents of the prime factorisation ofn
as a list.
- divisors(n)#
- proper_divisors(n)#
- largest_square_factor(n)#
The largest perfect square factor of the given number.
When the prime factorisation of \(n\) is \(p_1^{x_1} \times \ldots \times p_k^{x_k}\), the largest perfect square factor is p_1^{2 lfloor x_1/2 rfloor} times … times p_k^{2 lfloor x_k/2}.
- gamma(x)#
Gamma function.
- ceil(x)#
Round up to the nearest integer. When
x
is complex, each component is rounded separately.
- floor(x)#
Round down to the nearest integer. When
x
is complex, each component is rounded separately.
- round(x)#
Round to the nearest integer.
0.5
is rounded up.
- trunc(x[, p])#
Round towards zero: truncate the number
x
to the nearest integer or top
decimal places.If
x
is positive, round down; if it is negative, round up.
- fract(x)#
Fractional part of a number. Equivalent to
x-trunc(x)
.
- rational_approximation(n[, accuracy])#
Compute a rational approximation to the given number by computing terms of its continued fraction, returning the numerator and denominator separately. The approximation will be within \(e^{-\text{accuracy}}\) of the true value; the default value for
accuracy
is 15.
- mod(a, b)#
Modulo; remainder after integral division, i.e. \(a \bmod b\).
- perm(n, k)#
Count permutations, i.e. \(^n \kern-2pt P_k = \frac{n!}{(n-k)!}\).
- comb(n, k)#
Count combinations, i.e. \(^n \kern-2pt C_k = \frac{n!}{k!(n-k)!}\).
- gcd_without_pi_or_i(a, b)#
Take out factors of \(\pi\) or \(i\) from
a
andb
before computing their greatest common denominator.
- coprime(a, b)#
Are
a
andb
coprime? True if theirgcd
is \(1\), or if either ofa
orb
is not an integer.
- lcm(a, b)#
Lowest common multiple of integers
a
andb
. Can be used with any number of arguments; it returns the lowest common multiple of all the arguments.
Vector and matrix arithmetic#
- vector(a1, a2, ..., aN)
Create a vector with given components. Alternately, you can create a vector from a single list of numbers.
- matrix(row1, row2, ..., rowN)
Create a matrix with given rows, which should be either vectors or lists of numbers. Or, you can pass in a single list of lists of numbers.
- id(n)#
Identity matrix with \(n\) rows and columns.
- numrows(matrix)#
The number of rows in the given matrix
- numcolumns(matrix)#
The number of columns in the given matrix
- rowvector(a1, a2, ..., aN)#
Create a row vector (\(1 \times n\) matrix) with the given components. Alternately, you can create a row vector from a single list of numbers.
- dot(x, y)#
Dot (scalar) product. Inputs can be vectors or column matrices.
- cross(x, y)#
Cross product. Inputs can be vectors or column matrices.
- angle(a, b)#
Angle between vectors
a
andb
, in radians. Returns0
if eithera
orb
has length 0.
- is_zero(x)#
Returns
true
if every component of the vectorx
is zero.
- is_scalar_multiple(u, v[, rel_tol][, abs_tol])#
Returns
true
ifu
is a scalar multiple ofv
. That is, ifu = k*v
for some real numberk
.The optional arguments
rel_tol
andabs_tol
specify the relative and absolute tolerance of the equality check for each component; seeisclose
.
- det(x)#
Determinant of a matrix. Throws an error if used on anything larger than a 3×3 matrix.
- transpose(x)#
Matrix transpose.
- sum_cells(m)#
Calculate the sum of all the cells in a matrix.
- augment(m1, m2)#
- combine_horizontally(m1, m2)#
Combine two matrices horizontally: given a \(r_1 \times c_1\) matrix
m1
and a \(r_2 \times c_2\) matrixm2
, returns a new \(\max(r_1,r_2) \times (c_1+c_2)\) matrix formed by putting the two matrices side, and padding with zeros where necessary.
- stack(m1, m2)#
- combine_vertically(m1, m2)#
Combine two matrices vertically: given a \(r_1 \times c_1\) matrix
m1
and a \(r_2 \times c_2\) matrixm2
, returns a new \((r_1 + r_2) \times \max(c_1,c_2)\) matrix formed by puttingm1
abovem2
, and padding with zeros where necessary.
- combine_diagonally(m1, m2)#
Combine two matrices diagonally: given a \(r_1 \times c_1\) matrix
m1
and a \(r_2 \times c_2\) matrixm2
, returns a new \((r_1 + r_2) \times (c_1 + c_2)\) matrix whose top-left quadrant ism1
and bottom-right quadrant ism2
.
- lu_decomposition(m)#
Perform LU-decomposition: decompose the given matrix into a lower-triangular matrix \(L\) and an upper-triangular matrix \(U\), such that \(m = LU\).
The matrix must be square.
Returns a list
[L, U]
.
- gauss_jordan_elimination(m)#
Perform Gaussian elimination: given a \(m \times n\) matrix, where \(n \geq m\), reduce the rows so that the leading coefficient in each row is \(1\), and every column containing a leading coefficient has zeros in every other row.
Strings#
- x[n]#
Get the Nth character of the string
x
. Indices start at 0.- Example:
"hello"[1]
→"e"
- x[a..b]
Slice the string
x
- get the substring between the given indices. Note that indices start at 0, and the final index is not included.- Example:
"hello"[1..4]
→"ell"
- substring in string#
Test if
substring
occurs anywhere instring
. This is case-sensitive.- Example:
"plain" in "explains"
→true
- string(x)
Convert
x
to a string.When converting a
expression
value to a string, you can give a list of display options as a second argument, either as a comma-separated string or a list of strings.- Definitions:
- Example:
string(123)
→"123"
string(x)
→"x"
string(expression("0.5"))
→"0.5"
string(expression("0.5"),"fractionNumbers")
→"1/2"
- jme_string(x)#
Convert any jme type
x
to a string representation.- Definitions:
anything
→string
- Example:
jme_string(123)
→"123"
jme_string(expression("x+y"))
→"x + y"
jme_string(vector(1,2,3))
→"vector(1,2,3)"
- latex(x)#
Mark string
x
as containing raw LaTeX, so when it’s included in a mathmode environment it doesn’t get wrapped in a\textrm
environment.If
x
is aexpression
value, it’s rendered to LaTeX.Note that backslashes must be double up, because the backslash is an escape character in JME strings.
- Definitions:
- Example:
latex('\\frac{1}{2}')
.latex(expression("x^2 + 3/4"))
→"x^{2} + \\frac{3}{4}"
- safe(x)#
Mark string
x
as safe: don’t substitute variable values into it when this expression is evaluated.Use this function to preserve curly braces in string literals.
- render(x, values)#
Substitute variable values into the string
x
, even if it’s marked as safe (seesafe
).The optional dictionary
values
overrides any previously-defined values of variables.- Definitions:
- Example:
render(safe("I have {num_apples} apples."), ["num_apples": 5])
→"I have 5 apples."
render(safe("Let $x = \\var{x}$"), ["x": 2])
→"Let $x = {2}$"
Note
The variable dependency checker can’t establish which variables will be used in the string until
render
is evaluated, so you may encounter errors if usingrender
in the definition of a question variable. You can ensure a variable has been evaluated by including it in thevalues
argument, e.g.:render("a is {}",["a": a])
This function is intended for use primarily in content areas.
- capitalise(x)#
Capitalise the first letter of a string.
- pluralise(n, singular, plural)#
Return
singular
ifn
is 1, otherwise returnplural
.
- upper(x)#
Convert string to upper-case.
- lower(x)#
Convert string to lower-case.
- join(strings, delimiter)#
Join a list of strings with the given delimiter.
- split(string, delimiter)#
Split a string at every occurrence of
delimiter
, returning a list of the the remaining pieces.
- match_regex(pattern, str, flags)#
If
str
matches the regular expressionpattern
, returns a list of matched groups, otherwise returns an empty list.This function uses JavaScript regular expression syntax.
flags
is an optional string listing the options flags to use. If it’s not given, the default value of"u"
is used.
- split_regex(string, pattern, flags)#
Split a string at every occurrence of a substring matching the given regular expression pattern, returning a list of the the remaining pieces.
flags
is an optional string listing the options flags to use. If it’s not given, the default value of"u"
is used.
- replace_regex(pattern, replacement, string, flags)#
Replace a substring of
string
matching the given regular expressionpattern
with the stringreplacement
.flags
is an optional string listing the options flags to use. If it’s not given, the default value of"u"
is used.Remember that backslashes must be doubled up inside JME strings, and curly braces are normally used to substitute in variables. You can use the
safe()
function to avoid this behaviour.To replace all occurrences of the pattern, add the flag
"g"
.- Definitions:
- Example:
replace_regex("day","DAY","Monday Tuesday Wednesday")
→"MonDAY Tuesday Wednesday"
replace_regex("day","DAY","Monday Tuesday Wednesday","g")
→"MonDAY TuesDAY WednesDAY"
replace_regex("a","o","Aardvark")
→"Aordvark"
replace_regex("a","o","Aardvark","i")
→"oardvark"
replace_regex("a","o","Aardvark","ig")
→"oordvork"
replace_regex(safe("(\\d+)x(\\d+)"),"$1 by $2","32x24")
→"32 by 24"
replace_regex(safe("a{2}"),"c","a aa aaa")
→"a c aaa"
- trim(str)#
Remove whitespace from the start and end of
str
.
- currency(n, prefix, suffix)#
Write a currency amount, with the given prefix or suffix characters.
- separateThousands(n, separator)#
Write a number, with the given separator character between every 3 digits
To write a number using notation appropriate to a particular culture or context, see
formatnumber
.
- unpercent(str)#
Get rid of the
%
on the end of a percentage and parse as a number, then divide by 100.
- lpad(str, n, prefix)#
Add copies of
prefix
to the start ofstr
until the result is at leastn
characters long.
- rpad(str, n, suffix)#
Add copies of
suffix
to the end ofstr
until the result is at leastn
characters long.
- formatstring(str, values)#
For each occurrence of
%s
instr
, replace it with the corresponding entry in the listvalues
.
- letterordinal(n)#
Get the \(n\)th element of the sequence
a, b, c, ..., aa, ab, ...
.Note that the numbering starts from 0.
- translate(str, arguments)#
Translate the given string, if it’s in the localisation file.
Look at the default localisation file for strings which can be translated. This function takes a key representing a string to be translated, and returns the corresponding value from the current localisation file.
arguments
is a dictionary of named substitutions to make in the string.
Logic#
- x<y#
Returns
true
ifx
is less thany
.
- x>y#
Returns
true
ifx
is greater thany
.
- x<=y#
Returns
true
ifx
is less than or equal toy
.
- x>=y#
Returns
true
ifx
is greater than or equal toy
.
- x<>y#
Returns
true
ifx
is not equal toy
. Returnstrue
ifx
andy
are not of the same data type.- Definitions:
anything, anything →
boolean
- Examples:
'this string' <> 'that string'
→true
1<>2
→true
'1' <> 1
→true
1 <> 1
→false
- x=y#
Returns
true
ifx
is equal toy
. Returnsfalse
ifx
andy
are not of the same data type.- Definitions:
anything, anything →
boolean
- Examples:
vector(1,2) = vector(1,2,0)
→true
4.0 = 4
→true
1/3 = 0.3
→false
- isclose(x, y[, rel_tol][, abs_tol])#
Returns
true
ifx
is close toy
.The arguments
rel_tol
andabs_tol
are optional, with default values of \(10^{-15}\).Equivalent to the following expression:
abs(x-y) <= max( rel_tol*max(abs(a),abs(b)), abs_tol )
- resultsequal(a, b, checkingFunction, accuracy)#
Returns
true
ifa
andb
are both of the same data type, and “close enough” according to the given checking function.Vectors, matrices, and lists are considered equal only if every pair of corresponding elements in
a
andb
is “close enough”.checkingFunction
is the name of a checking function to use. These are documented in the Numbas runtime documentation.
- x and y#
- x && y
- x & y
Logical AND. Returns
true
if bothx
andy
are true, otherwise returnsfalse
.
- not x#
Logical NOT.
- x or y#
- x || y
Logical OR. Returns
true
when at least one ofx
andy
is true. Returns false when bothx
andy
are false.
- x xor y#
Logical XOR. Returns
true
when at eitherx
ory
is true but not both. Returnsfalse
whenx
andy
are the same expression.
Collections#
- x[y]
Get the
y
th element of the collectionx
.For matrices, the
y
th row is returned.For dictionaries, the value corresponding to the key
y
is returned. If the key is not present in the dictionary, an error will be thrown.
- x[a..b]
- x[a..b#c]
Slice the collection
x
- return elements with indices in the given range. Note that list indices start at 0, and the final index is not included.
- x in collection
Is element
x
incollection
?- Definitions:
- Examples:
3 in [1,2,3,4]
→true
3 in (set(1,2,3,4) and set(2,4,6,8))
→false
"a" in ["a": 1]
→true
1 in ["a": 1]
throws an error because dictionary keys must be strings.
Ranges#
- a .. b#
Define a range. Includes all integers between and including
a
andb
.
- range # step#
Set the step size for a range. Default is 1. When
step
is 0, the range includes all real numbers between the limits.
- a except b#
Exclude a number, range, or list of items from a list or range.
- Definitions:
- Examples:
-2..2 except 0
→[-2,-1,1,2]
-9..9 except [-1,1]
3..8 except 4..6
[1,2,3,4,5] except [2,3]
Lists#
- repeat(expression, n)#
Evaluate
expression
n
times, and return the results in a list.
- all(list)#
Returns
true
if every element oflist
istrue
.
- some(list)#
Returns
true
if at least one element oflist
istrue
.
- map(anonymous_function, d)#
- map(expression,name[s],d)
Apply a transformation to each item in a list, range, vector or matrix.
You can either give an anonymous function (the neater way), or give an expression followed by a name to refer to the item being transformed.
You can also give a list of names if each element of
d
is a list of values. The Nth element of the list will be mapped to the Nth name.- Definitions:
- Examples:
map(x -> x+1, 1..3)
→[2,3,4]
map(x+1,x,1..3)
→[2,3,4]
map(s -> capitalise(s), ["jim","bob"])
→["Jim","Bob"]
map([x,y] -> sqrt(x^2+y^2), [ [3,4], [5,12] ])
→[5,13]
map(sqrt(x^2+y^2), [x,y], [ [3,4], [5,12] ])
→[5,13]
map(x -> x+1, id(2))
→matrix([2,1],[1,2])
map(x -> sqrt(x), vector(1,4,9))
→vector(1,2,3)
- expression for: name of: list where: condition#
This is similar to
map
andfilter
, with different syntax.Evaluate
expression
for each item inlist
, replacing variablename
with the element fromlist
each time.You can also give a list of names if each element of
d
is a list of values. The Nth element of the list will be mapped to the Nth name.You can chain several
for: ... of: ...
statements together to work over the Cartesian product of the given lists. Variables assigned by earlierfor:
statements are available in laterfor:
statements in the chain. Note that with bracketing you can change the shape of the resulting list.Each
for: ... of: ...
statement can be followed by an optionalwhere: condition
statement, restricting the values to be iterated over. Only values which satisfy the condition will be used.- Examples:
x^2 for: x of: 1..5
→[1, 4, 9, 16, 25]
(square the numbers 1 to 5)x for: x of: 1..10 where: mod(x,3)=0
→[3, 6, 9]
(find multiples of 3 between 1 and 10)log(x,b) for: [x,b] of: [[100,10], [16,2]]
→[2, 4]
(given pairs of numbers and bases, take the logarithm of each number with the corresponding base)[a,b] for: [a,b] of: zip(1..3, 4..6)
→[ [1,4], [2,5], [3,6] ]
(pair the numbers from the range1..3
and numbers from the range4..6
)[a,b] for: a of: 1..3 for: b of: 4..6
→[ [1,4], [1,5], [1,6], [2,4], [2,5], [2,6], [3,4], [3,5], [3,6] ]
(produce all possible pairs of numbers from the ranges1..3
and4.6
)mod(a,b) for: a of: 1..5 for: b of: [2,3]
→[1, 1, 0, 2, 1, 0, 0, 1, 1, 2]
(mod(a,b) for: a of: 1..5) for: b of: [2,3]
→[ [1,0,1,0,1], [1,2,0,1,2] ]
(mod(a,b) for: b of: [2,3]) for: a of: 1..5
→[ [1,1], [0,2], [1,0], [0,1], [1,2] ]
[x,y] for: x of: 1..3 for: y of: 1..x
→[ [1,1], [2,1] ,[2,2], [3,1], [3,2], [3,3] ]
[x,y] for: x of: 2..7 for: y of: (x+1)..7 where: gcd(x,y)=1
→[ [2,3], [2,5], [2,7], [3,4], [3,5], [3,7], [4,5], [4,7], [5,6], [5,7], [6,7] ]
(find coprime pairs of numbers between 2 and 7)[a,b,c] for: a of: 1..20 for: b of: 1..20 for: c of: 1..20 where: a<b<c and a^2+b^2 = c^2
→[ [ 3, 4, 5 ], [ 5, 12, 13 ], [ 6, 8, 10 ], [ 8, 15, 17 ], [ 9, 12, 15 ], [ 12, 16, 20 ] ]
(find Pythagorean triples with side lengths up to 20)[a,b,c] for: [a,b,c] of: product(1..20, 3) where: a<b<c and a^2+b^2 = c^2
→[ [ 3, 4, 5 ], [ 5, 12, 13 ], [ 6, 8, 10 ], [ 8, 15, 17 ], [ 9, 12, 15 ], [ 12, 16, 20 ] ]
(the same as above, but written more concisely)
- filter(anonymous_function, d)#
- filter(expression, name, d)
Filter each item in list or range
d
.You can either give an anonymous function (the neater way), or give an expression followed by a name to refer to the item being considered.
The returned value is a list containing values for which the function or expression evaluated to
true
.
- foldl(anonymous_function, first_value, d)#
- foldl(expression, accumulator_name, item_name, first_value, d)
Accumulate a value by iterating over a collection. This can be used as an abstraction of routines such as “sum of a list of numbers”, or “maximum value in a list”.
You can either give an anonymous function (the neater way), or give an expression followed by names to refer to the accumulated value and the item from the collection.
For each item in the list, range, vector or matrix
d
the function or expression is evaluated along with the accumulated value so far, ending up with a single value which is returned.At each iteration, the variable
item_name
is replaced with the corresponding value fromd
. The variableaccumulator_name
is replaced withfirst_value
for the first iteration, and the result ofexpression
from the previous iteration subsequently.- Definitions:
- Examples:
foldl((total, x) -> total + x, 0, [1,2,3])
→6
foldl(total + x, total, x, 0, [1,2,3])
→6
foldl((longest, x) -> if(len(x)>len(longest),x,longest), "", ["banana","pineapple","plum"])
→"pineapple"
- iterate(anonymous_function, initial, times)#
- iterate(expression, name, initial, times)
Iterate an expression on the given initial value the given number of times, returning a list containing the values produced at each step.
You can either give an anonymous function (the neater way), or give an expression followed by a name to refer to the current value.
- Definitions:
- Example:
iterate(x -> x+1, 0, 3)
→[0,1,2,3]
iterate(x+1, x, 0, 3)
→[0,1,2,3]
iterate([a,b] -> [b,a+b], [1,1], 3)
→[ [1,1], [1,2], [2,3], [3,5] ]
iterate(l -> l[1..len(l)]+[l[0]], ["a","b","c"], 3)
→[ ["a","b","c"], ["b","c","a"], ["c","a","b"], ["a","b","c"] ]
- iterate_until(iteration_function, initial, condition_function, max_iterations)#
- iterate_until(expression, name, initial, condition, max_iterations)
Iterate an expression on the given initial value until the condition is satisfied, returning a list containing the values produced at each step.
You can either give anonymous functions for the iteration function and condition, or give expressions and a name to use for the current value.
max_iterations
is an optional parameter specifying the maximum number of iterations that may be performed. If not given, the default value of 100 is used. This parameter prevents the function from running indefinitely, when the condition is never met.- Definitions:
- Example:
iterate_until(x -> if(mod(x,2)=0,x/2,3x+1), 5, x -> x=1)
→[ 5, 16, 8, 4, 2, 1 ]
iterate_until(if(mod(x,2)=0,x/2,3x+1), x, 5, x=1)
→[ 5, 16, 8, 4, 2, 1 ]
iterate_until([a,b] -> [b,mod(a,b)], [37,32], [a,b] -> b=0)
→[ [ 37, 32 ], [ 32, 5 ], [ 5, 2 ], [ 2, 1 ], [ 1, 0 ] ]
- take(n, condition_function, d)#
- take(n, expression, name, d)
Take the first
n
elements from list or ranged
which satisfy a condition.You can either give an anonymous function or an expression representing a condition and a name used to refer to the item being considered.
This operation is lazy - once
n
elements satisfying the expression have been found, execution stops. You can use this to filter a few elements from a large list, where the condition might take a long time to calculate.
- separate(list, x → :data:`boolean`)#
Sort each of the values in
list
into one of two lists, depending on whether they satisfy the condition. Values which satisfy the condition go into the first list; values which don’t satisfy it go in the second list.
- flatten(lists)#
“Flatten” a list of lists, returning a single list containing the concatenation of all the entries in
lists
.- Definitions:
list of list
→list
- Example:
flatten([ [1,2], [3,4] ])
→[1,2,3,4]
- let(name, definition, ..., expression)#
- let(definitions, expression)
Evaluate
expression
, temporarily defining variables with the given names. Use this to cut down on repetition. You can define any number of variables - in the first calling pattern, follow a variable name with its definition. Or you can give a dictionary mapping variable names to their values. The last argument is the expression to be evaluated.
- |>
a |> f()
is equivalent tof(a)
.This operator can be chained:
a |> f() |> g()
is equivalent tog(f(a))
.The “pipe” operator can be used to apply a sequence of transformations to a value.
The left-hand value
a
is inserted as the first argument of the right-hand functionf
.If
f
takes more than one argument, you must give the others on the right-hand side.- Definitions:
anything, anything → anything
- Examples:
2 |> sqrt() |> siground(2)
→1.4
["happy", "birthday"] |> join(" ") |> upper()
→"HAPPY BIRTHDAY"
- sort_destinations(x)#
Return a list giving the index that each entry in the list will occupy after sorting.
- sort_by(key, list)#
Sort the given list of either
list
ordict
values by their entries corresponding to the given key. When sorting a list of lists, the key is a number representing the index of each list to look at. When sorting a list of dictionaries, the key is a string.- Definitions:
- Examples:
sort_by(0, [[5,0], [3,2], [4,4]])
→[[3,2], [4,4], [5,0]]
sort_by("width", [["label": "M", "width": 20], ["label": "L", "width": 30], ["label": "S", "width": 10]])
→[["label": "S", "width": 10], ["label": "M", "width": 20], ["label": "L", "width": 30]]
- group_by(key, list)#
Group the entries in the given list of either
list
ordict
values by their entries corresponding to the given key. The returned value is a list of lists of the form[key, group]
, wherekey
is the value all elements of the listgroup
have in common.When grouping a list of lists, the
key
argument is a number representing the index of each list to look at. When grouping a list of dictionaries, thekey
argument is a string.- Definitions:
- Examples:
group_by(0, [[0,0], [3,2], [0,4]])
→[[0, [[0,0], [0,4]]], [3, [[3,2]]]]
group_by("a", [["a": 1, "b": "M"], ["a": 2, "b": "S"], ["a": 1, "b": "XL"]])
→[[1,[["a": 1, "b": "M"], ["a": 1, "b": "XL"]]], [2, [["a": 2, "b": "S"]]]]
- indices(list, value)
Find the indices at which
value
occurs inlist
.
- distinct(x)#
Return a copy of the list
x
with duplicates removed.
- list(x)
Convert a value to a list of its components (or rows, for a matrix).
- Definitions:
- Examples:
list(set(1,2,3))
→[1,2,3]
(note that you can’t depend on the elements of sets being in any order)list(vector(1,2))
→[1,2]
list(matrix([1,2],[3,4]))
→[[1,2], [3,4]]
- make_variables(definitions, vRange)#
Evaluate a dictionary of variable definitions and return a dictionary containing the generated values.
definitions
is a dictionary mapping variable names toexpression
values corresponding to definitions.The definitions can refer to other variables to be evaluated, or variables already defined in the current scope. Variables named in the dictionary which have already been defined will be removed before evaluation begins.
If the optional parameter
vRange
is given, then a variablevRange
is defined in the given scope with that value.- Definitions:
dict
ofexpression
,range
→dict
- Example:
make_variables(["a": expression("3"), "b": expression("a^2")])
→["a": 3, "b": 9]
make_variables(["a": expression("random(1..5)"), "b": expression("a^2")])
→["a": 3, "b": 9]
(other values can be produced)
- satisfy(names, definitions, conditions, maxRuns)#
Each variable name in
names
should have a corresponding definition expression indefinitions
.conditions
is a list of expressions which you want to evaluate totrue
. The definitions will be evaluated repeatedly until all the conditions are satisfied, or the number of attempts is greater thanmaxRuns
. IfmaxRuns
isn’t given, it defaults to 100 attempts.Note
This function is deprecated, and retained only for backwards compatibility. Use
make_variables
instead.
- sum(numbers)#
Add up a list of numbers
- prod(list)#
Multiply a list of numbers together
- product(list1, list2, ..., listN)#
Cartesian product of lists. In other words, every possible combination of choices of one value from each given list.
If one list and a number are given, then the
n
-th Cartesian power of the list is returned: the Cartesian product ofn
copies of the list.
- zip(list1, list2, ..., listN)#
Combine two (or more) lists into one - the Nth element of the output is a list containing the Nth elements of each of the input lists.
- combinations(collection, r)#
All ordered choices of
r
elements fromcollection
, without replacement.
- combinations_with_replacement(collection, r)#
All ordered choices of
r
elements fromcollection
, with replacement.
- permutations(collection, r)#
All choices of
r
elements fromcollection
, in any order, without replacement.
- frequencies(collection)#
Count the number of times each distinct element of
collection
appears.Returns a list of pairs
[value, frequency]
, wherevalue
is a value from the list, andfrequency
is the number of times it appeared.
- enumerate(collection)#
Enumerate the elements of
collection
: this function returns a list containing, for each elementv
ofcollection
, a new list of the form[i,v]
, wherei
is the index of the element incollection
.
Dictionaries#
- dict[key]
Get the value corresponding to the given key string in the dictionary
d
.If the key is not present in the dictionary, an error will be thrown.
- get(dict, key, default)#
Get the value corresponding to the given key string in the dictionary.
If the key is not present in the dictionary, the
default
value will be returned.
- dict(a:b, c:d, ...)
- dict(pairs)
Create a dictionary with the given key-value pairs. Equivalent to
[ .. ]
, except when no key-value pairs are given:[]
creates an empty list instead.You can alternately pass a list of pairs of the form
[key, value]
, to transform a list into a dictionary.- Definitions:
multiple
keypair
→dict
- Examples:
dict()
dict("a": 1, "b": 2)
dict([ ["a",1], ["b",2] ])
- keys(dict)#
A list of all of the given dictionary’s keys.
- values(dict[, keys])#
A list of the values corresponding to each of the given dictionary’s keys.
If a list of keys is given, only the values corresponding to those keys are returned, in the same order.
Sets#
- set(elements)
Create a set with the given elements. Either pass the elements as individual arguments, or as a list.
- union(a, b)#
Union of sets
a
andb
- intersection(a, b)#
Intersection of sets
a
andb
, i.e. elements which are in both sets.
- a - b
Set minus - elements which are in a but not b
- Example:
set(1,2,3,4) - set(2,4,6)
→set(1,3)
Randomisation#
- random(x)#
Pick uniformly at random from a range, list, or from the given arguments.
- weighted_random(x)#
Pick random from a weighted list of items. Each element in the input list is a pair of the form
[item, probability]
, whereprobability
is anumber
value.Items with negative weight are ignored.
- deal(n)#
Get a random shuffling of the integers \([0 \dots n-1]\)
- reorder(list, order)#
Reorder a list given a permutation. The
i``th element of the output is the ``order[i]``th element of ``list
.
- shuffle(x)#
Random shuffling of list or range.
- shuffle_together(lists)#
Shuffle several lists together - each list has the same permutation of its elements applied. The lists must all be the same length, otherwise an error is thrown.
Control flow#
- award(a, b)#
Return
a
ifb
istrue
, else return0
.
- if(p, a, b)#
If
p
istrue
, returna
, else returnb
. Only the returned value is evaluated.- Definitions:
boolean
, anything, anything → unspecified
- Example:
if(false,1,0)
→0
- switch(p1, a1, p2, a2, ..., pn, an, d)#
Select cases. Alternating boolean expressions with values to return, with the final argument representing the default case. Only the returned value is evaluated.
- Definitions:
multiple
boolean
,anything, anything → unspecified
- Examples:
switch(true,1,false,0,3)
→1
switch(false,1,true,0,3)
→0
switch(false,1,false,0,3)
→3
- assert(condition, value)#
If
condition
isfalse
, then returnvalue
, otherwise don’t evaluatevalue
and returnfalse
. This is intended for use in marking scripts, to apply marking feedback only if a condition is met.- Definitions:
boolean
, anything → unspecified
- Example:
assert(1 < 2, "oops")
→false
assert(1 > 2, "oops")
→"oops"
assert(studentAnswer<=0, correct("Student answer is positive"))
- try(expression, name, except)#
Try to evaluate
expression
. If it is successfully evaluated, return the result. Otherwise, evaluateexcept
, with the error message available asname
.- Definitions:
anything,
name
, anything → unspecified
- Examples:
try(eval(expression("x+")),err, "Error: "+err)
→"Error: Not enough arguments for operation <code>+</code>"
try(1+2,err,0)
→3
- a |> f()#
Insert the left-hand value
a
as the first argument of the right-hand functionf
. Several applications of this operator can be chained together, to make code that applies successive functions to a single value more readable.When the right-hand function has more than one argument, the left-hand value is inserted before the arguments you give, so
a |> f(b,c)
is equivalent tof(a,b,c)
.- Example:
3 |> sqrt() |> precround(2)
→1.73
HTML#
- isnonemptyhtml(str)#
Does
str
represent a string of HTML containing text? Returns false for the empty string, or HTML elements with no text content.
- table(data)#
- table(data, headers)
Create an HTML with cell contents defined by
data
, which should be a list of lists of data, and column headers defined by the list of stringsheaders
.
- image(url[, width][, height])#
Create an HTML
img
element loading the image from the given URL. Images uploaded through the resources tab are stored in the relative URLresources/images/<filename>.png
, where<filename>
is the name of the original file.The optional
width
andheight
parameters specify the size the image should be displayed at, in em units. If only the width is given, the height will be automatically set to maintain the image’s original proportions. 1 em is the width of the letter ‘m’.If neither width nor height are given, the image is displayed at its original size.
- Definitions:
- Examples:
image('resources/images/picture.png')
image(chosenimage)
- max_width(width, element)#
Apply a CSS
max-width
attribute to the given element. You can use this to ensure that an image is not displayed too wide. The givenwidth
is inem
units.
- max_height(width, element)#
Apply a CSS
max-height
attribute to the given element. You can use this to ensure that an image is not displayed too long. The givenheight
is inem
units.
JSON#
JSON is a lightweight data-interchange format. Many public data sets come in JSON format; it’s a good way of encoding data in a way that is easy for both humans and computers to read and write.
For an example of how you can use JSON data in a Numbas question, see the exam Working with JSON data.
- json_decode(json)#
Decode a JSON string into JME data types.
JSON is decoded into numbers, strings, booleans, lists, or dictionaries. To produce other data types, such as matrices or vectors, you will have to post-process the resulting data.
Warning
The JSON value
null
is silently converted to an empty string, because JME has no “null” data type. This may change in the future.- Definitions:
string
→ unspecified
- Example:
json_decode(safe(' {"a": 1, "b": [2,true,"thing"]} '))
→["a": 1, "b": [2,true,"thing"]]
Sub-expressions#
The expression
data type represents a JME expression.
You can use it to store and manipulate expressions symbolically, substituting in other variables before evaluating or displaying to the student.
There are functions to construct sub-expressions from strings of code, or by joining other sub-expressions together as the arguments to operators or functions.
Once you’ve got a sub-expression, you can evaluate it to a normal JME data type, test if it matches a pattern, substitute values or other sub-expressions for free variables, rearrange using simplification rules, or test if it is equivalent to another sub-expression.
- expression(string)
- parse(string)#
Parse a string as a JME expression. The expression can be substituted into other expressions, such as the answer to a mathematical expression part, or the
\simplify
LaTeX command.parse(string)
is a synonym forexpression(string)
.Warning
Note that the argument to
expression
is evaluated using the same rules as any other JME expression, so for exampleexpression("2" + "x")
is equivalent toexpression("2x")
, notexpression("2 + x")
. A good way to construct a randomised sub-expression is usingsubstitute()
.- Definitions:
- Example:
- eval(expression, values)#
Evaluate the given sub-expression.
If
values
is given, it should be a dictionary mapping names of variables to their values.- Definitions:
expression
→ unspecifiedexpression
,dict
→ unspecified
- Example:
eval(expression("1+2"))
→3
eval(expression("x+1"), ["x":1])
→2
- args(expression)#
Returns the arguments of the top-level operation of
expression
, as a list of sub-expressions. Ifexpression
is a data type other than an operation or function, an empty list is returned.Binary operations only ever have two arguments. For example,
1+2+3
is parsed as(1+2)+3
.- Definitions:
- Examples:
args(expression("f(x)"))
→[expression("x")]
args(expression("1+2+3"))
→[expression("1+2"), expression("3")]
args(expression("1"))
→[]
- type(expression)#
Returns the name of the data type of the top token in the expression, as a string.
- Definitions:
- Examples:
type(expression("x"))
→"name"
type(expression("1"))
→"integer"
type(expression("x+1"))
→"op"
type(expression("sin(x)"))
→"function"
- name(string)
Construct a
name
token with the given name.
- function(name)
Construct a function token with the given name.
- Definitions:
string
→func
- Example:
function("sin")
→sin
- exec(op, arguments)#
Returns a sub-expression representing the application of the given operation to the list of arguments.
- Definitions:
op
,list
→expression
- Example:
exec(op("+"), [2,1])
→expression("2+1")
exec(op("-"), [2,name("x")])
→expression("2-x")
- findvars(expression)#
Return a list of all unbound variables used in the given expression. Effectively, this is all the variables that need to be given values in order for this expression to be evaluated.
Bound variables are those defined as part of operations which also assign values to those variables, such as
map
orlet
.- Definitions:
- Examples:
findvars(expression("x+1"))
→["x"]
findvars(expression("x + x*y"))
→["x","y"]
findvars(expression("map(x+2, x, [1,2,3])"))
→[]
- substitute(variables, expression)#
Substitute the given variable values into
expression
.variables
is a dictionary mapping variable names to values.- Definitions:
- Examples:
substitute(["x": 1], expression("x + y"))
→expression("1 + y")
substitute(["x": 1, "y": expression("sqrt(z+2)")], expression("x + y"))
→expression("1 + sqrt(z + 2)")
- simplify(expression, rules)#
Apply the given simplification rules to
expression
, until no rules apply.rules
is a list of names of rules to apply, given either as a string containing a comma-separated list of names, or a list of strings.Unlike the
\\simplify
command in content areas, thebasic
rule is not turned on by default.See Substituting variables into displayed maths for a list of rules available.
- Definitions:
- Examples:
simplify(expression("1*x+cos(pi)"),"unitfactor")
→expression("x+cos(pi)")
simplify(expression("1*x+cos(pi)"),["basic","unitfactor","trig"])
→expression("x-1")
- expand_juxtapositions(expression, options)#
Expand juxtapositions in variable and function names for implicit multiplication of terms or composition of functions. This is to do with strings of letters with no spaces or operator symbols between them.
options
is an optional dictionary of settings for the process. It can contain the following keys.singleLetterVariables
- Insist that all variable names consist of a single letter, interpreting longer strings of characters as implicit multiplication.Greek letters are considered to be one letter long.
noUnknownFunctions
- When a name appears before a bracket, but it’s not the name of a defined function, interpret it as a multiplication instead. This does not apply function applications with more than one argument.implicitFunctionComposition
- When several function names are juxtaposed together to form a string that is not the name of a defined function, or several function names are joined with the multiplication symbol*
, interpret it as implicity composition of functions.
If
options
is not given, all of these are turned on.Variable name annotations, subscripts and primes do not count towards the number of letters in a name.
- Definition:
- Examples:
expand_juxtapositions(expression("xy"))
→expression("x*y")
expand_juxtapositions(expression("x'y"))
→expression("x\'*y")
expand_juxtapositions(expression("pizza"))
→expression("pi*z*z*a")
expand_juxtapositions(expression("hat:abc"))
→expression("hat:a*b*c")
expand_juxtapositions(expression("xcos(x)"))
→expression("x*cos(x)")
expand_juxtapositions(expression("lnabs(x)"))
→expression("ln(abs(x))")
expand_juxtapositions(expression("ln*abs(x)"))
→expression("ln(abs(x))")
expand_juxtapositions(expression("xy"),["singleLetterVariables": false])
→expression("xy")
expand_juxtapositions(expression("x(x+1)"))
→expression("x*(x+1)")
expand_juxtapositions(expression("x(x+1)"),["noUnknownFunctions": false])
→expression("x(x+1)")
expand_juxtapositions(expression("ln*abs(x)"),["implicitFunctionComposition": false, "singleLetterVariables": true, "noUnknownFunctions": true])
→expression("l*n*abs(x)")
expand_juxtapositions(expression("xy^z"))
→expression("x*y^z")
expand_juxtapositions(expression("xy!"))
→expression("x*y!")
- canonical_compare(expr1, expr2)#
Compare expressions
a
andb
using the “canonical” ordering. Returns-1
ifa
should go beforeb
,0
if they are considered “equal”, and1
ifa
should go afterb
.Expressions are examined in the following order:
Names used: all variable names used in each expression are collected in a depth-first search and the resulting lists are compared lexicographically.
Data type: if
a
andb
are of different data types,op
andfunction
go first, and then they are compared using the names of their data types.Polynomials: terms of the form
x^b
ora*x^b
, wherea
andb
are numbers andx
is a variable name, go before anything else.Function name: if
a
andb
are both function applications, they are compared using the names of the functions. If the functions are the same, the arguments are compared. Powers, or multiples of powers, go after anything else.Number: if
a
andb
are both numbers, the lowest number goes first. Complex numbers are compared by real part and then by imaginary part.Elements of other data types are considered to be equal to any other value of the same data type.
- Definitions:
anything, anything →
number
- Examples:
canonical_compare(a,b)
→-1
canonical_compare(f(y),g(x))
→1
canonical_compare(f(x),g(x))
→-1
canonical_compare("a","b")
→0
- numerical_compare(a, b)#
Compare expression
a
andb
by substituting random values in for the free variables.Returns
true
ifa
andb
have exactly the same free variables, and produce the same results when evaluated against the randomly chosen values.For more control over the evaluation, see
resultsequal()
.- Definitions:
- Example:
numerical_compare(expression("x^2"), expression("x*x"))
→true
numerical_compare(expression("x^2"), expression("2x"))
→false
numerical_compare(expression("x^2"), expression("y^2"))
→false
- scope_case_sensitive(expression[, case_sensitive])#
Set the evaluation scope to be case-sensitive or not, depending on the value of
case_sensitive
, and then evaluateexpression
.If
case_sensitive
is not given, it defaults totrue
.Case-sensitivity affects variable and function names. The names
x
andX
are considered equivalent when not in case-sensitive mode, but are considered to be different when in case-sensitive mode.- Definitions:
expression
,boolean
→ unspecified
- Example:
scope_case_sensitive(findvars(expression("x+X")))
→["X","x"]
scope_case_sensitive(let(x,1,X,2,x+X), true)
→3
Calculus#
- diff(expression, variable)#
Differentiate the given expression with respect to the given variable name
- Definitions:
- Example:
diff(expression("x^2 + 2x + 4"), "x")
→expression("2x + 2")
diff(expression("x * y + 3x + 2y"), "x")
→expression("y + 3")
diff(expression("cos(x^2)"), "x")
→expression("-2 * sin(x^2) * x")
Pattern-matching sub-expressions#
- match(expr, pattern, options)#
If
expr
matchespattern
, return a dictionary of the form["match": boolean, "groups": dict]
, where"groups"
is a dictionary mapping names of matches to sub-expressions.See the documentation on pattern-matching mathematical expressions.
If you don’t need to use any parts of the matched expression, use
matches
instead.- Definitions:
expression
,string
→dict
expression
,string
,string
→dict
- Examples:
match(expression("x+1"),"?;a + ?;b")
→["match": true, "groups": ["a": expression("x"), "b": expression("1"), "_match": expression("x+1")]]
match(expression("sin(x)"), "?;a + ?;b")
→["match": false, "groups": dict()]
match(expression("x+1"),"1+?;a")
→["match": true, "groups": ["a": expression("x"), "_match": expression("x+1")]]
- matches(expr, pattern, options)#
Return
true
ifexpr
matchespattern
.Use this if you’re not interested in capturing any parts of the matched expression.
- Definitions:
- Examples:
matches(expression("x+1"),"?;a + ?;b")
→true
matches(expression("sin(x)"), "?;a + ?;b")
→false
- replace(pattern, replacement, expr)#
Replace occurrences of
pattern
inexpr
with the expression created by substituting the matched items intoreplacement
.- Definitions:
- Examples:
replace("?;x + ?;y", "x*y", expression("1+2"))
→expression("1*2")
replace("?;x + ?;y", "f(x,y)", expression("1+2+3"))
→expression("f(f(1,2),3)")
replace("0*?", "0", expression("0*sin(x) + x*0 + 2*cos(0*pi)"))
→expression("0 + 0 + 2*cos(0)")
Identifying data types#
- type(x)
Returns the name of the data type of
x
.- Example:
type(1)
→"integer"
- x as type#
Convert
x
to the given data type, if possible.If
x
can not be automatically converted totype
, an error is thrown.- Definitions:
anything,
string
→ given type
- Examples:
dec(1.23) as "number"
→1.23
set(1,2,3) as "list"
→[1,2,3]
- infer_variable_types(expression)#
Attempt to infer the types of free variables in the given expression.
There can be more than one valid assignment of types to the variables in an expression. For example, in the expression
a+a
, the variablea
can be any type which has a defined addition operation.Returns the first possible assignment of types to variables, as a dictionary mapping variable names to the name of its type. If a variable name is missing from the dictionary, the algorithm can’t establish any constraint on it.
- Definitions:
- Examples:
infer_variable_types(expression("x^2"))
→["x": "number"]
infer_variable_types(expression("union(a,b)"))
→["a": "set", "b": "set"]
infer_variable_types(expression("k*det(a)"))
→[ "k": "number", "a": "matrix" ]
- infer_type(expression)#
Attempt to infer the type of the value produced by the given expression, which may contain free variables.
First, the types of any free variables are inferred. Then, definitions of an operations or functions in the function are chosen to match the types of their arguments.
Returns the name of the expression’s output type as a string, or
"?"
if the type can’t be determined.- Definitions:
- Examples:
infer_type(expression("x+2"))
→"number"
infer_type(expression("id(n)"))
→"matrix"
infer_type(expression("random(2,true)"))
→"?"
Inspecting the evaluation scope#
- definedvariables()#
Returns a list containing the names of every variable defined in the current scope, as strings.
- Definitions:
() →
list
- isset(name)#
Returns
true
if the variable with the given name has been defined in the current scope.