Skip to main content

Grading functions

WirisQuizzes provides a wide range of options for comparing the student's answer to the correct answer when you edit a question. These involve decimal digits, units, simplification, etc. (everything in the Validation options section). However, sometimes we will find that it's necessary to create our own rule for determining when an answer is correct. This can be done via grading functions. A grading function is a user-defined formula that takes the student's response and decides whether it is accurate or not. This allows for even more specificity than the Validation options section options.

Basic grading function

Let's suppose that we want to ask the question "Give a prime number". For this, we need to use a grading function.

First, let's create the grading function. This is done in the Define random variables and functions section. In this example, the grading function will be called gfgf.


The function we've defined, gf(x)gf(x), returns true if xx is prime and false otherwise. Select Custom grading function in the Validation options section to use this as the validation method. Then, use the name of the grading function in the blank, in this case, "gf".



As you may notice, you can also define how the student's answer will be passed to the grading function. This is an advanced feature for which you can find more details in the two latest sections of this documentation page. Most user cases will require leaving the default value: Evaluated.

As for the Correct answer blank, anything will work. Since we've selected Custom grading function as the validation method, the output of the grading function is the only thing that determines correct answers. In this case, we could input a prime number, for example.

Custom marks

We'll show a simple example of a grading function with several outputs. The idea will be to award more marks for every level of correctness in the answer.

We want to ask the following question in basic arithmetic:


With partial credit awarded for each correct property of the student's answer. Say these are young children, and we consider the most challenging part to correctly give a number whose remainder is 2 when divided by 7. We'll award 0.4 marks for that and 0.3 for each of the other properties. Additionally, we only want to give half marks for the rest of the properties if the answer falls in the first one (the purpose of decrease_mark).


Observe that to make a more extended grading function with multiple conditionals and calculations; we must enclose it with the begin..end statements and use return to define the function's output.

The question is completed now. Make sure to tick the "grading function" option in the Validation options section as described earlier, and give any particular correct value in the Correct Answer blank. We can see that both of these responses are correct:


We've used a relatively simple question as an example, but we can already see that grading functions can be made to have a very customized and complex design.

Compound answers

We can also create grading functions in the case of compound answer questions. All we need to do is use a separate argument for each answer blank. So, if there are three blanks to fill in, the grading function should look like gf(x,y,z). The first argument corresponds to the first blank, and the second argument corresponds to the second blank, etc. Let's see a simple example.

The question will be a standard exercise in introductory calculus:


For this, the following grading function could be used:


As opposed to ordinary compound answers, the advantage, in this case, is that we don't need to worry about the order in which the student answers. It also allows virtually infinite answers (here, any solution of the form 8k+18k+1 with kk an integer was valid). However, much more complex behaviour can be programmed, as is easily readily

Empty answer from the student

Imagine that we are working with a compound answer like in the previous example. The student might leave a box empty and just answer some questions, which could crash the validation algorithm, resulting in all grades being 0 even if some were correct.

If you want to grade the answers he had submitted, you need to modify the algorithm and test that all boxes are not empty with the command not_null?. For instance, following the same example above, the algorithm should be as follows.



The not_null? is a precaution you need to use if you want to do something complex with your answer that might crash the program if the response were null. If you are making simple comparisons, you technically don't need it, but we strongly recommend systematically including it to avoid undesired situations.

Answering vectors

It's essential to read this section if you wish to create questions involving vectors. The critical point is that vectors are passed to the grading function as matrices, so we need to de-index them inside the function body to do normal vector operations with them. This should all be clear with the following basic example.

What this all essentially means is that if we pass [...] to a grading function, it will be taken as [ [...] ] (a list with the original vector as its only element). As a result, we cannot do vector operations with it. For example, the vector


will be converted to


How do we access the original vector? It is the first (and only) element of a list, so as with any list, we may access the first element with the subindex "1", as so:


So if "v" was the original vector given by the student and passed to the grading function, to treat it as a vector, we simply need to write "v1" wherever we would like to use "v". Let's look at this with some examples.

Example 1


The matrix has rank 2, so there will be infinite solutions, meaning that we have to use a grading function if we want to allow any possible solution. The procedure itself is pretty simple, but observe that we used the subindex as described above:


The other case we need to cover is allowing students to answer with a row or column vectors (until now, we've only assumed row vectors). We'll illustrate what needs to be done with an example. Using the same question as before, let's say the student responds like so:


This is a column vector, and it is treated differently. All we need to do, though, is transpose it, and we are back to the previous case. We most likely want to allow both types of answers, so at the beginning of the original grading function, we might add the following:


We've added an if statement that simply detects if the input is a column vector (by seeing if the number of columns is 1) and transposes it in that case. If not, then nothing is done to "v". The result is that in all circumstances ", v" will be of the form [ [...] ], and after that, we can use subindices precisely as described previously.

Example 2

Imagine we want to ask the students the following question:


This example clearly needs a grading function since there are infinite correct answers.

The first answer is a point, but it is understood as a matrix as before. We need to specify the corresponding element is a point and check whether it belongs to the corresponding line or not. The first part of the grading function would be:


The second answer is a vector and is also understood as a matrix. Similarly, we have to access its first row with a grading function as the following:


Student's answers to the same question

Another feature approach is using the student's answer in a later part of the question. For instance, imagine you want to ask the following question:


If a student gets the original line wrong, you may be interested in providing a partial grade if he uses the wrong answer correctly to get the perpendicular gradient. To do so, you need to create a grading function. The CalcMe algorithm must be something as follows:


Thus, perpendicular lines passing through the corresponding point will be accepted even though the original line didn't match the initial requirements.


Keep arguments unevaluated

Let's suppose that you need to create a grading fraction (for any of the aforementioned reasons), but you still want to check the form of the provided answers. By default, WirisQuizzes will take the values the student answered and evaluate them to their simplified form.

Imagine that, given an irreducible fraction, we want the student to answer with an equivalent fraction. We will also need a grading function to create this kind of question, as there are an infinite number of possible correct answers. Besides, since we want the student's answer to be interpreted as written, we may select Unevaluated , so the evaluation system considers the fraction without simplifying.


The corresponding grading function will be called gf . It will give the entire grade if the student answers with a fraction mathematically equal to the statement's one, f, and the corresponding fractions are not simplified.



Notice that you have to check if the student's answer is simplified or not using the command _check_simplified(x). You can find a complete guide about this particular notation for non-evaluated objects here. If you have any questions about it, you can contact our support team at

Thus, we will be able to answer with any equivalent fraction, and it will be accepted as correct.


Keep arguments as strings

As mentioned in the previous section, it's possible to transfer all the assertions you can handle inside WirisQuizzes Studio to a grading function. You just need to select the Unevaluated option and use the corresponding notation.

Unfortunately, there is one exception regarding this transfer process. To track trailing zeros, the Precision assertion needs to transfer the student's answer as a string.


Thus, you will need to select the String in case you want to create a grading function where checking the number of significant figures or decimal places is required. Let's imagine, with a formative perspective, that we want only to accept answers with a random absolute error and between 2 and 4 significant figures.

The corresponding grading function will require the student's answer to satisfy the error condition to receive some grade, which will only be the full mark if it also has between 2 and 4 significant figures.



Notice there are two particularities regarding the notation in this type of grading function:

  • As the student's answer is transferred as a string, we need to evaluate it before comparing it with another value. We need to use the expression() command for this purpose.

  • The _check_precision() command requires four arguments: the student's answer, the minimum and maximum number of significant figures or decimal values the answer must have, and a boolean to indicate if we want to check significant figures (true) or decimal places (false). You can see more details here.

Thus, we will be able to answer with any value inside the acceptance interval between 2 and 4 significant figures.