Skip to content

Authoring validation errors

This document aims to explain certain errors that may appear during authoring, specifically during validation/saving of a question. We are constantly improving the error trapping for question authors and so some of these errors might be new and appear during upgrades, and break, previously functional materials.

In some cases we have good reasons for now preventing actions which may have been permitted in the past. For some situations one can do things differently to lift the suspicions of the validation system.

Summary of advice.

  1. Do not attempt to redefine function names or constants which are already defined as part of Maxima.
  2. Avoid using the same name for functions and variables.
  3. Avoid complex substitutions.
  4. Do not attempt to redefine the variables which are the names of inputs.

Forbidden functions and variables

Some functions affecting the underlying system are forbidden to protect the environment, others are forbidden due to excessive load, and finally some have been disabled due to the way they return their values. Likewise, some variables/constants representing the state of the underlying system have been either marked as forbbiden to access or to modify. Use other names if this was just a collision of identifiers, otherwise this is just the way it is.

Redefining internal-functions

Some functions are part of the core functionality and the system relies on their behaviour. For example redefining what append() does for lists would have significant effects around the system, this is why (re)defining functions with some specific names is forbidden. You are free to use other names for your functions. Note that not all internal functions or functions they use are blocked by this, they might get blocked in the future or some might be left as something that can be redefined to tune the logic.

We suggest you do not attempt to redefine function names or constants which are already defined as part of Maxima.

Substitutions unclear or otherwise

Should you do substitutions of values in your code and the target of the substitution is an identifier that is later used as a function-name, things may become difficult. Avoid using the same name for functions and variables. Also if you use complex means to construct the substitutions themselves the system may need to assume that all possible identifiers in the expression that the substitutions are applied to are being targetted by unknown values, this can be avoided by avoiding complex construction of the substs itself.

Example

v:1; /* particular case of rand([1,2]) */
trig:[sin,cos][v];
sub:[(sin(x))^2=1-(cos(x))^2,(cos(x))^2=1-(sin(x))^2][v];
f:(trig(x))^3;
df:diff(f,x);
df_simp:subst(sub,df);

This produces the error message

The function name "sin" is potentially redefined in unclear substitutions. The function name "diff" is potentially redefined in unclear substitutions.

The issue is that sub is a complicated expression here, so the validation system is not able to check that this code is not doing something suspicious.

It may be worth trying to use ev rather than subst - for this example, the question works again if we change the final line to the following:

df_simp:ev(df, sub);

Use of the students answer

Since 4.3 you have been forbidden from writing to the variable storing the students answer, feel free to simply store whatever you wanted to store in any other valid variable. You are now also forbidden from using the students input directly as a function-name, if you need to do so rewrite the logic as a "switch", unfortunately this also applies to MCQ inputs:

/* Not like this. */
val: ans1(4);

/* Instead write it like this to restrict the set of possible names. */
if is(ans1=sqrt) then
 val: sqrt(4)
else if(ans1=sin) then
 val: sin(4)
...

Some recomendations

The validation of certain things evaluates dependency graphs of identifiers so if you can keep those graphs small things tend to work faster. To do so avoid redefining the same variable if at all possible and just create a new variable when needed, i.e. do not reuse some tmp-var for all the calculations, if you do then the graph of that variable will become quite large and that may slow things down. Many small graphs tend to be faster to deal with than few large ones and a large graph may mean that features of node in the graph may block other nodes from doing certain things, e.g. being used as function identifiers.

Likewise, avoid reusing same variable names for multiple different types of things in the question, i.e. if A is a matrix let it stay as such and don't turn it into a list or a function if you wish the validation during saving and first execution after import/upgrade to be fast.

If you are using local() to define local-scope variables always call it as the first thing in a block (if you use the list of identifiers logic then you should not use local() in the same block) or in a lambda (after arguments). This allows the graph building to identify the point of disconnection of the graphs and to separate the scopes. Calling local after any variables have been used will confuse the logic and we do not want to invest into dealign with that special case.