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.
- Do not attempt to redefine function names or constants which are already defined as part of Maxima.
- Avoid using the same name for functions and variables.
- Avoid complex substitutions.
- 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.
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.
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:
solution : rhs(ode2(eqn,y,x)); vars : delete(x,listofvars(solution)); TAns11 : subst([vars=A,vars=B],solution); TAns12 : subst([vars=A,vars=B],solution);
Here the error messsages will claim that pretty much everything that goes into
solution is potentially redefined in unclear substitutions. What the code above does is that it solves a differential equation with CAS and then asks the CAS for the names of the constants being used. Depending on the shape of the equation there might be more than one but in this case there are always exactly two of them.
%k2, if there were only one it would probably get called
%c so there is a reason for checking what they are.
Why the example asks for those constants names is because the author has chosen to force the student to use
B as the constants and constructs different correct answers for the two ways of selecting the order of the constants. The problem arises from the substitution of the constants which now finds the names of them from a list (
vars) that is not directly visible to the validation system. There are two ways forward from this. Firstly, the question could use the SubstEquiv test that allows any names for those constants to be used and then just confirms that the correct ones were used if that matters, however then the teachers answer might look silly with those CAS-style constants so you would still need to replace them. Secondly, one can hard-code the names of the constants, in this case they are always the same so that should not be a problem:
solution : rhs(ode2(eqn,y,x)); TAns11 : subst([%k1=A,%k2=B],solution); TAns12 : subst([%k2=A,%k1=B],solution);
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) ...
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
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
(after arguments). This allows the graph building to identify the point of
disconnection of the graphs and to separate the scopes. Calling
after any variables have been used will confuse the logic and we do not
want to invest into dealign with that special case.