From ff638f0c307844f0e8e822a6dd942be9db5d807d Mon Sep 17 00:00:00 2001 From: Lennart Kramer <lennart.kramer@stud.uni-goettingen.de> Date: Wed, 29 Jul 2020 17:02:52 +0200 Subject: [PATCH] use per-version maximalocal --- .gitignore | 2 + Dockerfile | 10 +- stack/2014083000/maxima/arccos.lisp | 51 - stack/2014083000/maxima/assessment.mac | 757 ------ stack/2014083000/maxima/assessment.texi | 568 ---- stack/2014083000/maxima/complexi.lisp | 10 - stack/2014083000/maxima/complexj.lisp | 10 - stack/2014083000/maxima/cos-1.lisp | 51 - stack/2014083000/maxima/elementary.mac | 477 ---- stack/2014083000/maxima/expandfeedback.mac | 139 - stack/2014083000/maxima/experimental.mac | 298 --- stack/2014083000/maxima/mathml.lisp | 762 ------ stack/2014083000/maxima/multiply_cross.lisp | 6 - stack/2014083000/maxima/multiply_dot.lisp | 6 - stack/2014083000/maxima/noun_arith.lisp | 28 - .../maxima/rtest_assessment_simpboth.mac | 297 --- .../maxima/rtest_assessment_simpfalse.mac | 121 - .../maxima/rtest_assessment_simptrue.mac | 20 - stack/2014083000/maxima/rtest_elementary.mac | 179 -- .../2014083000/maxima/rtest_experimental.mac | 104 - stack/2014083000/maxima/stackmaxima.mac | 2293 ----------------- stack/2014083000/maxima/stackreporting.mac | 27 - stack/2014083000/maxima/stacktex.lisp | 181 -- stack/2014083000/maxima/unittests_load.mac | 49 - stack/2017121800/maximalocal.mac.template | 41 + stack/2018030500/maximalocal.mac.template | 41 + stack/2018080600/maximalocal.mac.template | 41 + stack/2019090200/maximalocal.mac.template | 41 + stack/2020042000/maximalocal.mac.template | 41 + stack/2020052700/maximalocal.mac.template | 41 + stack/2020061000/maximalocal.mac.template | 41 + .../2020070100}/maximalocal.mac.template | 4 +- 32 files changed, 299 insertions(+), 6438 deletions(-) delete mode 100644 stack/2014083000/maxima/arccos.lisp delete mode 100644 stack/2014083000/maxima/assessment.mac delete mode 100644 stack/2014083000/maxima/assessment.texi delete mode 100644 stack/2014083000/maxima/complexi.lisp delete mode 100644 stack/2014083000/maxima/complexj.lisp delete mode 100644 stack/2014083000/maxima/cos-1.lisp delete mode 100644 stack/2014083000/maxima/elementary.mac delete mode 100644 stack/2014083000/maxima/expandfeedback.mac delete mode 100644 stack/2014083000/maxima/experimental.mac delete mode 100644 stack/2014083000/maxima/mathml.lisp delete mode 100644 stack/2014083000/maxima/multiply_cross.lisp delete mode 100644 stack/2014083000/maxima/multiply_dot.lisp delete mode 100644 stack/2014083000/maxima/noun_arith.lisp delete mode 100644 stack/2014083000/maxima/rtest_assessment_simpboth.mac delete mode 100644 stack/2014083000/maxima/rtest_assessment_simpfalse.mac delete mode 100644 stack/2014083000/maxima/rtest_assessment_simptrue.mac delete mode 100644 stack/2014083000/maxima/rtest_elementary.mac delete mode 100644 stack/2014083000/maxima/rtest_experimental.mac delete mode 100644 stack/2014083000/maxima/stackmaxima.mac delete mode 100644 stack/2014083000/maxima/stackreporting.mac delete mode 100644 stack/2014083000/maxima/stacktex.lisp delete mode 100644 stack/2014083000/maxima/unittests_load.mac create mode 100644 stack/2017121800/maximalocal.mac.template create mode 100644 stack/2018030500/maximalocal.mac.template create mode 100644 stack/2018080600/maximalocal.mac.template create mode 100644 stack/2019090200/maximalocal.mac.template create mode 100644 stack/2020042000/maximalocal.mac.template create mode 100644 stack/2020052700/maximalocal.mac.template create mode 100644 stack/2020061000/maximalocal.mac.template rename {assets => stack/2020070100}/maximalocal.mac.template (97%) diff --git a/.gitignore b/.gitignore index 19fa632..fa44107 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ Sessionx.vim tags # Persistent undo [._]*.un~ + +bin diff --git a/Dockerfile b/Dockerfile index d7f6a36..8a1d927 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ COPY ./buildscript.sh / RUN bash /buildscript.sh -# e.g. assStackQuestion/classes/stack/maxima +# e.g. stack/20200701/maxima ARG LIB_PATH RUN echo ${LIB_PATH?Error \$LIB_PATH is not defined} @@ -26,7 +26,7 @@ RUN echo ${LIB_PATH?Error \$LIB_PATH is not defined} COPY ${LIB_PATH} ${LIB} # Copy optimization scripts -COPY assets/maxima-fork.lisp assets/optimize.mac.template assets/maximalocal.mac.template ${ASSETS}/ +COPY assets/maxima-fork.lisp assets/optimize.mac.template ${LIB_PATH}/../maximalocal.mac.template ${ASSETS}/ RUN grep stackmaximaversion ${LIB}/stackmaxima.mac | grep -oP "\d+" >> /opt/maxima/stackmaximaversion \ && sh -c 'envsubst < ${ASSETS}/maximalocal.mac.template > ${ASSETS}/maximalocal.mac \ @@ -43,5 +43,11 @@ RUN grep stackmaximaversion ${LIB}/stackmaxima.mac | grep -oP "\d+" >> /opt/maxi COPY ./bin/web ${BIN}/goweb ENV GOEMAXIMA_LIB_PATH=/opt/maxima/assets/maximalocal.mac +ENV LANG C.UTF-8 +EXPOSE 80 + +# rm /dev/tty because we do not want it to be opened by maxima for security reasons, +# and clear tmp because when kubernetes restarts a pod, it keeps the /tmp content even if it's tmpfs, +# which means that on a restart caused by an overfull tmpfs, it will keep restarting in a loop CMD rm /dev/tty && cd /tmp && rm --one-file-system -rf * && exec tini ${BIN}/goweb ${BIN}/maxima-optimised diff --git a/stack/2014083000/maxima/arccos.lisp b/stack/2014083000/maxima/arccos.lisp deleted file mode 100644 index 963ff6b..0000000 --- a/stack/2014083000/maxima/arccos.lisp +++ /dev/null @@ -1,51 +0,0 @@ -(mapc #'tex-setup - '( - (%acos "\\arccos ") - (%asin "\\arcsin ") - (%atan "\\arctan ") - ; Latex's arg(x) is ... ? - (%cos "\\cos ") - (%cosh "\\cosh ") - (%cot "\\cot ") - (%coth "\\coth ") - (%csc "\\csc ") - ; Latex's "deg" is ... ? - (%determinant "\\det ") - (%dim "\\dim ") - (%exp "\\exp ") - (%gcd "\\gcd ") - ; Latex's "hom" is ... ? - (%inf "\\inf ") ; many will prefer "\\infty". Hmmm. - ; Latex's "ker" is ... ? - ; Latex's "lg" is ... ? - ; lim is handled by tex-limit. - ; Latex's "liminf" ... ? - ; Latex's "limsup" ... ? - (%ln "\\ln ") - (%log "\\ln ") - (%max "\\max ") - (%min "\\min ") - ; Latex's "Pr" ... ? - (%sec "\\sec ") - (%sin "\\sin ") - (%sinh "\\sinh ") - ; Latex's "sup" ... ? - (%tan "\\tan ") - (%tanh "\\tanh ") - ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual - ;(%laplace "{\\cal L}") - - ; Maxima built-in functions which do not have corresponding TeX symbols. - (%asec "{\\rm arcsec}") - (%acsc "{\\rm arccsc}") - (%acot "{\\rm arccot}") - (%sech "{\\rm sech}") - (%csch "{\\rm csch}") - (%asinh "{\\rm arcsinh}") - (%acosh "{\\rm arccosh}") - (%atanh "{\\rm arctanh}") - (%asech "{\\rm arcsech}") - (%acsch "{\\rm arccsch}") - (%acoth "{\\rm arccoth}") -)) ;; etc - diff --git a/stack/2014083000/maxima/assessment.mac b/stack/2014083000/maxima/assessment.mac deleted file mode 100644 index 24ebb7e..0000000 --- a/stack/2014083000/maxima/assessment.mac +++ /dev/null @@ -1,757 +0,0 @@ -/* Author Chris Sangwin - Loughborough University - Copyright (C) 2014 Chris Sangwin - - This program is free software: you can redistribute it or modify - it under the terms of the GNU General Public License version two. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - - -/****************************************************************/ -/* An assessment package for Maxima */ -/* */ -/* Chris Sangwin, <chris@sangwin.com> */ -/* V0.6 September 2014 */ -/* */ -/****************************************************************/ - -MAXIMA_VERSION:map(parse_string, tokens(?\*autoconf\-version\*, 'digitcharp))$ -MAXIMA_VERSION_NUM:float(MAXIMA_VERSION[2]+MAXIMA_VERSION[3]/10)$ - -/* Note how Maxima has changes this.... */ -DIV_OP:"//"$ -if MAXIMA_VERSION_NUM>=15.0 then DIV_OP:"/"$ - -/* ********************************** */ -/* Load contributed packages */ -/* ********************************** */ - -if not(?functionp('poly_reduced_grobner)) then load("grobner"); - -/* ********************************** */ -/* Parts of expressions */ -/* ********************************** */ - -/* op(ex) is unsafe on atoms: this is a fix. */ -/* This function always returns a string */ -safe_op(ex) := block( - if mapatom(ex) then return(""), - if stringp(op(ex)) then return(op(ex)) else return(string(op(ex))) -)$ - -/* This function takes an expression ex and returns a list of coefficients of v */ -coeff_list(ex,v):= block([deg,kloop,cl], - cl:[], - ex:ev(expand(ex),simp), - deg:hipow(ex,v), - ev(for kloop:0 thru deg do - cl:append(cl,[coeff(ex,v,kloop)]),simp), - cl -)$ - -/* This function takes an expression ex and returns a list of nonzero coefficients of v */ -coeff_list_nz(ex,v):= block([deg,kloop,cl], - cl:[], - ex:ev(expand(ex),simp), - deg:hipow(ex,v), - ev(for kloop:0 thru deg do - if coeff(ex,v,kloop)#0 then cl:append(cl,[[kloop,coeff(ex,v,kloop)]]),simp), - cl -)$ - -/* Return the set of operations which occur in the expression */ -/* Note, this function varies depending on the value of simp! */ -/* E.g. x+x-> 2*x, so is this a product of sum? */ -get_ops(ex):= setify(flatten(get_ops_helper(ex)))$ -get_ops_helper(ex):=if mapatom(ex) then [] else append([op(ex)],maplist(get_ops_helper,args(ex)))$ - -/* ********************************** */ -/* General list and utility functions */ -/* ********************************** */ - -/* True if and only if ex is in the list l */ -element_listp(ex,l):= any_listp(lambda([ex2], is(ex2=ex)), l)$ - -/* all_listp(p,l) true if all elements of l satisfy p */ -all_listp(p,l):= if listp(l) then ret:apply("and", maplist(p,l)) else ret:"fail"$ - -/* any_listp(p,l) true if all elements of l satisfy p */ -any_listp(p,l):= if listp(l) then ret:apply("or", maplist(p,l)) else ret:"fail"$ - -/* This function applies the binary function zf to two lists a and b returning a list -[ zf(a[1],b[1]), zf(a[2],b[2]), ... ] zip_with quietly gives up when one of the list runs out of elements. */ -zip_with(zf, a, b) := block( - if not(listp(a)) then return(false), - if not(listp(b)) then return(false), - if emptyp(a) then return([]), - if emptyp(b) then return([]), - cons(zf(first(a), first(b)), zip_with(zf, rest(a), rest(b))) -)$ - -/* This function makes a substitution of all variables for their lower case equivalents. - Useful when wanting to do a specific case sensitivity - check, e.g. that X^2=1 is x^2=1, without using subst_equiv. - - Note that exdowncase(X-x)=0, of course! -*/ -exdowncase(ex):=block([lv], - lv:listofvars(ex), - lv:map(lambda([v],v=parse_string(sdowncase(string(v)))),lv), - return(subst(lv,ex)))$ - - -/* ********************************** */ -/* Type predicates */ -/* ********************************** */ - -/* Determines if we are using an equation */ -equationp(ex) := block( - if atom(ex) then return(false), - if "="= op(ex) then return(true), - return(false) -)$ - -/* Determines if we are using a function */ -functionp(ex) := block( - if atom(ex) then return(false), - if ":="= op(ex) then return(true), - return(false) -)$ - -/* Determines if we are using an inequality */ -inequalityp(ex) := block( - if atom(ex) then return(false), - if ">"= op(ex) or "<"= op(ex) or ">="= op(ex) or "<="= op(ex) then return(true), - if "and"= op(ex) or "or"= op(ex) or "not" then return(true), - return(false) -)$ - -expressionp(ex) := block( - if matrixp(ex) or listp(ex) or equationp(ex) or inequalityp(ex) or setp(ex) or functionp(ex) then - return (false), - return(true) -); - -/* Checks that an expression is a polynomial */ -polynomialpsimp(e):= polynomialp(e, listofvars(e))$ - -/* ********************************** */ -/* Numerical operations */ -/* ********************************** */ - -/* numberp() does not "work" when simp:false, since unary minus is an unevaluated function... */ -simp_numberp(ex) := block( - if numberp(ex) then return(true), - if atom(ex) then return(false), - if op(ex)="-" and numberp(first(args(ex))) then return(true), - false -)$ - -/* Do we have a real number?*/ -/* Code taken from Stack_Test */ -real_numberp(ex):= - block([keepfloat, trigexpand, logexpand], - trigexpand:true, - logexpand:super, - keepfloat:true, - ex:errcatch(ev(fullratsimp(ex),simp)), - if ex=[] then return(false), - ex:ev(float(ex[1]),simp), - if listofvars(ex)#[] then return(false), - if floatnump(ex) then return(true) else return(false) -)$ - -/* Write the number x in n decimal places */ -decimalplaces(x,n) := ev(float(round(10^n*float(x))/(10^n)),simp)$ - -/* Write numbers in significant figures */ -/* Matti Pauna, Sun, 23 Oct 2011 */ -significantfigures(x,n) := block([fpprec:128,fpprintprec,simp:true,ex,ex2], - if x = 0 then return(0), - if x = 0.0 then return(0.0), - sign_of_x : signum(x), - x : abs(x), - ex:floor(float(log(x)/log(10))), - ex2:round(float(x/10^(ex-n+1))), - ex2:float(ex2*10^(ex-n+1)), - if floor(ex2)=ratsimp(ex2) then ex2:ratsimp(ex2), - return(sign_of_x*ex2) -); - - -scientific_notation(x) := block([simp:false,fpprintprec,ex,ex2,ex3], - if real_numberp(x) and ev(x>0,simp) then ( - ex:ev(floor(float(log(x)/log(10))),simp), - ex2:ev(float(x/10^ex),simp), - ex3:ex2*10^ex, - return(ex3) - ) else return (x) -); - -/* commonfaclist(l) returns the gcd of a list of numbers */ -commonfaclist(l) := block([i,a,ret], - if listp(l) then - ret:( a:l[1], - if length(l)>1 then - ev(for i:2 thru length(l) do (a:ev(gcd(a,l[i]),simp)),simp), - return(a)) - else ret:"fail", - return(ret) )$ - -/* Returns a list of factors of ex without multiplicities */ -factorlist(ex) := block([simp:false,ret:"",ex2], - ex:ev(factor(ex),simp), - if mapatom(ex) then return([ex]), - if op(ex)#"*" then - ret:[ex] - else - ret:args(ex), - /* now strip off powers */ - ret:maplist(lambda([ex2],if atom(ex2) then ex2 else if op(ex2)="^" then part(ex2,1) else ex2),ret), - return(ret) -)$ - -/* Is the fraction in its lowest terms? */ -lowesttermsp(ex) := block([simp:false,ex1,ex2,ex3], - if atom(ex) then return(true), - if op(ex)#DIV_OP then return(true), - if gcd(num(ex),denom(ex))=1 then return(true) else return(false) -)$ - -/* Create a list with all parts for which numberp(ex)=true, or which appear to be rational numbers */ -list_expression_numbers(ex) := block([ex2], - if mapatom(ex) then (if numberp(ex) then return([ex]) else return([])) - else ( - if op(ex)=DIV_OP and simp_numberp(num(ex)) and simp_numberp(denom(ex)) then return([ex]), - ex2:args(ex), - flatten(maplist(list_expression_numbers,ex2))) -)$ - -all_lowest_termsex(ex):= block([simp:false,ex2], - ex2:list_expression_numbers(ex), - all_listp(lowesttermsp,ex2) -)$ - -/* anyfloats(l) returns true if any of the list are floats */ -anyfloat(l) := block([ret:false], - if listp(l)=false then ret:"fail", - ev(l:map('floatnump,l),simp), - ev(for i:1 thru length(l) do (ret:ret or l[i]),simp), - return(ret) )$ - -/* Decides if any floats are in the expression. */ -anyfloatex(ex) := block([partswitch,ret,kloop], - ret:false, - ex:ev(ex,simp), - if floatnump(ex) then return(true), - if atom(ex) then return(false), - partswitch:true, - ev(for kloop:1 while part(ex,kloop)#end do - ret:ret or anyfloatex(part(ex,kloop)),simp), - return(ret) -)$ - -/* compare with*/ -/* coefl:map('first,rest(coeffs(SA,x))) */ - -/* ********************************** */ -/* Inequalities */ -/* ********************************** */ - -infix("=>"); -"=>"(a,b):=a>=b; -infix("=<"); -"=<"(a,b):=a<=b; - - -/* Reduces an inequality to either ? > 0 or ? >=0, which is monic in its variable. */ -ineqprepare(ex) := block([op2,ex2], - if mapatom(ex) then return(ex), - if op(ex)="=" then return(make_monic(ev(part(ex,1) - part(ex,2),simp,trigreduce)) = 0), - if op(ex)=">" then return(make_monic(ev(part(ex,1) - part(ex,2),simp,trigreduce)) > 0), - if op(ex)=">=" then return(make_monic(ev(part(ex,1) - part(ex,2),simp,trigreduce)) >= 0), - if op(ex)="<" then return(make_monic(ev(part(ex,2) - part(ex,1),simp,trigreduce)) > 0), - if op(ex)="<=" then return(make_monic(ev(part(ex,2) - part(ex,1),simp,trigreduce)) >= 0), - ex2:args(ex), - ex2:map(ineqprepare,ex2), - return(apply(op(ex),ex2)) -)$ - -/* Turn an single variable polynomial expression into a +1/-1 monic polynomial */ -make_monic(ex):=block( - if mapatom(ex) then return(ex), - if not(polynomialpsimp(ex)) then return(ex), - if length(listofvars(ex))>1 then return(ex), - ex:expand(ex), - ev(expand(ex/abs(coeff(ex,first(listofvars(ex)),degree(ex,first(listofvars(ex)))))),simp) -)$ - -/* Writes an expression in a cannonical form */ -ineqorder(ex) := ineqorder_f(ev(ineqprepare(ex),simp))$ - -/* This function prepares inequalities, removes duplicates (e.g. x>1 and 1<x end up the same. Finally it orders the result. */ -ineqorder_f(ex) := block( - if mapatom(ex) then return(ex), - if op(ex)="and" then return(apply("and",sort(listify(setify((map(ineqorder_f,args(ex)))))))), - if op(ex)="or" then return(apply("or",sort(listify(setify((map(ineqorder_f,args(ex)))))))), - if op(ex)="not" then return(apply("not",sort(listify(setify((map(ineqorder_f,args(ex)))))))), - return(ex) -)$ - -/* ********************************** */ -/* Equivalence */ -/* ********************************** */ - -/* A general all purpose function on **expressions**. - Takes two objects and returns true if they are equal, and false otherwise - This is a "bash as hard as possible" function - - 26/9/12. Avoid fullratsimp after exponentialize. This results in a non-terminating process. - - 24/11/13. Avoid fullratsimp. This expands out exprsssions such as (x+a)^6000, which results in an overflow. -*/ -algebraic_equivalence(SA, SB) := - block([keepfloat, trigexpand, logexpand, ex, vi], - /* Reject obviously different expressions. These can be very time consuming in the tests below. */ - /* The code below is actually making the situation worse: needs reconsidering. */ - if numerical_not_alg_equiv(SA, SB) then return(false), - trigexpand:true, - logexpand:super, - keepfloat:true, - /* In some cases we just go inside the function one level */ - if (safe_op(SA)=safe_op(SB) and (safe_op(SA)="sqrt" or safe_op(SA)="abs")) then - (SA:first(args(SA)), - SB:first(args(SB))), - /* Try not to expand out: pure numbers */ - ex:errcatch(ev(SA-SB,simp)), - if ex=[] then (print("algebraic_equivalence: evaluating the difference of two expressions threw an error."), return(false)), - ex:ex[1], - if numberp(ex) then - if rat(ex)=0 then return(true) - else return (false), - /* Try not to expand out: factoring */ - ex:errcatch(ev(factor(SA-SB),simp)), - if ex=[] then (print("algebraic_equivalence: factoring the difference of two expressions threw an error."), return(false)), - ex:ex[1], - /* Try to return a negative result without expanding anything! */ - if safe_op(ex)="-" then - ex:first(args(ex)), - if (safe_op(ex)="*" or safe_op(ex)="^") then - if not(any_listp(lambda([ex2], algebraic_equivalence(ex2, 0)), args(ex))) then return(false), - if ratsimp(ex)=0 then return(true), - /* Next we expand out the difference. */ - ex:errcatch(ev(fullratsimp(SA-SB), simp)), - if ex=[] then (print("algebraic_equivalence: evaluating the difference of two expressions threw an error."), return(false)), - ex:ex[1], - if floatnump(ex) then return(false), - ex:num(ex), /* after a fullratsimp, we have a ratio. We should only need to consider the top */ - ex:trigsimp(ex), - ex:rectform(ex), - ex:exponentialize(ex), - /* ex:trigreduce(ex), CJS, removed 21/1/2010. This was breaking ATSingleFrac! Don't know why. */ - if ratsimp(ex)=0 then return(true), - ex:radcan(ex), - ex:factcomb(ex), - if ratsimp(ex)=0 then return(true), - for vi:1 while ex#sqrtdenest(ex) do ex:sqrtdenest(ex), - if ratsimp(ex)=0 then return(true) else return(false) - )$ - - -/* This test establishes if two expressions appear NOT to be equivalent. - It does so by evaluating the expressions numerically. */ -numerical_not_alg_equiv(p1, p2):= block([lv, sz], - /* We take the *union* of the two lists of variables, this way we - hedge against comparing (x+a)+(x-a) with 2*x, which are the same. */ - lv:listify(union(setify(listofvars(p1)), setify(listofvars(p2)))), - /* Now we evaluate the difference of the expressions at each variable. */ - lv:zip_with("=", lv, makelist(float((sqrt(2)^k+k*%pi)/4), k, length(lv))), - p1:errcatch(ev(float(p1), lv, numer_pbranch:true)), - if is(p1 = []) then (print("STACK: ignore previous error."), return(false)), - p2:errcatch(ev(float(p2), lv, numer_pbranch:true)), - if is(p2 = []) then (print("STACK: ignore previous error."), return(false)), - sz:errcatch(abs(float(first(p1)-first(p2)))), - /* print([p1,p2,sz]), */ - if is(sz = []) then (print("STACK: ignore previous error."), return(false)), - if first(sz) > 0.0001 then true else false)$ - -/* This function takes two expressions. - It establishes if there exists a substitution of the variables of ex2 into ex1 which renders - ex1 algebraically equivalent to ex2. - If such a substitution exists the function returns it in a form so that - - ex2 = ev(ex1, subst_equiv(ex1, ex2)) - - If no such permutation exists it returns the empty list []. - If it could not establish this, because there are too many combinations to reasonably consider, - then the function returns false. -*/ -subst_equiv(ex1,ex2):=block([lv1, lv2, lvi, lvp, lvs, lve, il, perm_size, simp], - simp:true, - perm_size:4, /* This algorithm is order factorial(perm_size) and so this needs to be small. */ - lv1:listofvars(ex1), - lv2:listofvars(ex2), - if length(lv1)#length(lv2) then return([]), - /* If the lists are too long, try a weaker condition */ - /* We assume the variables which occur in both are correctly assigned. */ - /* Can we find a permutation of those left in each? */ - if length(lv1)>perm_size then ( - lv1:setify(lv1), - lv2:setify(lv2), - lvi:intersection(lv1, lv2), - lv1:listify(setdifference(lv1, lvi)), - lv2:listify(setdifference(lv2, lvi)) - ), - if length(lv1)>perm_size then return(false), - /* */ - lvp:listify(permutations(lv2)), - /* Create a list of subsitutions */ - lvs:map(lambda([ex], zip_with("=", lv1, ex)), lvp), - /* Create list of expressions with which to compare ex1 */ - lve:map(lambda([ex], ev(ex1, ex)), lvs), - lve:map(lambda([ex], ATAlgEquivfun(ex, ex2)), lve), - lve:map(second,lve), - lve:map(lambda([ex], equal(ex, true)),lve), - if apply("or", lve) then (il:sublist_indices(lve, identity), lvs[il[1]]) else [] -)$ - -/* ********************************** */ -/* Noun arithmetic */ -/* ********************************** */ - -/* ** Noun forms of the arithmetic functions ** */ - -/* These function define arithmetic functions which do - not perform their actual mathematical functions. That is to say - noun forms of the standard arithmetic functions. This is to - give much finer control over the simplification of very elementary - expressions. - - Chris Sangwin 21 Oct 2005. - Chris Sangwin 7 Nov 2009, with help from JHD. -*/ - -/* Create noun forms of the functions of +, -, *, / and ^ - as follows. - + noun+ - - noun- - * noun* - / noun/ - ^ noun^ -*/ - -/* For each of these we do the following. - (1) They are defined as infix and nary operators in Maxima - with the binding precedences of their namesakes. - (2) The tex() function is modified to display them exactly as - their namesakes. This should work with a *mix* of noun and - active operators - (3) verb_arith(expr) which will replace noun versions with their - active counterparts. - (4) noun_arith(expr) which will replace arithmetic operators with their - noun counterparts. -*/ - -/* (1) */ -nary("noun+", 100); -prefix("noun-", 100); -nary("noun*", 120); -infix("noun/", 122, 123); -infix("noun^", 140, 139); -prefix("UNARY_RECIP", 100); - -/* (2) */ -load("noun_arith.lisp"); - -/* (3) */ - -declare("noun+", commutative); -declare("noun+", lassociative); -declare("noun+", rassociative); - -declare("noun*", commutative); -declare("noun*", lassociative); -declare("noun*", rassociative); - -/* (4) */ -verb_arith(ex) := block( - ex:subst("+", "noun+", ex), - ex:subst("*", "noun*", ex), - ex:subst("-", "noun-", ex), - ex:subst(DIV_OP, "noun/", ex), - ex:subst("^", "noun^", ex), - define(UNARY_RECIP a, a^(-1)), - ex:ev(ex, UNARY_MINUS=-1), - remfunction("noun+", "noun*", "noun/", "noun^", "noun-"), - ex -)$ - -/* (5) */ -noun_arith(ex) := block( - ex:subst("noun+", "+", ex), - ex:subst("noun*", "*", ex), - /* Unary minus really communtes with multiplication. */ - ex:subst(lambda([ex], UNARY_MINUS noun* ex), "-", ex), - /* Turn 1/x into x^(-1), in a special form */ - ex:subst(lambda([ex1, ex2], ex1 noun* (UNARY_RECIP ex2)), DIV_OP, ex), - ex:subst("noun^", "^", ex), - ev(ex) -)$ - -/* (6) Assumes we are working in the context of noun operators.*/ -gather_reduce(ex) := block( - ex:subst("+", "noun+", ex), - ex:subst("*", "noun*", ex), - ex:subst("-", "noun-", ex), - ex:ev(ex, simp), - ex:subst("noun+", "+", ex), - ex:subst("noun*", "*", ex), - ex:subst("noun-", "-", ex), - ex -)$ - -/* (7) */ -/* Returns true iff ex1 and ex2 are equal up to commutativity and associativity */ -equals_commute_associate(ex1,ex2) := block([oldsimp,ex1n,ex2n,ret], - oldsimp:simp, - simp:false, - ex1n:noun_arith(ex1), - ex2n:noun_arith(ex2), - simp:true, - if ex1n=ex2n then ret:true else ret:false, - simp:oldsimp, - ret -)$ - -/* An answer test in the context of commutative+associative addition and multiplication.*/ -ATEqualComAss(sa,sb) := - block([Validity, RawMark, FeedBack, AnswerNote, ret, SAA, SBB], - Validity:true, RawMark:true, FeedBack:"", AnswerNote:"", - - SAA:errcatch(ev(sa, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATEqualComAss_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(sb, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false,false,StackAddNote("", "ATEqualComAss_STACKERROR_TAns"), ""]), - - /* We need to check things are of the same type */ - ret:ATSameTypefun(sa,sb), - if ret[2]=false then - (ret[3]:StackAddNote("ATEqualComAss: ", StackTrimNote(ret[3])), return([false, ret[2], ret[3], ret[4]]) ), - ret:block([simp:true, ret], ATAlgEquivfun(sa, sb)), - if ret[2]=false then - (ret[3]:StackAddNote("ATEqualComAss: (AlgEquiv:false)",StackTrimNote(ret[3])), return([false, ret[2], ret[3], ""])), - /* Now actually apply this test */ - if equals_commute_associate(sa,sb) then - (RawMark:true, AnswerNote:"") - else - (RawMark:false, AnswerNote:StackAddNote("","ATEqualComAss: (AlgEquiv:true)")), - return([Validity,RawMark,AnswerNote,FeedBack]) -)$ - - -/* ********************************** */ -/* Algebraic form */ -/* ********************************** */ - -/* expandp(p) is true if p equals its expanded form. */ -/* Use ev with the expand option to limit expansion of large powers .*/ -/* The use of a strange argument to this function is caused by an extra evaluation within the function body.*/ -expandp(expandparg):= block([simp:true], if expandparg=ev(expand(expandparg),expand(1000,1000)) then true else false)$ - -/* factorp(p) is true if p equals its factored form */ -factorp(argfac) := block([a], - if ev(argfac=factor(argfac), simp) then - return(true), - if mapatom(argfac) then - return(false), - /* Note, in Maxima factor((1-x)) = -(x-1), so we need to fix this, for learning and teaching! */ - if ev(-1*factor(argfac) = expand(-1*argfac), simp) then - return(true), - if op(argfac)="^" and mapatom(part(argfac, 1)) - then return(true), - if op(argfac)="^" and factorp(part(argfac, 1)) then - return(true), - if op(argfac)="*" then - return(all_listp(factorp, args(argfac))), - return(false) -)$ - -/* Write the polynomial in completed square form */ -comp_square(ex,var) := block([vc], - if not(atom(var)) or numberp(var) then ( - print("comp_square: var should be an atom but not a number. "), - return(ex) - ), - ex:ratsimp(expand(ex)), - if not(polynomialp(ex, [var])) then ( - print("comp_square: ex should be a polynomial in var. "), - return(ex) - ), - if hipow(ex, var)#2 then ( - print("comp_square: ex should be a quadratic. "), - return(ex) - ), - delta:(coeff(ex, var, 1)^2-4*coeff(ex, var, 2)*coeff(ex, var, 0))/(4*coeff(ex, var, 2)^2), - vc:coeff(ex, var, 1)/(2*coeff(ex, var, 2)), - return(coeff(ex, var, 2)*((var+vc)^2-delta)) -)$ - - -/*********************/ -/* Matrix operations */ -/*********************/ - -/* - Description : forme echelonne par lignes d'une matrice rectangulaire - (a coefficients dans un corps commutatif). - Taken from http://www.math.utexas.edu/pipermail/maxima/2007/008246.html -*/ - -request_rational_matrix(m, pos, fn) := - if every('identity, map(lambda([s], every('ratnump,s)), args(m))) then true else - print("Some entries in the matrix are not rational numbers. The result might be wrong.")$ - -rowswap(m,i,j) := block([n, p, r], - require_matrix(m, "first", "rowswap"), - require_integer(i, "second", "rowswap"), - require_integer(j, "third", "rowswap"), - n : length(m), - if (i < 1) or (i > n) or (j < 1) or (j > n) - then error("Array index out of bounds"), - p : copymatrix(m), - r : p[i], - p[i] : p[j], - p[j] : r, - p -)$ - -addrow(m,i,j,k) := block([n,p], - require_matrix(m, "first", "addrow"), - require_integer(i, "second", "addrow"), - require_integer(j, "third", "addrow"), - require_rational(k, "fourth", "addrow"), - n : length(m), - if (i < 1) or (i > n) or (j < 1) or (j > n) - then error("Array index out of bounds"), - p : copymatrix(m), - p [i] : p[i] + k * p[j], - p -)$ - -rowmul(m,i,k) := block([n,p], - require_matrix(m, "first", "addrow"), - require_integer(i, "second", "addrow"), - require_rational(k, "fourth", "addrow"), - n : length(m), - if (i < 1) or (i > n) then error("Array index out of bounds"), - p : copymatrix(m), - p [i] : k * p[i], - p -)$ - - -rref(m):= block([p,nr,nc,i,j,k,pivot,pivot_row,debug], - debug : 0, - request_rational_matrix(m," ","rref"), - nc: length(first(m)), - nr: length(m), - if nc = 0 or nr = 0 then - error ("The argument to 'rref' must be a matrix with one or more rows and columns"), - p:copymatrix(m), - ci : 1, cj : 1, - while (ci<=nr) and (cj<=nc) do - ( - if (debug = 1) then ( - disp(p), - print("curseur en ligne ",ci," et colonne ",cj)), - pivot_row : 0, pivot : 0, - for k : ci thru nr do ( - if ( abs(p[k,cj]) > pivot ) then ( - pivot_row : k, - pivot : abs(p[k,cj]))), - if (debug = 1) then - print("colonne ",cj," : pivot trouve ligne ", pivot_row,", valeur : ",pivot), - if (pivot = 0) then (cj : cj +1) - else ( - p : rowswap(p,ci,pivot_row), - if (debug = 1) then print (".. Echange : ",p), - p : rowmul(p,ci,1/p[ci,cj]), - if (debug = 1) then print (".. Normalisation : ",p), - for k : 1 thru nr do ( - if not (k=ci) then (p : addrow (p,k,ci,-p[k,cj]))), - ci : ci+1, cj : cj+1)), - p -)$ - -/* ********************************** */ -/* Analysis tests */ -/* ********************************** */ - -/* This determines if an expression is continuous - ex the expression, - v the variable, - xp the point at which to evaluate. */ -continuousp(ex, v, xp) := block([lp, lm], - lp: ev(limit(ex, v, xp, minus), simp), - lm: ev(limit(ex,v,xp,plus),simp), - /* print(lp), print(lm), */ - if lp # und - and lm # und - and lp # ind - and lm # ind - and lp # inf - and lm # inf - and lp # minf - and lm # minf - and lp = lm - then true else false -)$ - - -/* This determines if an expression is differentiable - ex the expression, - v the variable, - xp the point at which to evaluate, - n the number of times it is differentiated (optional). -*/ -diffp(ex,[args]) := block([v, xp, n], - v:args[1], - xp:args[2], - n:1, - if length(args)=3 then n:args[3], - return(continuousp(diff(ex, v, n), v, xp)) -)$ - -/* ********************************** */ -/* Buggy rules */ -/* ********************************** */ - - -/* (a+b)^n -> a^n+b^n */ -buggy_pow(ex) := block([ex_ex], - if mapatom(ex) then return(ex), - if op(ex)="/" and atom(part(ex, 2))#true and op(part(ex, 2))="+" then return(map(lambda([ex2],part(ex, 1)/ex2), part(ex, 2))), - if mapatom(part(ex, 1)) or op(part(ex, 1))#"+" then return(map(buggy_pow, ex)), - if op(ex)="^" then return(map(lambda([ex2], ex2^buggy_pow(part(ex, 2))), map(buggy_pow, part(ex, 1)))), - if op(ex)=sqrt then return(map(sqrt, map(buggy_pow, part(ex, 1)))) -)$ - -/* Naive adding of fractions! But see Farey sequences. */ -mediant(ex1,ex2) := (num(ex1)+num(ex2))/(denom(ex1)+denom(ex2)); - - -/* ********************************** */ -/* Answer tests */ -/* ********************************** */ - -AnswerTests : [AlgEquiv, EqualComAss, CasEqual, SameType, SubstEquiv, SysEquiv, Expanded, FacForm, SingleFrac, PartFrac, CompSquare, GT, GTE, NumAbsolute, NumRelative, NumSigFigs, LowestTerms, Diff, Int, String, StringSloppy, RegExp]$ - diff --git a/stack/2014083000/maxima/assessment.texi b/stack/2014083000/maxima/assessment.texi deleted file mode 100644 index 8e3b16f..0000000 --- a/stack/2014083000/maxima/assessment.texi +++ /dev/null @@ -1,568 +0,0 @@ -\input texinfo - -@c %**start of header (This is for running texinfo on a region.) -@setfilename assessment.info -@settitle An Assessment Package for Maxima - -@macro mybibitem{ref} -@item -@anchor{\ref\}[\ref\] -@end macro - - -@c %**end of header (This is for running texinfo on a region.) - -@ifinfo -@macro var {expr} -<\expr\> -@end macro -@end ifinfo - -@titlepage -@title An Assessment Package for Maxima -@subtitle Draft -@subtitle August 2011 -@author Chris Sangwin -@end titlepage - - -@node Top, Introduction to Assessment, (dir), (dir) -@top -@menu -* Introduction:: -@end menu - -@node Introduction to Assessment, , Top, Top - -@chapter The Assessment Package - -@section Introduction to Assessment - -This document describes an assessment package for the computer algebra system Maxima. - -Note, the assessment package is designed to be used with @code{simp:false}. Otherwise it will not always function correctly. - -A computer algebra system (CAS) is software for manipulating mathematical expressions symbolically. For example, we can expand out, or differentiate. Increasingly, CAS is being used to assess students' mathematical work automatically. -When doing this we seek to @emph{establish mathematical properties} of expressions, rather than performing calculations with them. For example, if @math{p(x)} is an expression provided by a student, we might try to establish @emph{``is @math{p(x)} an odd expression?''}. The prototype property is to establish if a student's answer @code{sa} is @emph{``equivalent to the teacher's answer @code{ta}''}. Establishing such properties is a key step in the assessment process. - -The STACK CAA system uses Maxima. -See @cite{Sangwin2006CASAlgebra}, @cite{WebALT2006}, @cite{Sangwin2007CAME}, @cite{SangwinTMA03}, -@cite{CervalPena2008}, @cite{Wild2009}, @cite{Lowe2010}, @cite{2010STACKReport}, @cite{Rasila2007}, @cite{Rasila2010}, @cite{Ruokokoski2009}, @cite{Harjula2008} and @cite{Nakamura2010}. -The assessment package comprises much of the code developed for STACK, but factored out into a more general package. In this way it can be used in other software projects, and others can more easily contribute to the development of other features. - -The design decisions made here are appropriate for @emph{elementary mathematics}. In particular, we are usually interested in working over the real numbers rather than the complex plane. - - -@node Simplification, , , Top -@section Representation of expressions and simplification - -Everything in Maxima is an @emph{expression}, including mathematical expressions, -objects, and programming constructs. An expression is either an atom, or -an operator together with its arguments. - -An atom is a symbol (a name), a string enclosed in quotation marks, an integer or floating point number. Note that rational numbers and complex numbers are not atoms. - -All other expressions have an @emph{operator} and list of @emph{arguments}. - -For the purposes of assessment we usually deal with expressions @emph{as provided by students}. In particular, we do not initially wish to manipulate them in any way. As a specific example, a student might enter an answer such as -@math{ {{3}\over{21}}x^2+0.5.} -We would certainly want to know that this is @emph{equivalent} to the correct answer @math{x^2/7+1/2}, but that it also contains (i) rational numbers not in lowest terms, and (ii) floating point numbers which are exact representations of rational numbers. Clearly there are a number of separate properties here, each of which needs an individual test. We do @emph{not} want the system to manipulate this expression into -@math{{{x^2}\over{7}}+0.5}, or even to rationalize it to @math{{{x^2}\over{7}}+{{1}\over{2}}}, before we have had a chance to establish these properties. - -Maxima is unusual in that @emph{all simplification} can be switched off using the command -@code{simp:false}. -The assessment package is designed to be used with @code{simp:false}. Otherwise it will not always function correctly. When this flag is set, even expressions such as @math{1+1} remain unchanged. Individual expressions can be evaluated with simplification using -@example -ev(ex,simp); -@end example - -The difficulty now, of course, is performing the @emph{correct} manipulations. This is not so simple. Internally, Maxima stores expressions as LISP trees. It is possible to obtain the internal data structure of the expression @code{ex} by using the command @code{?print(ex)}. Notice there is no space after the @code{?}, otherwise we would call for the helpfile. - -Notice the subtle differences when simplification is on or off, as illustrated by the following session. -@example -(%i1) p:x-1; -(%o1) x-1 - -(%i2) ?print(p)$ -((MPLUS SIMP) -1 $X) - -(%i3) simp:false$ - -(%i4) p:x-1; -(%o4) x-1 - -(%i5) ?print(p)$ -((MPLUS) $X ((MMINUS) 1)) -@end example - -In the first example we literally have @code{"+"(-1,x)}, while in the second we have @code{"+"(x,"-"(1))}. I.e., in the second we have a unary minus function applied to the number @math{1}. However, at the display level these expressions are indistinguishable. -The unary minus is particularly troublesome! - -Note that the flag @code{SIMP} in @code{((MPLUS SIMP) -1 $X)} indicates that the arguments have have already been simplified. - -@deffn {Function} safe_op (@var{ex}) -Note that applying @var{op} to an atom throws an error. Sometimes @var{op} returns a string, and sometimes a function name. (Compare @code{op(sin(x))} to @code{op(x+1)}). This function always returns a string. -If @var{ex} is an atom then we return the empty string @code{""}. -@end deffn - -@deffn {Function} coeff_list (@var{ex},@var{v}) -This function takes an expression @var{ex} and returns a list of coefficients of @var{v}. -@end deffn - - -@section Utility functions - -A predicate function returns either @code{true} or @code{false}. In Maxima, most predicate functions end with the letter @code{p}. - -@deffn {Function} element_listp (@var{ex},@var{l}) -Is @var{ex} an element of the list @var{l}? Note, ``sameness" is established with Maxima's @var{is} command. -@end deffn - -@deffn {Function} any_listp (@var{p},@var{l}) -Maps the predicate @var{p} to the list @var{l}, and then applies the Boolean connective @code{or}. -@end deffn - -@deffn {Function} all_listp (@var{p},@var{l}) -Maps the predicate @var{p} to the list @var{l}, and then applies the Boolean connective @code{and}. -@end deffn - -@deffn {Function} filter (@var{p},@var{l}) -Returns a list of those elements of @var{l} for which the predicate @var{p} is @code{true}. -@end deffn - -@deffn {Function} zip_with (@var{f},@var{a},@var{b}) -This takes a binary function @var{f} and two lists @var{a} and @var{b}. It returns the list -@example -[ f(a[1],b[1]), f(a[2],b[2]), ... ] -@end example -I.e. it @emph{zips} the two lists together with @var{f}. @code{zip_with} quietly gives up when one of the lists runs out of elements. For example, to implement the dot product of two lists @code{l1} and @code{l2} we could use -@example -apply("*",zip_with("+",l1,l2)); -@end example -@end deffn - -@deffn {Function} exdowncase (@var{ex}) -This function makes a substitution of all variables for their lower case equivalents. -Useful when wanting to do a specific case sensitivity -check, e.g. that @math{X^2=1} is @math{x^2=1}, without using @code{subst_equiv}. -Note that @code{exdowncase(X-x)} simplifies to zero, of course! -@end deffn - -@section Types of elementary object - -Maxima is a relatively weakly typed CAS. In particular, while Maxima tolerates polynomials with a mixture of floating point coefficients and integers, other CAS do not. In other CAS such as Axiom, see @cite{Jenks1992}, there is a much stronger sense of `type'. - -In the assessment world, we have the following types of objects -@enumerate -@item sets, -@item lists, -@item matrices, -@item equations and inequalities, -@item polynomials or other "expressions". -@end enumerate -This sense of type is useful, because it is nonsense to attempt to compare an equation, e.g. @math{y=mx+c} with an expression, e.g. @math{mx+c}. In assessment we need to establish which type of object we are dealing with before we can proceed. - -Maxima already has predicate functions such as @code{listp}, @code{matrixp} and @code{setp}. This package defines the rest. - -@deffn {Function} equationp (@var{ex}) -True if @code{op(ex)="="}@. Safe for atoms. -@end deffn - -@deffn {Function} inequalityp (@var{ex}) -True if @code{op(ex)}@ is some kind of inequality. Safe for atoms. -@end deffn - -@deffn {Function} expressionp (@var{ex}) -True if @code{op(ex)}@ is not a set, list, matrix, inequality or equation. Safe for atoms. -@end deffn - -Notice that in sets duplicates are removed. It is important to establish which notion of ``sameness'' is applied. In Maxima we currently have little control, other than @code{simp:true} and @code{simp:false}. - -Maxima already has a function @code{polynomialp(p,L)} which requires a list, @code{L}, of variable names. Hence, we define the following. - -@deffn {Function} polynomialpsimp (@var{p}) -This simply establishes if @var{p} is a polynomial in its own variables, i.e. -@example - polynomialpsimp(p):= polynomialp(p, listofvars(p))$ -@end example -@end deffn - -@section Numerical operations - -The assessment package defines the following functions for dealing with numbers. - -@deffn {Function} simp_numberp (@var{ex}) -@code{numberp(ex)} does not work when @code{simp:false}, since unary minus is an unevaluated function. Literally, input of @code{-1} is treated as @code{"-"(1)}. Hence, @code{simp_numberp} should be used instead. -@end deffn - -@deffn {Function} real_numberp (@var{ex}) -Surds and mathematical constants @math{\pi}, @math{e}, @math{\gamma} should also be considered as ``numbers'', even if from a formal point of view they are atomic CAS symbols, or operators and arguments, rather than numeric datatypes. Constants such as @math{\pi} are not considered numbers by Maxima's function @code{numberp}, so we need this separate predicate function to test for real numbers. -@end deffn - -@deffn {Function} decimalplaces (@var{x},@var{n}) -This function evaluates, i.e. rounds, @var{x} to @var{n} decimal places. Note that the number of decimal digits displayed by Maxima is controlled by @code{fpprintprec} which is currently limited to 16, so the displayed result of this calculation may not appear to be correct. -@end deffn - -@deffn {Function} significantfigures (@var{x},@var{n}) -This function evaluates, i.e. rounds, @var{x} into @var{n} significant figures. See @code{decimalplaces} for comments on numerical precision. -@end deffn - -@deffn {Function} scientific_notation (@var{ex}) -This writes the argument in the form @math{a\ 10^b}, where @math{0\leq a < 10}. -@end deffn - - -@deffn {Function} commonfaclist (@var{l}) -Returns the @code{gcd} of a list of numbers. -@end deffn - -@deffn {Function} factorlist (@var{ex}) -Returns a list of factors of @var{ex} without multiplicities. -@end deffn - -@deffn {Function} lowesttermsp (@var{ex}) -This returns @code{false} if @code{op(ex)} is division and the arguments are not coprime. -@end deffn - -@deffn {Function} list_expression_numbers (@var{ex}) -Create a list with all parts for which @code{numberp(ex)=true}, or which appear to be rational numbers. -@end deffn - -@deffn {Function} all_lowest_termsex (@var{ex}) -This is @code{true} if and only if all numbers appearing in the expression are written in lowest terms. -@end deffn - -@deffn {Function} anyfloatex (@var{ex}) -This is @code{true} if @var{ex} contains any floating point numbers. -@end deffn - -@section Inequalities - -The assessment package defines non-strict inequalities @code{>=} and @code {<=} as infix operators. - -@deffn {Function} ineqprepare (@var{ex}) -Reduces an inequality to either @code{? > 0} or @code{? >=0}. -@end deffn - - -@section Equivalence of expressions - -The assessment package defines the following senses in which two expressions are considered equivalent. -@enumerate -@item Same ``type'' of object. -@item Substitution equivalence. -@item Algebraic equivalence. -@item Equivalent up to associativity and commutativity of elementary algebraic operations. -@item Identical LISP trees. -@end enumerate -These tests return a boolean result, so strictly speaking could be predicate functions. However, they also return feedback which is suitable, and very useful, for computer aided assessment system. - -For example, the system might generate string such as ``@emph{Your answer should be a list, but is not.}" or ``@emph{Your inequality should not be strict! Your inequality appears to be backwards.}". Hence the answer tests are actually asymmetric when they might reasonably be expected to be symmertical/commutative in their arguments. The first argument is assumed to be the student's and the second argument the teacher's. In particular situations such feedback may be inappropriate or even irrelevant. It is much easier to generate this from the test and then subsequently suppress it than it would be to try to generate it again retrospectively with separate functions. - -Furthermore, the teacher is likely to want to compile statistics which include details of the logical mistake, regardless of the actual values used in the question. Hence, each test actually returns a list of three things, @code{[valid,value,feedback,note]}. - -The Boolean variable @code{valid} indicates if a test could be applied, or if @code{false} if for some reason occurred why this might be invalid. For example, a set cannot be compared with a list. The @code{value} is a Boolean of the outcome. The @code{feedback} is a language-independent string which can later be translated into actual feedback to the student. This may have displayed forms of expressions embedded within it. The @code{note} is used for statistical analysis. - -@subsection Same ``type'' of object - -This test establishes that expressions are of the same ``type''. -It works recursively over the entire expression, so a list of equations is different from a list of polynomials. -In order to provide feedback, it acts recursively on objects such as sets and lists to identify which members differ in type. -Matrices are checked for size and matrix elements are examined individually. - -@subsection Substitution equivalence - -Consider a situation where a student types in @math{X^2+1} rather than @math{x^2+1}. In this case we could establish algebraic equivalence by using case insensitivity. However, given two expressions @var{ex1} and @var{ex2}, we could also seek a substitution of the variables of @var{ex2} into @var{ex1} which renders @var{ex1} algebraically equivalent to @var{ex2}. -If @code{ex1=X^2+1} and @code{ex2=x^2+1} then for our example, the required substitution is @code{X=x}. -This test is surprisingly useful, especially in establishing whether the student has used the wrong variable name beyond case insensitivity. - -@deffn {Function} subst_equiv (@var{ex1},@var{ex2}) -This function establishes if there exists a substitution of the variables of @var{ex2} into @var{ex1} which renders @var{ex1} algebraically equivalent to @var{ex2}. - If such a substitution exists the function returns it in a form so that - @code{ex2 = ev(ex1, subst_equiv(ex1,ex2))}. - If no such permutation exists it returns the empty list @code{[]}. - This algorithm is of factorial order in the number of variables. - If there are more than 4 variables then the system returns @code{false} to prevent instability. -@end deffn - - -@subsection Algebraic equivalence - -This is the prototype test. The student's answer is assigned internally to a CAS variable @var{sa} and the teacher's expression to @var{ta}. -Essentially we evaluate the following pseudo-code -@example - if simplify(sa-ta)=0 then true else false. -@end example - -There are theoretical limits on the extent to which this test works. -See @cite{Richardson1966}, @cite{Caviness1970} and @cite{Moses1971}. -In practice, for learning and teaching, this test works very well indeed on the limited range of expressions used. -As @cite{Fenichel1966} comments @emph{``recursive undecidability can be a remote and unthreatening form of hopelessness''}. - -@deffn {Function} algebraic_equivalence (@var{ex1},@var{ex2}) -This function tests for algebraic equivalence of @var{ex1} and @var{ex2} by attempting to establish that the difference is zero. This function expects @var{ex1} and @var{ex2} to be expressions, but no checking is done. -@end deffn - -@subsection Associativity and Commutativity - -This test seeks to establish whether two expressions are the same when the basic arithmetic operations of addition and multiplication are assumed to be nouns but are commutative and associative. Hence, @math{2x+y=y+2x} but @math{x+x+y\neq 2x+y}. The real difficulties here are the inverse operations, and in particular the unary minus. - -The first step is to replace all arithmetic operations by a pseudo-noun form as follows. - -@deffn {Function} noun+ (@var{[ex]}) -This is a commutative, associative, nary operator. Normal addition is replaced by this operator when we are testing for equivalence up to associativity and commutativity. -@end deffn - -@deffn {Function} noun* (@var{[ex]}) -This is a commutative, associative, nary operator. Normal multiplication is replaced by this operator when we are testing for equivalence up to associativity and commutativity. -@end deffn - -@deffn {Function} noun^ (@var{a},@var{b}) -This is a binary infix operator. Normal exponentiation is replaced by this operator when we are testing for equivalence up to associativity and commutativity. -@end deffn - -@deffn {Function} noun- (@var{ex}) -This is a prefix operator. This is to match unary minus when we are testing for equivalence up to associativity and commutativity. However, in practice unary minus, @code{"-"(ex)}, is replaced by @code{UNARY_MINUS noun* ex} so that it correctly commutes with multiplication. -@end deffn - -We need functions which will transform expressions between these forms. - -@deffn {Function} noun_arith (@var{ex}) -All operations are replaced with their noun forms. Note that unary minus function, @code{"-"(ex)} is replaced by @code{UNARY_MINUS noun* ex} so that it correctly commutes with multiplication. Similarly, @code{ex1/ex2} is replaced by @code{ex1 noun* (UNARY_RECIP ex2)}. -@end deffn - -@deffn {Function} verb_arith (@var{ex}) -All noun operations are replaced with their verb forms. -@end deffn - -@deffn {Function} equals_commute_associate (@var{ex1},@var{ex2}) -Returns @code{true} if and only if @var{ex1} and @var{ex2} are equal up to associativity and commutativity of the elementary algebraic operations. -@end deffn - -Notice, that these functions would enable us to define specific rule-based transformations such as @math{-(-x)\rightarrow x}, but at this stage we have not done this. - - -@subsection Parse tree equality - -This ensures that the two expressions have the same representation in the data structure of Maxima. -This is the strictest notion of all and in practice it is surprisingly rarely helpful. For example, the expressions @math{x+y} and @math{y+x} have different representations as trees, but in few situations would a teacher accept one but not the other. - -There is no need for a function. With @code{simp:false} we simply use the code -@example - if ex1=ex2 then true else false -@end example - -@section Equivalence of equations - -Single equations and inequalities are transformed into the forms @math{p=0}, @math{p>0} and @math{p\geq 0} and are then compared. - -Systems of polynomial equations are dealt with using Grobner basis techniques. -See @cite{Sangwin2010IGI} for more details. - -@section Analysis - -The assessment package has predicates which establish that an expression is continuous or differentiable at a particular point. There are, of course, theoretical limits on the extent to which these functions can possibly work and also practical limitations of Maxima's current implementation of the @code{limit} function. - -@deffn {Function} continuousp (@var{ex},@var{v},@var{p}) -Establishes is @var{ex} is continuous in the variable @var{v} at the point @var{p}. -@end deffn - - -@deffn {Function} diffp (@var{ex},@var{v},@var{p},@var{n}) -Establishes is @var{ex} is @var{n}-times differentiable in the variable @var{v} at the point @var{p}. -The argument @var{n} is optional. -@end deffn - -There are also specific tests for assessment questions in calculus, e.g. differentiation and integration, as constants of integration can be difficult to spot reliably. - -@section Algebraic forms - -The assessment package has a number of tests for particular algebraic forms. - -@subsection Expanded @emph{vs} Factored - -Checking whether an expression is factored is significantly different from comparing an expression @var{ex} with the result of @code{factor(ex)}. -Consider the following forms of @math{x^2-4x+4} - -@math{(x-2)(x-2)}, @math{(x-2)^2}, @math{(2-x)^2}, @math{4\left(1-{{x}\over{2}}\right)^2}. - -One might argue that each of these is factored, if not fully ``simplified''. - -Such a test seeks to establish that the expression is a product of powers of distinct irreducible factors. @cite{Sangwin2009CalculumusII} identified the following meanings. -For example, consider @math{x^8+16x^4+48}. -@enumerate -@item Any non-trivial factorization, e.g. @math{(x^4+4)(x^4+12)}. -@item A factorization into irreducible factors over the integers, @* -i.e. @math{(x^2+2x+x)(x^2-2x+2)(x^4+12)}. -@item A factorization into terms irreducible over the reals, @* - i.e. @math{(x^2+2x+x)(x^2-2x+2)(x^2+2\root 4\of{3}x+2\root 4\of{3})(x^2-2\root 4\of{3}x+2\root 4\of{3})}. -@item A factorization into irreducible polynomials over the Gaussian integers, with @math{i} allowed,@* -i.e. @math{(x+1+i)(x+1-i)(x-1+i)(x-1-i)(x^4+12)}. -@item A factorization over the complex numbers, where the factor @math{(x^4+12)} would also be split into the four terms @math{x\pm\root 4\of{3}(1\pm i)}. -@end enumerate -In elementary teaching, meaning 4. is unlikely to occur. Indeed, we might take this example to represent factoring over any extension field of the rational numbers. We normally seek to establish that the factors are irreducible over the integers (which is equivalent to irreducibility over the rational numbers) or the reals. But, unlike a canonical form, we are not particularly interested in the order of the terms in this product, or the order of summands inside these terms. Strictly speaking, in establishing that an expression is in factored form, we might not even care whether the terms in the product are fully simplified, as long as they are irreducible. - -There are some delicate cases such as: @math{(2-x)(3-x)} vs @math{(x-2)(x-3)} and @math{(1-x)^2} vs @math{(x-1)^2}. - -Establishing that an expression, @var{ex}, is expanded is much more straightforward. Essentially, we compare @var{ex} with @code{expand(ex)} up to commutativity and associativity of the algebraic operations. - -@deffn {Function} factorp (@var{ex}) -Returns @code{true} if @var{ex} equals @code{factor(ex)}. Note, some wrinkles with unary minus etc. are ironed out quietly with this function. -@end deffn - -@deffn {Function} expoandp (@var{ex}) -Returns @code{true} if @var{ex} equals @code{expand(ex)}. -@end deffn - -@subsection Rational expression @emph{vs} Partial fraction - -Testing for a rational expression is relatively simple. We do need to establish the denominator and numerator have no common factors, otherwise feedback is available. - -Partial fractions form is more difficult to recognize. Just as with the factor test this is significantly different from checking equivalence with the result of the @code{partfrac} function. There are also subtleties here, as illustrated by -@math{{{1}\over{n+1}}+{{1}\over{1-n}} = {{1}\over{n+1}}-{{1}\over{n-1}}} -and -@math{{{1}\over{4n-2}}-{{1}\over{4n+2}}={{n}\over{2n-1}}-{{n+1}\over{2n+1}}.} - - -@section Buggy rules - -In order to establish that the student has done something particular but wrong, it is useful for us to be able to apply @emph{wrong} or @emph{buggy} rules to expressions. A typical example would be to expand out powers in the wrong way, e.g. @math{(x+y)^2=x^2+y^2}. The following function does this! - -@deffn {Function} buggy_pow (@var{ex}) -Implements the ``buggy'' linearity rule for exponentiation, i.e. @math{(a+b)^n \rightarrow a^n+b^n}. This is useful if we want to compare a student's answer to the result of having done something wrong. -@end deffn - -The following is not always a ``buggy rule'', when used for example in connection with Farey sequences, but it is included here as in assessment this function is useful for checking a common mistake when adding fractions. -@deffn {Function} mediant (@var{ex1},@var{ex2}) -The mediant of two fractions @math{{p_1}\over {q_1}} and @math{{p_2}\over{q_2}} is @math{{p_1+p_2}\over {q_1+q_2}}. Note that both @code{denom} and @code{num} work on non-rational expressions, assuming the expression to be ``over one'' by implication. Hence @code{mediant} will also assume the denominator is also one in such cases. -@end deffn - -There is scope for further examples of such rules. -See, for example, @cite{Sleeman1982} for more details. - - -@section Future plans - -Better support is needed for the following features: - -@enumerate -@item Dealing with systems of inequalities, and intervals. - Canonical form for systems of inequalities. Note that Maxima already can represent expressions such as @code{x>1 and x<4}, and the library @code{to_poly_solver} can solve systems such as the following - @example - (%i1) load("to_poly_solver")$ - (%i2) to_poly_solve((x-1)*(x-4)<0,x); - (%o2) %union([1<x,x<4]) - (%i3) to_poly_solve(abs(x)<2,x); - (%o3) %union([-2<x,x<2]) - @end example - These need to be incorporated, expanded and developed. -@item A test which finds a mapping of variable names which makes two expressions equal (or returns ``false''). Also known as unification. -@item Tests which deal with scientific units. -@item Step-by-step derivation of standard types of problems. -@item A larger range of buggy rules. -@end enumerate - -@bye - -@chapter References - -@itemize @asis - -@mybibitem{Sangwin2010IGI} -M. Badger and C.J. Sangwin. My equations are the same as yours!: computer aided assessment using a Grobner basis approach. -In A. A. Juan, M. A. Huertas, and C. Steegmann, editors, Teaching Mathematics Online: Emergent Technologies and Methodologies. IGI Global, 2011. - -@end itemize - -@bye - -@mybibitem{Sangwin2009CalculumusII} -R. Bradford, J. H. Davenport, and C. J. Sangwin. A comparison of equality in computer algebra and correctness in mathematical pedagogy. The International Journal for Technology in Mathematics Education, 2010. - -@mybibitem{Caviness1970} -B. F. Caviness. On canonical forms and simplification. Journal of the ACM (JACM), 17(2):385-396, 1970. - -@mybibitem{CervalPena2008} -E. R. Cerval-Pena. Automated computer-aided formative assessment with ordinary differential equations. Master's thesis, University of Birmingham, 2008. - -@mybibitem{Fenichel1966} -R. R. Fenichel. An On-line System for Algebraic Manipulation. Phd thesis, Harvard Graduate School of Arts and Sciences, 1966. - -@mybibitem{Harjula2008} -M. Harjula. Mathematics exercise system with automatic assessment. Master's thesis, Helsinki University of Technology, 2008. - -@mybibitem{Jenks1992} -R. D. Jenks and R. S. Sutor. AXIOM: the scientific computation system. The Numerical Algorithms Group Ltd, 1992. ISBN: 0-387-07855-0. - -@mybibitem{Lowe2010} -T. Lowe. e-Assessment using Symbolic Manipulation Tools. Technical report, Centre for Open Learning of Mathematics, Science, Computing and Technology, The Open University, 2010. - -@mybibitem{Moses1971} -J. Moses. Algebraic simplification a guide for the perplexed. Communications of the ACM, 14(8):527-537, August 1971. - -@mybibitem{Nakamura2010} -Y. Nakamura. The STACK e-Learning and Assessment System for mathematics, science and engineering education through Moodle, chapter Preface, pages vi-vii. -Tokyo Denki University Press, 2010. In Japanese. ISBN 978-4-501-54820-9. - -@mybibitem{Rasila2007} -A. Rasila, M. Harjula, and K. Zenger. -Automatic assessment of mathematics exercises: Experiences and future prospects. -In ReflekTori 2007: Symposium of Engineering Education, pages 70-80. Helsinki University of Technology, Finland, Teaching and Learning Development Unit, http://www.dipoli.tkk.fi/ok, 2007. - -@mybibitem{Rasila2010} -A. Rasila, L. Havola, Majander H., and J. Malinen. Automatic assessment in engineering mathematics: evaluation of the impact. -In ReflekTori 2010: Symposium of Engineering Education. Aalto University, Finland, Teaching and Learning Development Unit, http://www.dipoli.tkk.fi/ok, 2010. - -@mybibitem{Richardson1966} -D. Richardson. Solvable and Unsolable Problems Involving Elementary Functions of a Real Variable. PhD thesis, University of Bristol, 1966. - -@mybibitem{Ruokokoski2009} -J. Ruokokoski. Automatic assessment in university-level mathematics. Master's thesis, Helsinki University of Technology, 2009. - -@mybibitem{SangwinTMA03} -C. J. Sangwin. Assessing mathematics automatically using computer algebra and the internet. Teaching Mathematics and its Applications, 23(1):1-14, 2004. - -@mybibitem{Sangwin2006CASAlgebra} -C. J. Sangwin. Assessing Elementary Algebra with STACK. -International Journal of Mathematical Education in Science and Technology, 38(8):987-1002, December 2008. - -@mybibitem{2010STACKReport} -C. J. Sangwin. Who uses STACK? A report on the use of the STACK CAA system. Technical report, The Maths Stats and OR Network, School of Mathematics, The University of Birmingham, 2010. - -@mybibitem{WebALT2006} -C. J. Sangwin and M. J. Grove. -STACK: addressing the needs of the ``neglected learners''. In Proceedings of the First WebALT Conference and Exhibition January 5-6, Technical University of Eindhoven, Netherlands, pages 81-95. Oy WebALT Inc, University of Helsinki, ISBN 952-99666-0-1, 2006. - -@mybibitem{Sleeman1982} -D. Sleeman and J. S. Brown, editors. Intelligent Tutoring Systems. Academic Press, 1982. - -@mybibitem{Wild2009} -I. Wild. Moodle 1.9 Math. Packt Publishing, 2009. - -@end itemize - -@bye - - -@node Function and variable index, , Definitions for MYTOPIC, Top -@appendix Function and variable index -@printindex fn -@printindex vr - -@bye - -@C \documentclass[11pt]{article} -@C \newcommand{\href}[2]{#2} -@C \begin{document} -@C \bibliographystyle{plain} -@C -@C \cite{Jenks1992,Richardson1966,Caviness1970,Moses1971}\cite{Fenichel1966,Sleeman1982}\cite{Sangwin2010IGI,Sangwin2009CalculumusII}\cite{Sangwin2006CASAlgebra, WebALT2006,SangwinTMA03} \cite{CervalPena2008,Wild2009,Lowe2010,2010STACKReport}\cite{Rasila2007,Rasila2010,Ruokokoski2009,Harjula2008,Nakamura2010}. -@C -@C \bibliography{/Bib/education,/Bib/sangwin,/Bib/PUS,/Bib/MathsTexts,/Bib/CAA,/Bib/sr,/Bib/students} -@C -@C \end{document} - -@c %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -@deffn {Function} expressionp (@var{ex}) -@end deffn \ No newline at end of file diff --git a/stack/2014083000/maxima/complexi.lisp b/stack/2014083000/maxima/complexi.lisp deleted file mode 100644 index 8be0972..0000000 --- a/stack/2014083000/maxima/complexi.lisp +++ /dev/null @@ -1,10 +0,0 @@ -;; Customize Maxima's TEX() function. -;; Make %i print at a "j" -;; Chris Sangwin 19 August Jan 2005. -;; Useful files: -;; \Maxima-5.9.0\share\maxima\5.9.0\share\utils\mactex-utilities.lisp -;; \Maxima-5.9.0\share\maxima\5.9.0\src\mactex.lisp - -(defprop $%i "\\mathrm{i}" texword) - -(defprop $%i "<mi>i</mi> " mathmlword) diff --git a/stack/2014083000/maxima/complexj.lisp b/stack/2014083000/maxima/complexj.lisp deleted file mode 100644 index 1fdfd5b..0000000 --- a/stack/2014083000/maxima/complexj.lisp +++ /dev/null @@ -1,10 +0,0 @@ -;; Customize Maxima's TEX() function. -;; Make %i print at a "j" -;; Chris Sangwin 19 August Jan 2005. -;; Useful files: -;; \Maxima-5.9.0\share\maxima\5.9.0\share\utils\mactex-utilities.lisp -;; \Maxima-5.9.0\share\maxima\5.9.0\src\mactex.lisp - -(defprop $%i "\\mathrm{j}" texword) - -(defprop $%i "<mi>j</mi> " mathmlword) diff --git a/stack/2014083000/maxima/cos-1.lisp b/stack/2014083000/maxima/cos-1.lisp deleted file mode 100644 index 7cdb2e2..0000000 --- a/stack/2014083000/maxima/cos-1.lisp +++ /dev/null @@ -1,51 +0,0 @@ -(mapc #'tex-setup - '( - (%acos "\\cos^{-1}") - (%asin "\\sin^{-1}") - (%atan "\\tan^{-1}") - ; Latex's arg(x) is ... ? - (%cos "\\cos ") - (%cosh "\\cosh ") - (%cot "\\cot ") - (%coth "\\coth ") - (%csc "\\csc ") - ; Latex's "deg" is ... ? - (%determinant "\\det ") - (%dim "\\dim ") - (%exp "\\exp ") - (%gcd "\\gcd ") - ; Latex's "hom" is ... ? - (%inf "\\inf ") ; many will prefer "\\infty". Hmmm. - ; Latex's "ker" is ... ? - ; Latex's "lg" is ... ? - ; lim is handled by tex-limit. - ; Latex's "liminf" ... ? - ; Latex's "limsup" ... ? - (%ln "\\ln ") - (%log "\\ln ") - (%max "\\max ") - (%min "\\min ") - ; Latex's "Pr" ... ? - (%sec "\\sec ") - (%sin "\\sin ") - (%sinh "\\sinh ") - ; Latex's "sup" ... ? - (%tan "\\tan ") - (%tanh "\\tanh ") - ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual - ;(%laplace "{\\cal L}") - - ; Maxima built-in functions which do not have corresponding TeX symbols. - (%asec "{\\rm sec}^{-1}") - (%acsc "{\\rm csc}^{-1} ") - (%acot "{\\rm cot}^{-1}") - (%sech "{\\rm sech}") - (%csch "{\\rm csch}") - (%asinh "{\\rm sinh}^{-1}") - (%acosh "{\\rm cosh}^{-1}") - (%atanh "{\\rm tanh}^{-1}") - (%asech "{\\rm sech}^{-1}") - (%acsch "{\\rm csch}^{-1}") - (%acoth "{\\rm coth}^{-1}") -)) ;; etc - diff --git a/stack/2014083000/maxima/elementary.mac b/stack/2014083000/maxima/elementary.mac deleted file mode 100644 index de8f9c8..0000000 --- a/stack/2014083000/maxima/elementary.mac +++ /dev/null @@ -1,477 +0,0 @@ -/* Author Chris Sangwin - University of Birmingham - Copyright (C) 2013 Chris Sangwin - - This program is free software: you can redistribute it or modify - it under the terms of the GNU General Public License version two. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - - - -/* THIS IS EXPERIMENTAL CODE */ -/* Currently this is under development by CJS and is not connected to the main STACK codebase */ -/* It sits here because the long-term goal is to incorporate it */ - -/* http://www.ncl.ac.uk/math/numbas/manual.pdf and -https://github.com/numbas/Numbas/blob/master/runtime/scripts/jme-display.js#L749 - - unitDenominator transform x/1 to x - zeroPower transform x^0 to 1 - simplifyFractions transform (a*b)/(a*c) to b/c - zeroBase transform 0^x to 0 - sqrtProduct simplify sqrt(a)*sqrt(b) to sqrt(a*b) - sqrtDivision simplify sqrt(a)/sqrt(b) to sqrt(a/b) - sqrtSquare simplify sqrt(x^2) to x - trig simplify various trigonometric values e.g. sin(n*pi) to 0 - otherNumbers simplify 2^3 to 8 - fractionNumbers display all numbers as fractions instead of decimals -*/ - -/* NOTE: all these operations really need three separate -things, as with zeroAdd: - -zeroAddp - the predicate which matches to the pattern zeroAdd - -perform the rule on the top level. zeroAddr - recurse over the -whole expression applying the rule. - -What about working through to the first occurance of the -pattern? - -What about identifying the first occurance of where a rule is -satisfied? - -*/ - -/*******************************************/ -/* Control functions */ -/*******************************************/ - -/* List of all available rules */ -ID_TRANS:["zeroAdd","zeroMul","oneMul","onePow","idPow","zeroPow","zPow"]$ -ALG_TRANS:["assAdd","assMul","unaryAdd","unaryMul","comAdd","comMul"]$ -NEG_TRANS:["negZero","negDef","negNeg","negInt","negMinusOne","negDistAdd","negProdA","negProdB"]$ -INT_ARITH:["intAdd","intMul","intPow"]$ -DIV_TRANS:["oneDiv","idDiv","divDivA","divDivB","recipDef","recipNeg","recipMul"]$ -ALL_TRANS:append(ALG_TRANS,ID_TRANS,INT_ARITH,NEG_TRANS,DIV_TRANS)$ - -BUG_RULES:["buggyPow","buggyNegDistAdd"]$ - -/* Is the rule applicable at the top level? */ -trans_topp(ex,rl):=apply(parse_string(sconcat(rl,"p")),[ex])$ - -/* Is the rule applicable anywhere in the expression? */ -trans_anyp(ex,rl):=block( - if atom(ex) then return(trans_topp(ex,rl)), - if trans_topp(ex,rl) then return(true), - apply("or",maplist(lambda([ex2],trans_anyp(ex2,rl)),args(ex))) -)$ - -/* Identify applicable rules at the top level */ -trans_top(ex):=sublist(ALL_TRANS, lambda([ex2],trans_topp(ex,ex2)))$ - -/* Identify applicable rules */ -trans_any(ex):=sublist(ALL_TRANS, lambda([ex2],trans_anyp(ex,ex2)))$ - - -/* Transform recursively accross an expression*/ -transr(ex,rl):=block( - if atom(ex) then return(ex), - if listp(rl) then print("ERROR: only apply one rule using transr"), - if trans_topp(ex,rl) then - /* If applying the rule changes the expression then do so */ - block([ex2], ex2:apply(parse_string(rl),[ex]), if ex=ex2 then ex else transr(ex2,rl) ) - else return(map(lambda([ex2],transr(ex2,rl)),ex)) -)$ - -/* Apply a list of rules recursively, in order, once each */ -transl(ex,rll):=block( - if atom(ex) or not(listp(rll)) or emptyp(rll) then return(ex), - return(transl(transr(ex,first(rll)),rest(rll))) -)$ - -/*******************************************/ -/* Higher level control functions */ -/*******************************************/ - -/* Very inefficient! */ -/* Has the advantage that the whole expression is always visible at the top level */ -step_through(ex):=block([rls], - rls:trans_any(ex), - if emptyp(rls) then return(ex), - print(string(ex)), - print(rls), - step_through(transr(ex,first(rls))) -)$ - -/* This only looks at the top level for rules which apply. If none, we look deeper. */ -/* This is much more efficient */ -step_through2(ex):=block([rls,rl,ex2], - if atom(ex) then return(ex), - rls:trans_top(ex), - if emptyp(rls) then return(block([ex2], ex2:map(step_through2,ex), if ex=ex2 then ex else step_through2(ex2))), - rl:first(rls), - ex2:apply(parse_string(rl),[ex]), - print([ex,rl,ex2]), - if ex=ex2 then ex else step_through2(ex2) -)$ - -/* Assume some rules are just applied in the background */ -step_through3(ex):=block([rls], - rls:sublist(ALG_TRANS, lambda([ex2],trans_anyp(ex,ex2))), - if not(emptyp(rls)) then return(step_through3(transr(ex,first(rls)))), - rls:trans_any(ex), - if emptyp(rls) then return(ex), - print(string(ex)), - print(rls), - step_through3(transr(ex,first(rls))) -)$ - - -/*******************************************/ -/* Transformation rules */ -/*******************************************/ - -/* 0+x -> x */ /* Strictly zero at the first part */ -zeroAddp(ex):= block( - if safe_op(ex)="+" and is(part(ex,1)=0) then true else false -)$ - -zeroAdd(ex) := block( - if zeroAddp(ex) then - return( block([ex2],ex2:rest(args(ex)), if equal(length(ex2),1) then return(part(ex,2)) else return(apply("+",rest(args(ex)))))), - return(ex) -)$ - -/* zeroMul transform 0*x to 0 */ -zeroMulp(ex) := block( - if safe_op(ex)="*" and is(part(ex,1)=0) then true else false -)$ - -zeroMul(ex) := block( - if zeroMulp(ex) then return(0) else return (ex) -)$ - -/* oneMul transform 1*x to x */ -oneMulp(ex) := block([ex2], - if safe_op(ex)="*" and is(part(ex,1)=1) then true else false -)$ - -oneMul(ex) := block([ex2], - if oneMulp(ex) then - return(block([ex2],ex2:rest(args(ex)), if equal(length(ex2),1) then return(part(ex,2)) else return(apply("*",rest(args(ex)))))) - else return(ex) -)$ - -/* 1^x -> 1 */ -onePowp(ex):=block( - if safe_op(ex)="^" and is(part(ex,1)=1) then true else false -)$ - -onePow(ex):= if onePowp(ex) then 1 else ex$ - -/* x^1 -> x */ -idPowp(ex):=block( - if safe_op(ex)="^" and is(part(ex,2)=1) then true else false -)$ - -idPow(ex):= if idPowp(ex) then part(ex,1) else ex$ - -/* 0^x -> 0*/ -zeroPowp(ex):=block( - if safe_op(ex)#"^" or is(part(ex,2)=0) then return(false), - if is(part(ex,1)=0) then true else false -)$ - -zeroPow(ex):= if zeroPowp(ex) then 0 else ex$ - -/* x^0 -> 1*/ -zPowp(ex):=block( - if safe_op(ex)#"^" or is(part(ex,1)=0) then return(false), - if is(part(ex,2)=0) then true else false -)$ - -zPow(ex):= if zPowp(ex) then 1 else ex$ - -/* "+"(x) -> x. (Probably not needed, but we may end up with sums of lists of length 1.)*/ -unaryAddp(ex):= block( - if safe_op(ex)="+" and length(args(ex))=1 then true else false -)$ - -unaryAdd(ex):= if unaryAddp(ex) then first(args(ex)) else ex$ - -/* "*"(x) -> x. (Probably not needed.)*/ -unaryMulp(ex):= block( - if safe_op(ex)="*" and length(args(ex))=1 then true else false -)$ - -unaryMul(ex):= if unaryMulp(ex) then first(args(ex)) else ex$ - - -/*****************************************/ - -/* These functions "flatten" sums or products by removing uncessary parentheses - i.e. it enforces associativity */ -/* Note that the predicates only return true if the rule changes the expression */ -assAddp(ex):= if safe_op(ex)="+" and flatten(ex)#ex then true else false$ -assAdd(ex) := if assAddp(ex) then flatten(ex) else ex$ - -assMulp(ex):= if safe_op(ex)="*" and flatten(ex)#ex then true else false$ -assMul(ex) := if assMulp(ex) then flatten(ex) else ex$ - -/* Define a predicate to sort elements, NEG at the front, RECIP at the end. */ -orderelementaryp(exa,exb):=block( - if exa=NEG then return(true), - if exb=NEG then return(false), - if safe_op(exa)="RECIP" and safe_op(exb)="RECIP" then return(orderlessp(part(exa,1),part(exb,1))), - if safe_op(exa)="RECIP" then return(false), - return(orderlessp(exa,exb)) -)$ - -/* sort(args(ex),orderelementaryp) does not work :-( */ -elsort(l):=block([l1,l2], - l1:sublist(l, lambda([ex],safe_op(ex)#"RECIP")), - l2:sublist(l, lambda([ex],safe_op(ex)="RECIP")), - append(sort(l1,orderelementaryp),sort(l2,orderelementaryp)) -)$ - -/* Sort out the order of elements, i.e. commutativity */ -/* NOTE: sort(args(ex), orderelementaryp)) should work but does not... */ -comAddp(ex):= if safe_op(ex)="+" and apply("+",elsort(args(ex)))#ex then true else false$ -comAdd(ex) := if comAddp(ex) then apply("+",elsort(args(ex))) else ex$ - -comMulp(ex):= if safe_op(ex)="*" and apply("*",elsort(args(ex)))#ex then true else false$ -comMul(ex) := if comMulp(ex) then apply("*",elsort(args(ex))) else ex$ - -/*******************************************/ -/* Double negation -(-(a)) */ -negNegp(ex):=block( - if safe_op(ex)#"-" then return(false), - if safe_op(part(ex,1))="-" then return(true) else return(false) -)$ - -negNeg(ex):=if negNegp(ex) then part(ex,1,1) else ex$ - -/* -1*x -> -x */ -negMinusOnep(ex):=block( - if safe_op(ex)#"*" then return(false), - if is(first(args(ex))=negInt(-1)) then return(true) else return(false) -)$ - -negMinusOne(ex):=block( - if negMinusOnep(ex)#true then return(ex), - if length(args(ex))>2 then "-"(apply("*",rest(args(ex)))) else -second(args(ex)) -)$ - -/* Negation of zero -0 -> 0 */ -negZerop(ex):=block( - if safe_op(ex)#"-" then return(false), - if is(part(ex,1)=0) then return(true) else return(false) -)$ - -negZero(ex):=if negZerop(ex) then 0 else ex$ - -/* Turns the negation of an integer into an actual integer "-"(n) -> -n */ -negIntp(ex):=block( - if safe_op(ex)#"-" then return(false), - if integerp(part(ex,1)) then return(true) else return(false) -)$ - -negInt(ex):=if negIntp(ex) then ev(ex,simp) else ex$ - -/* Turns unary minus in a product into a special symbol NEG */ -negProdAp(ex):=block( - if safe_op(ex)#"*" then return(false), - return(any_listp(lambda([ex],if safe_op(ex)="-" then true else false),args(ex))) -)$ - -negProdA(ex):=block( - if negProdAp(ex)=false then return(ex), - apply("*",maplist(lambda([ex],if safe_op(ex)="-" then NEG*first(args(ex)) else ex),args(ex))) -)$ - -/* matches up to NEG*... and turns this back into unary minus... */ -negProdBp(ex):=if safe_op(ex)="*" and first(args(ex))=NEG then true else false$ - -negProdB(ex):=block( - if negProdBp(ex)=false then return(ex), - -apply("*",rest(args(ex))) -)$ - -/* a-a -> 0 */ -/* This is a complex function. If "a" and "-a" occur as arguments in the sum - then we remove the first occurance of each. Then we add the remaining arguments. - Hence, this does not flatten arguments or re-order them, but does cope with nary-addition -*/ -negDefp(ex):=block([a0,a1,a2,a3], - if safe_op(ex)#"+" then return(false), - a1:maplist(first,sublist(args(ex), lambda([ex2],safe_op(ex2)="-"))), - a2:sublist(args(ex), lambda([ex2],safe_op(ex2)#"-")), - any_listp(lambda([ex2],element_listp(ex2,a2)),a1) -)$ - -negDef(ex):=block([a0,a1,a2,a3], - if negDefp(ex)#true then return(ex), - a0:args(ex), - a1:maplist(first,sublist(args(ex), lambda([ex2],safe_op(ex2)="-"))), - a2:sublist(args(ex), lambda([ex2],safe_op(ex2)#"-")), - a3:removeoncelist_negDef(a1,a0), - if emptyp(a3) then 0 else apply("+",a3) -)$ - - -/* removes the first occurance of ex from the list l */ -removeonce(ex,l):=block( - if listp(l)#true or emptyp(l) then return([]), - if first(l)=ex then return(rest(l)), - append([first(l)],removeonce(ex,rest(l))) -)$ - -/* removes elements of l1 from l2. */ -removeoncelist(l1,l2):=block( - if listp(l2)#true or emptyp(l2) then return([]), - if listp(l1)#true or emptyp(l1) then return(l2), - if element_listp(first(l1),l2) then return(removeoncelist(rest(l1),removeonce(first(l1),l2))), - removeoncelist(rest(l1),l2) -)$ - -/* A special function. - If a\in l1 is also in l2 then remove a and -a from l2. - Used on negDef */ -removeoncelist_negDef(l1,l2):=block( - if listp(l2)#true or emptyp(l2) then return([]), - if listp(l1)#true or emptyp(l1) then return(l2), - if element_listp(first(l1),l2) then return(removeoncelist_negDef(rest(l1),removeonce("-"(first(l1)),removeonce(first(l1),l2)))), - removeoncelist_negDef(rest(l1),l2) -)$ - -/* Distributes "-" over addition */ -negDistAddp(ex):=block( - if safe_op(ex)#"-" then return(false), - if safe_op(part((ex),1))="+" then true else false -)$ - -negDistAdd(ex):=block( - if negDistAddp(ex) then map("-",part((ex),1)) else ex -)$ - -/*******************************************/ -/* Warning, this is not safe on non-atoms, it evaluates them! */ -notintegerp(ex):= if atom(ex) then not(integerp(ex)) else true$ - -/* Evaluate integer arithmetic */ -intAddp(ex):=block( - if safe_op(ex)#"+" then return(false), - if length(sublist(args(ex), integerp))>1 then return(true) else return(false) -)$ - -intAdd(ex):=block([a1,a2], - if intAddp(ex)=false then return(ex), - a1:sublist(args(ex), integerp), - a1:ev(apply("+",a1),simp), - a2:sublist(args(ex), notintegerp), - if length(a2)=0 then a1 - else if length(a2)=1 then a1+first(a2) - else a1+apply("+",a2) -)$ - -intMulp(ex):=block( - if safe_op(ex)#"*" then return(false), - if length(sublist(args(ex), integerp))>1 then return(true) else return(false) -)$ - -intMul(ex):=block([a1,a2], - if intMulp(ex)=false then return(ex), - a1:sublist(args(ex), integerp), - a1:ev(apply("*",a1),simp), - a2:sublist(args(ex), notintegerp), - if length(a2)=0 then a1 - else if length(a2)=1 then a1*first(a2) - else apply("*",append([a1],a2)) -)$ - -intPowp(ex):=block( - if safe_op(ex)#"^" then return(false), - if integerp(part((ex),1)) and part((ex),1)#0 and integerp(part((ex),2)) and part((ex),2)#0 then return(true) else return(false) -)$ - -intPow(ex):=block([a1,a2], - if intPowp(ex)=false then return(ex), - ev(ex,simp) -)$ - -/*******************************************/ -/* Division rules */ - -/* a/1 -> a */ -oneDivp(ex):= if safe_op(ex)="/" and part(ex,2)=1 then true else false$ -oneDiv(ex) := if oneDivp(ex) then part(ex,1) else ex$ - -/* a/a -> 1 */ -idDivp(ex):= if safe_op(ex)="/" and part(ex,1)=part(ex,2) and part(ex,2)#0 then true else false$ -idDiv(ex) := if idDivp(ex) then 1 else ex$ - -/* a/(b/c)-> a*(c/b) */ -divDivAp(ex) := if safe_op(ex)="/" and safe_op(part(ex,2))="/" then true else false$ -divDivA(ex) := if divDivAp(ex) then part(ex,1)*(part(ex,2,2)/part(ex,2,1)) else ex$ - -/* (a/b)/c-> a/(c*b) */ -divDivBp(ex) := if safe_op(ex)="/" and safe_op(part(ex,1))="/" then true else false$ -divDivB(ex) := if divDivBp(ex) then part(ex,1,1)/(part(ex,1,2)*part(ex,2)) else ex$ - -/*******************************************/ -/* RECIP */ - -/* re-write a/b as RECIP */ - -recipDefp(ex) := if safe_op(ex)="/" then true else false$ -recipDef(ex) := if recipDefp(ex) then part(ex,1)*RECIP(part(ex,2))$ - -/* RECIP(-x) -> -RECIP(x) */ -recipNegp(ex) := if safe_op(ex)="RECIP" and safe_op(part(ex,1))="-" then true else false$ -recipNeg(ex) := if recipNegp(ex) then -RECIP(part(ex,1,1)) else ex$ - -/* a*RECP(b)*RECIP(c) -> a*RECIP(b*c) */ -recipMulp(ex) := block([l], - if safe_op(ex)#"*" then return(false), - if length(args(ex))=1 then return(false), - l:reverse(args(ex)), - if safe_op(first(l))="RECIP" and safe_op(second(l))="RECIP" then true else false -)$ - -recipMul(ex) := block([p1,p2], - if recipMulp(ex)#true then return(ex), - l:reverse(args(ex)), - apply("*",append(reverse(rest(rest(l))),[RECIP(part(second(l),1)*part(first(l),1))])) -)$ - -/*******************************************/ -/* Buggy rules */ - -/* (a+b)^n -> a^n+b^n */ -buggyPowp(ex):=block( - if safe_op(ex)#"^" then return(false), - if safe_op(part(ex,1))="+" then true else false -)$ - -buggyPow(ex):= if buggyPowp(ex) then apply("+",map(lambda([ex2],ex2^part(ex,2)),args(part(ex,1)))) else ex$ - -/* -(a+b) -> -a+b */ -buggyNegDistAddp(ex) := negDistAddp(ex)$ -buggyNegDistAdd(ex) := if buggyNegDistAddp(ex) then apply("+",append([-first(args(part(ex,1)))],rest(args(part((ex),1))))) else ex$ - - -/*******************************************/ -/* Testing */ -simp:false; -/*STT:batch("rtest_elementary.mac", test);*/ -simp:false; - - - diff --git a/stack/2014083000/maxima/expandfeedback.mac b/stack/2014083000/maxima/expandfeedback.mac deleted file mode 100644 index 8d688ae..0000000 --- a/stack/2014083000/maxima/expandfeedback.mac +++ /dev/null @@ -1,139 +0,0 @@ -/* Author Chris Sangwin - University of Birmingham - Copyright (C) 2006 Chris Sangwin - - This program is free software: you can redistribute it or modify - it under the terms of the GNU General Public License version two. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - - -/* Expand tutorial. */ -/* This file should take a product and expand out one level in steps */ -/* Chris Sangwin, 6/11/2006 */ -/* This is experimental code, but may be useful. */ - -COLOR_LIST:["red", "Blue" , "YellowOrange", "Bittersweet" , "BlueViolet" , "Aquamarine", "BrickRed" , "Apricot" , "Brown" , "BurntOrange", "CadetBlue" , "CarnationPink" , "Cerulean" , "CornflowerBlue" , "CyanDandelion" , "DarkOrchid" , "Emerald" , "ForestGreen" , "Fuchsia", "Goldenrod" , "Gray" , "Green" , "JungleGreen", "Lavender" , "LimeGreen" , "Magenta" , "Mahogany" , "Maroon" , "Melon", "MidnightBlue" , "Mulberry" , "NavyBlue" , "OliveGreen" , "Orange", "OrangeRed" , "Orchid" , "Peach" , "Periwinkle" , "PineGreen" , "Plum", "ProcessBlue" , "Purple" , "RawSienna" , "Red" , "RedOrange" , "RedViolet" , "Rhodamine" , "RoyalBlue" , "RoyalPurple" , "RubineRed", "Salmon" , "SeaGreen" , "Sepia" , "SkyBlue" , "SpringGreen" , "Tan", "TealBlue" , "Thistle" , "Turquoise" , "Violet" , "VioletRed" ,"WildStrawberry" , "Yellow" , "YellowGreen" , "BlueGreen" ]$ -COLOR_LIST_LENGTH:length(COLOR_LIST)$ - - -/* This function applies the binary function f to two lists a and b - returning a list [ f(a[1],b[1]), f(a[2],b[2]), ... ] - zip_with quietly gives up when one of the list runs out of elements. */ -zip_with(f,a,b) := block( - if listp(a)= false then return(false), - if listp(b)= false then return(false), - if a = [] then return([]), - if b = [] then return([]), - cons(f(first(a),first(b)),zip_with(f,rest(a),rest(b))) -)$ - -/* We want a list of the summands, but you cannot apply args to an atom */ -make_args_sum(ex) := if atom(ex) then [ex] else - if op(ex)#"+" then [ex] else args(ex)$ - -/* Adds up the elements of a list */ -sum_list(ex) := if listp(ex) then - if length(ex)=1 then ex[1] else apply("+",ex) - else ex$ -/* Multiplies together the elements of a list */ -product_list(ex) := if listp(ex) then - if length(ex)=1 then ex[1] else apply("*",ex) - else ex$ - -make_product(ex) := product_list(maplist(sum_list,ex))$ - -/******************************************************************/ -/* A "step" is a list representing a row in a three column matrix */ -/* eg [ [], [], [] ] */ - -/* display a single step, returning a string */ -display_step(ex) := block([ret,ex1,ex2,ex3], - ex1:" ", ex2:" = ", ex3:" ", - if []#ex[1] then ex1:StackDISP(ex[1][1],""), - if []=ex[2] then ex2:" " else - if ex[2][1]#"=" then ex2:StackDISP(ex[2][1],""), - if []#ex[3] then ex3:StackDISP(ex[3][1],""), - apply(concat,[ex1," & ",ex2," & ",ex3," \\\\ "]) -)$ - -/* Takes a list of steps in a problem, and returns a single LaTeX string */ -display_steps(ex) := block([ret], - if atom(ex) then return(StackDISP(ex,"")), - if listp(ex)#true then return(StackDISP(ex,"")), - /* */ - steps:map(display_step,ex), - ret:append(["\\begin{array}{rcl}"],flatten(steps),[" \\end{array} "]), - ret:apply(concat,ret) - )$ - - -/******************************************************************/ - -/* Tutorial expand. This function expands out the expression ex */ -/* It returns a list of steps */ -tut_expand_one_level(ex) := block([args_ex,args_ex1,cur_step,ret], - /* Make sure we apply this function to a product */ - if atom(ex) then return([ [[ex],[],[]] ]), - if op(ex)#"*" then return([ [[ex],[],[]] ]), - /* Get a list of lists with the arguments of ex */ - args_ex:args(ex), - args_ex:maplist(make_args_sum,args_ex), - /* colour the first summands */ - cur_step:cons(zip_with(texcolor,COLOR_LIST,first(args_ex)),rest(args_ex)), - ret:[ [[ex],["="],[make_product(cur_step)]] ], - /* */ - ex1:args_ex[1], - ex2:args_ex[2], - ex3:rest(args_ex,2), - cur_step:maplist(lambda([x],x*sum_list(ex2)),ex1), - cur_step:cons(zip_with(texcolor,COLOR_LIST,cur_step),ex3), - ret:cons([[],["="],[make_product(cur_step)]],ret), - /* */ - cur_step:maplist(lambda([x],maplist(lambda([y],x*y),ex2)),ex1), - cur_step:maplist(sum_list,cur_step), - cur_step:zip_with(texcolor,COLOR_LIST,cur_step), - cur_step:make_product(cons(cur_step,ex3)), - ret:cons([[],["="],[cur_step]],ret), - /* */ - cur_step:maplist(lambda([x],maplist(lambda([y],x*y),ex2)),ex1), - cur_step:maplist(sum_list,cur_step), - /* BUG: this should only be "one step" of simplification. Currently it does everthing */ - cur_step:ev(sum_list(cur_step),simp), - cur_step:if ex3=[] then cur_step else make_product(cons(cur_step,ex3)), - ret:cons([[],["="],[cur_step]],ret), - /* */ - reverse(ret) -)$ - -/* Tutorial expand. This function expands out the expression ex */ -tut_expand_all_levels(ex) := block([args_ex,first_ex], - if atom(ex) then return([ [[ex],[],[]] ]), - if op(ex)#"*" then return([ [[ex],[],[]] ]), - /* first step */ - args_ex:args(ex), - first_ex:ev(expand(args_ex[1]*args_ex[2]),simp), - if length(args_ex)>2 then - append(tut_expand_one_level(ex), [ [["and"],[],[]] ], tut_expand_all_levels(product_list(cons(first_ex,rest(args_ex,2))))) - else - tut_expand_one_level(ex) -)$ - -tut_expand_full(ex) := block([ret,seps], - ret:tut_expand_all_levels(ex), - ret:append(ret,[ [["Hence"],[],[]], [[ex],["="],[ev(expand(ex),simp)]] ]), - display_steps(ret) -)$ - - - - - - - diff --git a/stack/2014083000/maxima/experimental.mac b/stack/2014083000/maxima/experimental.mac deleted file mode 100644 index 7f04855..0000000 --- a/stack/2014083000/maxima/experimental.mac +++ /dev/null @@ -1,298 +0,0 @@ -/* Author Chris Sangwin - University of Birmingham - Copyright (C) 2013 Chris Sangwin - - This program is free software: you can redistribute it or modify - it under the terms of the GNU General Public License version two. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - - -/* THIS IS EXPERIMENTAL CODE */ -/* Currently this is under development by CJS and is not connected to the main STACK codebase */ -/* It sits here because the long-term goal is to incorporate it */ - -/* More general random function - recurses across the structure. - Notice the use of the dummy "protect()" function to stop further evaluation. - E.g. - rand_recurse((5+protect(2))*x^protect(2)+3*x+7); - rand_recurse(sin([x,y,z])); -*/ -rand_recurse(ex) := block( - if (integerp(ex) or floatnump(ex) or matrixp(ex) or listp(ex)) then return(rand(ex)), - if atom(ex) then return(ex), - if op(ex)=protect then return(first(args(ex))), - apply(op(ex),maplist(rand_recurse,args(ex))) - ); - -/* Truncates a polynomial to only terms of degree "d" or less - always expands out */ -poly_truncate(pa,d) := apply("+",maplist(lambda([ex],if hipow(ex,x)>d then 0 else ex), args(expand(pa)))); - -/****************************************************************/ -/* Inequality functions for STACK */ -/* */ -/* Chris Sangwin, <chris@sangwin.com> */ -/* V0.2 July 2013 */ -/* */ -/****************************************************************/ - -/* Determines if we have a linear inequality in one variable */ -linear_inequalityp(ex) := block([ex2], - if atom(ex) then return(false), - if not(">"= op(ex) or "<"= op(ex) or ">="= op(ex) or "<="= op(ex)) then return(false), - ex2:ineqprepare(ex), - if not(is(length(listofvars(ex2))=1)) then return(false), - if is(degree(lhs(ex2),first(listofvars(ex2)))=1) then return(true), - return(false) -)$ - - -/* Reverses the inequality: purely syntactic. */ -rev_ineq(ex):=block( - if safe_op(ex)="<" then return(rhs(ex)>lhs(ex)), - if safe_op(ex)="<=" then return(rhs(ex)>=lhs(ex)), - if safe_op(ex)=">" then return(rhs(ex)<lhs(ex)), - if safe_op(ex)=">=" then return(rhs(ex)<=lhs(ex)), - return(ex) -)$ - -/* Reformat an inequality in an easier to read form, namely a<x or x<a: a syntactic transformation. */ -inequality_disp(ex):=block([ex2,v], - if not(linear_inequalityp(ex)) then return(ex), - ex2:ineqprepare(ex), - v:first(listofvars(ex2)), - if equal(coeff(lhs(ex2),v),1) then return(rev_ineq(subst(op(ex2),"=",first(solve(lhs(ex2),v))))), - if equal(coeff(lhs(ex2),v),-1) then return(neg_ineq(subst(op(ex2),"=",first(solve(lhs(ex2),v))))), - return(ex) -)$ - -/* Does the expression define a *single* interval, by means of an inequality? */ -/* E.g. 1<x and x<7 */ -/* We only accept linear inequalities in one variable, combined by "and" */ -/* We don't expect this to be the *simplest* form, that is later. */ -/* A single inequality is a half open interval. */ -/* true is the whole real line, false is the empty set. */ -interval_inequalityp(ex):= block( - /* Emptyset and real line. */ - if equal(ex, true) then return(true), - if equal(ex, false) then return(true), - if atom(ex) then return(false), - /* Half open intervals */ - if linear_inequalityp(ex) then return(true), - if not(op(ex)="and") then return(false), - if is(length(listofvars(ex))>1) then return(false), - return(all_listp(linear_inequalityp, args(ex))) -)$ - -/* Takes a real interval and returns the canonical form for this inequality */ -/* a<x and x<b */ -/* or, true, false, or a single inequality */ -interval_simplify(ex):=block([ex2,v,a,b], - if not(interval_inequalityp(ex)) then return(ex), - /* We know we have an interval inequality. */ - if equal(ex, true) then return(true), - if equal(ex, false) then return(false), - /* Remove redundant inequalities: might leave us with a single one. */ - ex:ineq_rem_redundant(ex), - if linear_inequalityp(ex) then return(inequality_disp(ex)), - /* Now we are in business. We have a single interval, of two inequalities. */ - ex:map(inequality_disp,ex), - v:listofvars(ex), - if equal(v,lhs(first(ex))) then ex:second(args(ex)) and first(args(ex)), - /* This should now be in the right form. */ - /* Check for an empty set (2 possibilities) */ - if (lhs(first(args(ex))))>(rhs(second(args(ex)))) then return(false), - if (lhs(first(args(ex))))=(rhs(second(args(ex)))) and not(safe_op(first(args(ex)))="<=" and safe_op(second(args(ex)))="<=") then return(false), - ex -)$ - -/* This removes redundant linear inequalities such as x>1 or x>0 -> x>0 */ -ineq_rem_redundant(ex) := block([exl,exn,exg,exl,exo,exv], - if atom(ex) then return(ex), - if not(op(ex)="and" or op(ex)="or") then return(ex), - /* Recurse over the expression */ - ex:apply(op(ex),maplist(ineq_rem_redundant,args(ex))), - if op(ex)="and" then exo:[max,min] else exo:[min,max], - exn:sublist(args(ex),lambda([ex2],not(linear_inequalityp(ex2)))), - exl:sublist(args(ex),linear_inequalityp), - /* Separate out different variables */ - exv:listofvars(exl), - exl:maplist(lambda([ex],sublist(exl,lambda([ex2],is(listofvars(ex2)=[ex])))),exv), - /* At this point we have linear inequalities, in a single variable, separated out into lists for each individual variable. */ - exl:maplist(lambda([ex],single_linear_ineq_reduce(ex,exo)),exl), - exl:flatten(exl), - apply(op(ex),append(exn,exl)) - )$ - -/* Take a list of linear inequalities the same single variable, and an list of operators, min/max. - Returns the equivalent inequalities. -*/ -single_linear_ineq_reduce(ex,exo):=block([exg,exl], - ex:maplist(ineqprepare,ex), - /* Separate out into x>?, x>=? and x<?, x<=?. */ - exg:sublist(ex,lambda([ex2],is(coeff(lhs(ex2),first(listofvars(ex2)))=1))), - exl:sublist(ex,lambda([ex2],is(coeff(lhs(ex2),first(listofvars(ex2)))=-1))), - /* Separate into solution and operator */ - exg:single_linear_ineq_reduce_h(exg,first(exo),true), - exl:single_linear_ineq_reduce_h(exl,second(exo),false), - append(exg,exl) -)$ - -/* Take a list of linear inequalities of the same sign, in a single variable, and an operator, min/max. - Return the single equivalent inequality. -*/ -single_linear_ineq_reduce_h(exl,exo,odr):=block([m1,m2,m3,exg], - if exl=[] then return([]), - if not(is(exo=max) or is(exo=min)) then print("ERROR: single_linear_ineq_reduce_h expects second argument to be max or min."), - exg:maplist(lambda([ex2],[rhs(first(solve(lhs(ex2)))),op(ex2)]),exl), - m1:apply(exo, maplist(first,exg)), - m2:sublist(exg,lambda([ex2],is(m1=first(ex2)))), - m3:sort(listify(setify(maplist(second,m2)))), /* get list of operators. Used to sort out >, >= etc. */ - if (not(odr) and is(exo=max)) or (odr and is(exo=min)) then m3:reverse(m3), - [apply(first(m3),if odr then [first(listofvars(exl)),m1] else [m1,first(listofvars(exl))])] -)$ - -/* Solve a single inequality in a single variable by factoring, where possible expressing the result as irreducible inequalities. */ -factor_ineq_solve(ex):=block([ex2,ex3,exop,m,fl,p], - if not(inequalityp(ex)) then return(ex), - if length(listofvars(ex))#1 then return(ex), - ex2:ineqprepare(ex), - exop:op(ex2), /* This is for >, >= */ - ex2:factor(lhs(ex2)), - if atom(ex2) then return(ex), - /* Create a list of factors */ - if is(op(ex2)="-") then m:true else m:false, - if m then fl:first(args(ex2)) else fl:ex2, - if safe_op(fl)="*" then fl:args(fl) else fl:[fl], - /* Turn each inequality back into a list */ - ex2:maplist(lambda([ex],apply(exop,[ex,0])),fl), - if m then ex2[1]:neg_ineq(ex2[1]), - /* Create a list of all even permutations, from which we negate those in the list */ - p:sublist(maplist(listify,listify(powerset(setify(makelist(n,n,length(ex2)))))),lambda([ex],evenp(length(ex)))), - ex3:maplist(lambda([l],neg_ineq_list(copylist(ex2),l)),p), - /* Tidy up the list */ - ex3:maplist(lambda([ex],ineq_rem_redundant(apply("and",ex))),ex3), - ex3:maplist(interval_simplify,ex3), - ex3:reverse(sort(ex3)), - ex3:apply("or",ex3) -)$ - -/* Negates the inequality */ -neg_ineq(ex):=block( - if safe_op(ex)="<" then return(lhs(ex)>rhs(ex)), - if safe_op(ex)="<=" then return(lhs(ex)>=rhs(ex)), - if safe_op(ex)=">" then return(lhs(ex)<rhs(ex)), - if safe_op(ex)=">=" then return(lhs(ex)<=rhs(ex)), - return(ex) -)$ - -/* This function takes a list of inequalities, ex and a list of index numbers l, and negates each inequality as indexed by l */ -neg_ineq_list(ex,l):=block([k], - if emptyp(l) then return(ex), - for k: 1 thru length(l) do ex[l[k]]:neg_ineq(ex[l[k]]), - ex -)$ - - -/****************************************************************/ -/* Reporting support functions for STACK */ -/* */ -/* Chris Sangwin, <chris@sangwin.com> */ -/* V0.1 January 2013 */ -/* */ -/****************************************************************/ - -/* Sample ways of representing a PRT in which we might have errors */ - -/* Evaluate a single node safely. */ -node_no(prt,num,inputs) := block([res,err], - /* Type checking */ - if not(listp(prt)) then (print("STACK exception: node_no expects its first argument to be a list."), return(false)), - if not(integerp(num)) then (print("STACK exception: node_no expects its second argument to be an integer."), return(false)), - if is(length(prt)<num) then (print("STACK exception: node_no expects its second argument to less than the length of the first."), return(false)), - /* Do computation */ - res:errcatch(ev(prt[num],inputs,nouns)), - if is([] = res) then - print(concat("Previous error generated by node number ", string(num), ".")), - if is([] = res) then - [] - else - first(res) - ); - -/* Actually traverse the PRT with given inputs */ -/* Inputs should be in the form of equations such as [ans1=x^2] */ -traverse_prt(inputs) := block( - /* Type checking */ - if not(listp(inputs)) then (print("STACK exception: traverse_prt expects its argument to be a list."), return(false)), - if not(alllistp(equationp,inputs)) then (print("STACK exception: traverse_prt expects its argument to be a list of equations."), return(false)), - /* Setup PRT */ - simp:false, - PRTtests:[ - 'ATAlgEquiv(ans1,x^3), - 'ATInt(ans2,[x^3,x]), - 'ATInt(ans2/0,[x^3,x]) - ], - quiet:[false,false,false], - nexttrue:[2,3,1], - nextfalse:[1,1,1], - /* Creatlist to store previously visited nodes */ - visited:makelist(false, length(PRTtests)), - current_node:1, - feedback:[], - answernote:[], - /* Actually traverse the tree */ - while not(visited[current_node]) do block([res], - visited[current_node]:true, - res:node_no(PRTtests,current_node,inputs), - if not(listp(res)) then return(false), - /* Feedback */ - if not(quiet[current_node]) then feedback:cons(res[4], feedback), - feedback:cons(concat("[STACK-feedback:",string(current_node),"-",string(res[2]),"]"), feedback), - /* Answernotes */ - if not(is(res[3] = "")) then answernote:cons(res[3], answernote), - answernote:cons(concat(string(current_node),"-",string(res[2])), answernote), - /* Update to next node */ - if res[2] then - current_node:nexttrue[current_node] - else - current_node:nextfalse[current_node] - ), - answernote:simplode(reverse(sublist(answernote, lambda([ex],not(is(ex=""))))), " | " ), - feedback:simplode(reverse(sublist(feedback, lambda([ex],not(is(ex=""))))), " | " ), - [answernote, feedback] -)$ - -print("[ STACK-reports started. ]")$ - -/****************************************************************/ -/* Unary minus functions for STACK */ -/* */ -/* Chris Sangwin, <chris@sangwin.com> */ -/* V0.1 March 2014 */ -/* */ -/****************************************************************/ - -/* Transforms --x into x recursively in the case simp:false */ -unary_minus_minus_simp(ex) := block( - if atom(ex) then return(ex), - if op(ex) = "-" and first(args(ex))<0 then return(ev(ex,simp)), - if op(ex) = "-" and atom(first(args(ex))) then return(ex), - if op(ex) = "-" and op(first(args(ex))) = "-" then return(first(args(first(args(ex))))), - apply(op(ex), map(unary_minus_minus_simp, args(ex)) ) -)$ - -/* Transforms --x into x recursively in the case simp:false */ -unary_minus_add_distrib(ex) := block( - if atom(ex) then return(ex), - if op(ex) = "-" and atom(first(args(ex))) then return(ex), - if op(ex) = "-" and op(first(args(ex))) = "+" then return(apply("+", map(lambda([ex2],-ex2), args(first(args(ex)))))), - apply(op(ex), map(unary_minus_add_distrib, args(ex)) ) -)$ - diff --git a/stack/2014083000/maxima/mathml.lisp b/stack/2014083000/maxima/mathml.lisp deleted file mode 100644 index 7671dad..0000000 --- a/stack/2014083000/maxima/mathml.lisp +++ /dev/null @@ -1,762 +0,0 @@ -(in-package "MAXIMA") -;; MathML-printing -;; Created by David Drysdale (DMD), December 2002/January 2003 -;; -;; closely based on the original TeX conversion code in mactex.lisp, -;; for which the following credits apply: -;; (c) copyright 1987, Richard J. Fateman -;; small corrections and additions: Andrey Grozin, 2001 -;; additional additions: Judah Milgram (JM), September 2001 -;; additional corrections: Barton Willis (BLW), October 2001 - -;; Usage: mathml(d8,"/tmp/foo.xml"); mathml(d10,"/tmp/foo.xml"); .. -;; to append lines d8 and d10 to the mathml file. If given only -;; one argument the result goes to standard output. - -;; Method: - -;; Producing MathML from a macsyma internal expression is done by -;; a reversal of the parsing process. Fundamentally, a -;; traversal of the expression tree is produced by the program, -;; with appropriate substitutions and recognition of the -;; infix / prefix / postfix / matchfix relations on symbols. Various -;; changes are made to this so that MathML will like the results. - -;; Instructions: -;; in macsyma, type mathml(<expression>); or mathml(<label>); or -;; mathml(<expr-or-label>, <file-name>); In the case of a label, -;; an equation-number will also be produced. -;; in case a file-name is supplied, the output will be sent -;; (perhaps appended) to that file. - -(macsyma-module mathml) - -#+franz -($bothcases t) ;; allow alpha and Alpha to be different -(declare-top - (special lop rop ccol $gcprint texport $labels $inchar - vaxima-main-dir - ) - (*expr mathml-lbp mathml-rbp)) - -;; top level command the result of converting the expression x. - -(defmspec $mathml(l) ;; mexplabel, and optional filename - ;;if filename supplied but 'nil' then return a string - (let ((args (cdr l))) - (cond ((and (cdr args) (null (cadr args))) - (let ((*standard-output* (make-string-output-stream))) - (apply 'mathml1 args) - (get-output-stream-string *standard-output*) - ) - ) - (t (apply 'mathml1 args))))) - -(defun mathml1 (mexplabel &optional filename ) ;; mexplabel, and optional filename - (prog (mexp texport $gcprint ccol x y itsalabel tmpport) - ;; $gcprint = nil turns gc messages off - (setq ccol 1) - (cond ((null mexplabel) - (displa " No eqn given to MathML") - (return nil))) - ;; collect the file-name, if any, and open a port if needed - (setq texport (cond((null filename) *standard-output* ); t= output to terminal - (t - (open (string (stripdollar filename)) - :direction :output - :if-exists :append - :if-does-not-exist :create)))) - ;; go back and analyze the first arg more thoroughly now. - ;; do a normal evaluation of the expression in macsyma - (setq mexp (meval mexplabel)) - (cond ((memq mexplabel $labels); leave it if it is a label - (setq mexplabel (concat "(" (stripdollar mexplabel) ")")) - (setq itsalabel t)) - (t (setq mexplabel nil)));flush it otherwise - - ;; maybe it is a function? - (cond((symbolp (setq x mexp)) ;;exclude strings, numbers - (setq x ($verbify x)) - (cond ((setq y (mget x 'mexpr)) - (setq mexp (list '(mdefine) (cons (list x) (cdadr y)) (caddr y)))) - ((setq y (mget x 'mmacro)) - (setq mexp (list '(mdefmacro) (cons (list x) (cdadr y)) (caddr y)))) - ((setq y (mget x 'aexpr)) - (setq mexp (list '(mdefine) (cons (list x 'array) (cdadr y)) (caddr y))))))) - (cond ((and (null (atom mexp)) - (memq (caar mexp) '(mdefine mdefmacro))) - (format texport "<pre>~%" ) - (cond (mexplabel (format texport "~a " mexplabel))) - ;; need to get rid of "<" signs - (setq tmpport (make-string-output-stream)) - (mgrind mexp tmpport) - (close tmpport) - (format texport "~a" - (string-substitute "<" #\< (get-output-stream-string tmpport))) - (format texport ";~%</pre>")) - - ((and - itsalabel ;; but is it a user-command-label? - (eq (getchar $inchar 2) (getchar mexplabel 2))) - ;; aha, this is a C-line: do the grinding: - (format texport "<pre>~%~a " mexplabel) - ;; need to get rid of "<" signs - (setq tmpport (make-string-output-stream)) - (mgrind mexp tmpport) - (close tmpport) - (format texport "~a" - (string-substitute "<" #\< (get-output-stream-string tmpport))) - (format texport ";~%</pre>")) - - (t ; display the expression for MathML now: - (myprinc "<math xmlns='http://www.w3.org/1998/Math/MathML'> ") - (mapc #'myprinc - ;;initially the left and right contexts are - ;; empty lists, and there are implicit parens - ;; around the whole expression - (mathml mexp nil nil 'mparen 'mparen)) - (cond (mexplabel - (format texport "<mspace width='verythickmathspace'/> <mtext>~a</mtext> " mexplabel))) - (format texport "</math>"))) - (cond(filename(terpri texport); and drain port if not terminal - (close texport))) - (return mexplabel))) - -(defun mathml (x l r lop rop) - ;; x is the expression of interest; l is the list of strings to its - ;; left, r to its right. lop and rop are the operators on the left - ;; and right of x in the tree, and will determine if parens must - ;; be inserted - (setq x (nformat x)) - (cond ((atom x) (mathml-atom x l r)) - ((or (<= (mathml-lbp (caar x)) (mathml-rbp lop)) - (> (mathml-lbp rop) (mathml-rbp (caar x)))) - (mathml-paren x l r)) - ;; special check needed because macsyma notates arrays peculiarly - ((memq 'array (cdar x)) (mathml-array x l r)) - ;; dispatch for object-oriented mathml-ifiying - ((get (caar x) 'mathml) (funcall (get (caar x) 'mathml) x l r)) - (t (mathml-function x l r nil)))) - -(defun string-substitute (newstring oldchar x &aux matchpos) - (setq matchpos (position oldchar x)) - (if (null matchpos) x - (concatenate 'string - (subseq x 0 matchpos) - newstring - (string-substitute newstring oldchar (subseq x (1+ matchpos)))))) - -;;; NOTE that we try to include spaces after closing tags (e.g. "</mwhatever> ") -;;; so that the line breaking algorithm in myprinc has some spaces where it -;;; can choose to line break. - -;;; First we have the functions which are called directly by mathml and its -;;; descendents - -(defun mathml-atom (x l r) - (append l - (list (cond ((numberp x) (mathmlnumformat x)) - ((mstringp x) (string-left-trim '(#\&) x)) - ((and (symbolp x) (get x 'mathmlword))) - (t (mathml-stripdollar x)))) - r)) - -(defun mathmlnumformat(atom) - (let (r firstpart exponent) - (cond ((integerp atom) - (strcat "<mn>" (format nil "~d" atom) "</mn> ")) - (t - (setq r (explode atom)) - (setq exponent (member 'e r :test #'string-equal));; is it ddd.ddde+EE - (cond ((null exponent) - ;; it is not. go with it as given - (strcat "<mn>" (format nil "~s" atom) "</mn> ")) - (t - (setq firstpart - (nreverse (cdr (member 'e (reverse r) :test #'string-equal)))) - (strcat - "<mrow><mn>" - (apply #'strcat firstpart) - "</mn><mo>×</mo> <msup><mn>10</mn><mn>" - (apply #'strcat (cdr exponent)) - "</mn></msup> </mrow> ") - )))))) - -(defun mathml-stripdollar(sym) - (or (symbolp sym) - (return-from mathml-stripdollar sym)) - (let* ((pname (string-left-trim '(#\$) (symbol-name sym))) - (l (length pname)) - (begin-sub - (loop for i downfrom (1- l) - when (not (digit-char-p (aref pname i))) - do (return (1+ i))))) - (cond ((< begin-sub l) ;; need to do subscripting - (strcat "<msub><mi>" - (subseq pname 0 begin-sub) - "</mi> <mn>" - (subseq pname begin-sub l) - "</mn></msub> ")) - (t ;; no subscripting needed - (strcat "<mi>" pname "</mi> "))))) - -(defun mathml-paren (x l r) - (mathml x (append l '("<mfenced separators=''>")) (cons "</mfenced> " r) 'mparen 'mparen)) - -(defun mathml-array (x l r) - (let ((f)) - (if (eq 'mqapply (caar x)) - (setq f (cadr x) - x (cdr x) - l (mathml f (append l (list "<mfenced separators=','>")) - (list "</mfenced> ") 'mparen 'mparen)) - (setq f (caar x) - l (mathml (mathmlword f) (append l '("<msub><mrow>")) nil lop 'mfunction))) - (setq - r (nconc (mathml-list (cdr x) nil (list "</mrow></msub> ") "<mo>,</mo>") r)) - (nconc l (list "</mrow><mrow>") r ))) - -;; set up a list , separated by symbols (, * ...) and then tack on the -;; ending item (e.g. "]" or perhaps ")" -(defun mathml-list (x l r sym) - (if (null x) r - (do ((nl)) - ((null (cdr x)) - (setq nl (nconc nl (mathml (car x) l r 'mparen 'mparen))) - nl) - (setq nl (nconc nl (mathml (car x) l (list sym) 'mparen 'mparen)) - x (cdr x) - l nil)))) - -;; we could patch this so sin x rather than sin(x), but instead we made sin a prefix -;; operator -(defun mathml-function (x l r op) op - (setq l (mathml (mathmlword (caar x)) l nil 'mparen 'mparen) - r (mathml (cons '(mprogn) (cdr x)) nil r 'mparen 'mparen)) - (nconc l r)) - -;;; Now we have functions which are called via property lists - -(defun mathml-prefix (x l r) - (mathml (cadr x) (append l (mathmlsym (caar x))) r (caar x) rop)) - -(defun mathml-infix (x l r) - ;; check for 2 args - (if (or (null (cddr x)) (cdddr x)) (wna-err (caar x))) - (setq l (mathml (cadr x) l nil lop (caar x))) - (mathml (caddr x) (append l (mathmlsym (caar x))) r (caar x) rop)) - -(defun mathml-postfix (x l r) - (mathml (cadr x) l (append (mathmlsym (caar x)) r) lop (caar x))) - -(defun mathml-nary (x l r) - (let* ((op (caar x)) (sym (mathmlsym op)) (y (cdr x)) (ext-lop lop) (ext-rop rop)) - (cond ((null y) (mathml-function x l r t)) ; this should not happen - ((null (cdr y)) (mathml-function x l r t)) ; this should not happen, too - (t (do ((nl) (lop ext-lop op) (rop op (if (null (cdr y)) ext-rop op))) - ((null (cdr y)) (setq nl (nconc nl (mathml (car y) l r lop rop))) nl) - (setq nl (nconc nl (mathml (car y) l (list sym) lop rop)) - y (cdr y) - l nil)))))) - -(defun mathml-nofix (x l r) (mathml (caar x) l r (caar x) rop)) - -(defun mathml-matchfix (x l r) - (setq l (append l (car (mathmlsym (caar x)))) - ;; car of mathmlsym of a matchfix operator is the lead op - r (append (cdr (mathmlsym (caar x))) r) - ;; cdr is the trailing op - x (mathml-list (cdr x) nil r "<mo>,</mo>")) - (append l x)) - -(defun mathmlsym (x) (or (get x 'mathmlsym) (get x 'strsym)(get x 'dissym) - (stripdollar x))) - -(defun mathmlword (x)(or (get x 'mathmlword) (stripdollar x))) - -(defprop bigfloat mathml-bigfloat mathml) - -(defun mathml-bigfloat (x l r) (declare (ignore l r)) (fpformat x)) - -(defprop mprog "<mi>block</mi><mspace width='mediummathspace'/> " mathmlword) -(defprop %erf "<mi>erf</mi> " mathmlword) -(defprop $erf "<mi>erf</mi> " mathmlword) ;; etc for multicharacter names -(defprop $true "<mi>true</mi> " mathmlword) -(defprop $false "<mi>false</mi> " mathmlword) - -(defprop mprogn mathml-matchfix mathml) ;; mprogn is (<progstmnt>, ...) -(defprop mprogn (("<mfenced separators=''>") "</mfenced> ") mathmlsym) - -(defprop mlist mathml-matchfix mathml) -(defprop mlist (("<mfenced separators='' open='[' close=']'>")"</mfenced> ") mathmlsym) - -;;absolute value -(defprop mabs mathml-matchfix mathml) -(defprop mabs (("<mfenced separators='' open='|' close='|'>")"</mfenced> ") mathmlsym) - -(defprop mqapply mathml-mqapply mathml) - -(defun mathml-mqapply (x l r) - (setq l (mathml (cadr x) l (list "(" ) lop 'mfunction) - r (mathml-list (cddr x) nil (cons ")" r) "<mo>,</mo>")) - (append l r));; fixed 9/24/87 RJF - -(defprop $%i "<mi>ⅈ</mi> " mathmlword) -(defprop $%pi "<mi>π</mi> " mathmlword) -(defprop $%e "<mi>ⅇ</mi> " mathmlword) -(defprop $inf "<mi>∞</mi> " mathmlword) -(defprop $minf "<mi>-∞</mi> " mathmlword) -(defprop %laplace "<mo>ℒ</mo>" mathmlword) -(defprop $alpha "<mi>α</mi> " mathmlword) -(defprop $beta "<mi>β</mi> " mathmlword) -(defprop $gamma "<mi>γ</mi> " mathmlword) -(defprop %gamma "<mi>Γ</mi> " mathmlword) -(defprop $delta "<mi>δ</mi> " mathmlword) -(defprop $epsilon "<mi>ε</mi> " mathmlword) -(defprop $zeta "<mi>ζ</mi> " mathmlword) -(defprop $eta "<mi>η</mi> " mathmlword) -(defprop $theta "<mi>θ</mi> " mathmlword) -(defprop $iota "<mi>ι</mi> " mathmlword) -(defprop $kappa "<mi>κ</mi> " mathmlword) -;(defprop $lambda "<mi>λ</mi> " mathmlword) -(defprop $mu "<mi>μ</mi> " mathmlword) -(defprop $nu "<mi>ν</mi> " mathmlword) -(defprop $xi "<mi>ξ</mi> " mathmlword) -(defprop $pi "<mi>π</mi> " mathmlword) -(defprop $rho "<mi>ρ</mi> " mathmlword) -(defprop $sigma "<mi>σ</mi> " mathmlword) -(defprop $tau "<mi>τ</mi> " mathmlword) -(defprop $upsilon "<mi>υ</mi> " mathmlword) -(defprop $phi "<mi>φ</mi> " mathmlword) -(defprop $chi "<mi>χ</mi> " mathmlword) -(defprop $psi "<mi>ψ</mi> " mathmlword) -(defprop $omega "<mi>ω</mi> " mathmlword) - -(defprop mquote mathml-prefix mathml) -(defprop mquote ("<mo>'</mo>") mathmlsym) -(defprop mquote 201. mathml-rbp) - -(defprop msetq mathml-infix mathml) -(defprop msetq ("<mo>:</mo>") mathmlsym) -(defprop msetq 180. mathml-rbp) -(defprop msetq 20. mathml-rbp) - -(defprop mset mathml-infix mathml) -(defprop mset ("<mo>::</mo>") mathmlsym) -(defprop mset 180. mathml-lbp) -(defprop mset 20. mathml-rbp) - -(defprop mdefine mathml-infix mathml) -(defprop mdefine ("<mo>:=</mo>") mathmlsym) -(defprop mdefine 180. mathml-lbp) -(defprop mdefine 20. mathml-rbp) - -(defprop mdefmacro mathml-infix mathml) -(defprop mdefmacro ("<mo>::=</mo>") mathmlsym) -(defprop mdefmacro 180. mathml-lbp) -(defprop mdefmacro 20. mathml-rbp) - -(defprop marrow mathml-infix mathml) -(defprop marrow ("<mo>→</mo>") mathmlsym) -(defprop marrow 25 mathml-lbp) -(defprop marrow 25 mathml-rbp) - -(defprop mfactorial mathml-postfix mathml) -(defprop mfactorial ("<mo>!</mo>") mathmlsym) -(defprop mfactorial 160. mathml-lbp) - -(defprop mexpt mathml-mexpt mathml) -(defprop mexpt 140. mathml-lbp) -(defprop mexpt 139. mathml-rbp) - -(defprop %sum 110. mathml-rbp) ;; added by BLW, 1 Oct 2001 -(defprop %product 115. mathml-rbp) ;; added by BLW, 1 Oct 2001 - -;; insert left-angle-brackets for mncexpt. a^<n> is how a^^n looks. -(defun mathml-mexpt (x l r) - (let((nc (eq (caar x) 'mncexpt))); true if a^^b rather than a^b - ;; here is where we have to check for f(x)^b to be displayed - ;; as f^b(x), as is the case for sin(x)^2 . - ;; which should be sin^2 x rather than (sin x)^2 or (sin(x))^2. - ;; yet we must not display (a+b)^2 as +^2(a,b)... - ;; or (sin(x))^(-1) as sin^(-1)x, which would be arcsine x - (cond ;; this whole clause - ;; should be deleted if this hack is unwanted and/or the - ;; time it takes is of concern. - ;; it shouldn't be too expensive. - ((and (eq (caar x) 'mexpt) ; don't do this hack for mncexpt - (let* - ((fx (cadr x)); this is f(x) - (f (and (not (atom fx)) (atom (caar fx)) (caar fx))) ; this is f [or nil] - (bascdr (and f (cdr fx))) ; this is (x) [maybe (x,y..), or nil] - (expon (caddr x)) ;; this is the exponent - (doit (and - f ; there is such a function - (memq (getchar f 1) '(% $)) ;; insist it is a % or $ function - (not (memq f '(%sum %product %derivative %integrate %at - %lsum %limit))) ;; what else? what a hack... - (or (and (atom expon) (not (numberp expon))) ; f(x)^y is ok - (and (atom expon) (numberp expon) (> expon 0)))))) - ; f(x)^3 is ok, but not f(x)^-1, which could - ; inverse of f, if written f^-1 x - ; what else? f(x)^(1/2) is sqrt(f(x)), ?? - (cond (doit - (setq l (mathml `((mexpt) ,f ,expon) l nil 'mparen 'mparen)) - (if (and (null (cdr bascdr)) - (eq (get f 'mathml) 'mathml-prefix)) - (setq r (mathml (car bascdr) nil r f 'mparen)) - (setq r (mathml (cons '(mprogn) bascdr) nil r 'mparen 'mparen)))) - (t nil))))) ; won't doit. fall through - (t (setq l (mathml (cadr x) (append l '("<msup><mrow>")) nil lop (caar x)) - r (if (mmminusp (setq x (nformat (caddr x)))) - ;; the change in base-line makes parens unnecessary - (if nc - (mathml (cadr x) '("</mrow> <mfenced separators='' open='<' close='>'> -")(cons "</mfenced></msup> " r) 'mparen 'mparen) - (mathml (cadr x) '("</mrow> <mfenced separators=''> -")(cons "</mfenced></msup> " r) 'mparen 'mparen)) - (if nc - (mathml x (list "</mrow> <mfenced separators='' open='<' close='>'>")(cons "</mfenced></msup>" r) 'mparen 'mparen) - (if (and (numberp x) (< x 10)) - (mathml x (list "</mrow> ")(cons "</msup> " r) 'mparen 'mparen) - (mathml x (list "</mrow> <mrow>")(cons "</mrow><mrow> " r) 'mparen 'mparen)) - ))))) - (append l r))) - -(defprop mncexpt mathml-mexpt mathml) - -(defprop mncexpt 135. mathml-lbp) -(defprop mncexpt 134. mathml-rbp) - -(defprop mnctimes mathml-nary mathml) -(defprop mnctimes "<mi>⋯</mi> " mathmlsym) -(defprop mnctimes 110. mathml-lbp) -(defprop mnctimes 109. mathml-rbp) - -(defprop mtimes mathml-nary mathml) -(defprop mtimes "<mspace width='thinmathspace'/>" mathmlsym) -(defprop mtimes 120. mathml-lbp) -(defprop mtimes 120. mathml-rbp) - -(defprop %sqrt mathml-sqrt mathml) - -(defun mathml-sqrt(x l r) - ;; format as \\sqrt { } assuming implicit parens for sqr grouping - (mathml (cadr x) (append l '("<msqrt>")) (append '("</msqrt>") r) 'mparen 'mparen)) - -;; macsyma doesn't know about cube (or nth) roots, -;; but if it did, this is what it would look like. -(defprop $cubrt mathml-cubrt mathml) - -(defun mathml-cubrt (x l r) - (mathml (cadr x) (append l '("<mroot><mrow>")) (append '("</mrow>3</mroot>") r) 'mparen 'mparen)) - -(defprop mquotient mathml-mquotient mathml) -(defprop mquotient ("<mo>/</mo>") mathmlsym) -(defprop mquotient 122. mathml-lbp) ;;dunno about this -(defprop mquotient 123. mathml-rbp) - -(defun mathml-mquotient (x l r) - (if (or (null (cddr x)) (cdddr x)) (wna-err (caar x))) - (setq l (mathml (cadr x) (append l '("<mfrac><mrow>")) nil 'mparen 'mparen) - r (mathml (caddr x) (list "</mrow> <mrow>") (append '("</mrow></mfrac> ")r) 'mparen 'mparen)) - (append l r)) - -(defprop $matrix mathml-matrix mathml) - -(defun mathml-matrix(x l r) ;;matrix looks like ((mmatrix)((mlist) a b) ...) - (append l `("<mfenced separators='' open='(' close=')'><mtable>") - (mapcan #'(lambda(y) - (mathml-list (cdr y) (list "<mtr><mtd>") (list "</mtd></mtr> ") "</mtd><mtd>")) - (cdr x)) - '("</mtable></mfenced> ") r)) - -;; macsyma sum or prod is over integer range, not low <= index <= high -;; Mathml is lots more flexible .. but - -(defprop %sum mathml-sum mathml) -(defprop %lsum mathml-lsum mathml) -(defprop %product mathml-sum mathml) - -;; easily extended to union, intersect, otherops - -(defun mathml-lsum(x l r) - (let ((op (cond ((eq (caar x) '%lsum) "<mrow><munder><mo>∑</mo> <mrow>") - ;; extend here - )) - ;; gotta be one of those above - (s1 (mathml (cadr x) nil nil 'mparen rop));; summand - (index ;; "index = lowerlimit" - (mathml `((min simp) , (caddr x), (cadddr x)) nil nil 'mparen 'mparen))) - (append l `( ,op ,@index "</mrow></munder> <mrow>" ,@s1 "</mrow></mrow> ") r))) - -(defun mathml-sum(x l r) - (let ((op (cond ((eq (caar x) '%sum) "<mrow><munderover><mo>∑</mo><mrow>") - ((eq (caar x) '%product) "<mrow><munderover><mo>∏</mo><mrow>") - ;; extend here - )) - ;; gotta be one of those above - (s1 (mathml (cadr x) nil nil 'mparen rop));; summand - (index ;; "index = lowerlimit" - (mathml `((mequal simp) ,(caddr x),(cadddr x)) nil nil 'mparen 'mparen)) - (toplim (mathml (car(cddddr x)) nil nil 'mparen 'mparen))) - (append l `( ,op ,@index "</mrow> <mrow>" ,@toplim "</mrow></munderover> <mrow>" ,@s1 "</mrow></mrow> ") r))) - -(defprop %integrate mathml-int mathml) - -(defun mathml-int (x l r) - (let ((s1 (mathml (cadr x) nil nil 'mparen 'mparen));;integrand delims / & d - (var (mathml (caddr x) nil nil 'mparen rop))) ;; variable - (cond((= (length x) 3) - (append l `("<mrow><mo>∫</mo><mrow>" ,@s1 "</mrow> <mspace width='mediummathspace'/> <mrow><mo>ⅆ</mo><mi>" ,@var "</mi></mrow></mrow> ") r)) - (t ;; presumably length 5 - (let ((low (mathml (nth 3 x) nil nil 'mparen 'mparen)) - ;; 1st item is 0 - (hi (mathml (nth 4 x) nil nil 'mparen 'mparen))) - (append l `("<mrow><munderover><mo>∫</mo> <mrow>" ,@low "</mrow> <mrow>" ,@hi "</mrow> </munderover> <mrow>" ,@s1 "</mrow> <mspace width='mediummathspace'/> <mrow><mo>ⅆ</mo><mi>" ,@var "</mi> </mrow></mrow> ") r)))))) - -(defprop %limit mathml-limit mathml) - -(defprop mrarr mathml-infix mathml) -(defprop mrarr ("<mo>→</mo> ") mathmlsym) -(defprop mrarr 80. mathml-lbp) -(defprop mrarr 80. mathml-rbp) - -(defun mathml-limit(x l r) ;; ignoring direction, last optional arg to limit - (let ((s1 (mathml (second x) nil nil 'mparen rop));; limitfunction - (subfun ;; the thing underneath "limit" - (mathml `((mrarr simp) ,(third x) ,(fourth x)) nil nil 'mparen 'mparen))) - (append l `("<munder><mo>lim</mo><mrow>" ,@subfun "</mrow> </munder> <mrow>" ,@s1 "</mrow>") r))) - -(defprop %at mathml-at mathml) - -;; e.g. at(diff(f(x)),x=a) -(defun mathml-at (x l r) - (let ((s1 (mathml (cadr x) nil nil lop rop)) - (sub (mathml (caddr x) nil nil 'mparen 'mparen))) - (append l '("<msub><mfenced separators='' open='' close='|'>") s1 '("</mfenced> <mrow>") sub '("</mrow> </msub> ") r))) - -;;binomial coefficients - -(defprop %binomial mathml-choose mathml) - -(defun mathml-choose (x l r) - `(,@l - "<mfenced separators='' open='(' close=')'><mtable><mtr><mtd>" - ,@(mathml (cadr x) nil nil 'mparen 'mparen) - "</mtd></mtr> <mtr><mtd>" - ,@(mathml (caddr x) nil nil 'mparen 'mparen) - "</mtd></mtr> </mtable></mfenced> " - ,@r)) - - -(defprop rat mathml-rat mathml) -(defprop rat 120. mathml-lbp) -(defprop rat 121. mathml-rbp) -(defun mathml-rat(x l r) (mathml-mquotient x l r)) - -(defprop mplus mathml-mplus mathml) -(defprop mplus 100. mathml-lbp) -(defprop mplus 100. mathml-rbp) - -(defun mathml-mplus (x l r) - ;(declare (fixnum w)) - (cond ((memq 'trunc (car x))(setq r (cons "<mo>+</mo><mtext>⋯</mtext> " r)))) - (cond ((null (cddr x)) - (if (null (cdr x)) - (mathml-function x l r t) - (mathml (cadr x) (cons "<mo>+</mo>" l) r 'mplus rop))) - (t (setq l (mathml (cadr x) l nil lop 'mplus) - x (cddr x)) - (do ((nl l) (dissym)) - ((null (cdr x)) - (if (mmminusp (car x)) (setq l (cadar x) dissym (list "<mo>-</mo> ")) - (setq l (car x) dissym (list "<mo>+</mo> "))) - (setq r (mathml l dissym r 'mplus rop)) - (append nl r)) - (if (mmminusp (car x)) (setq l (cadar x) dissym (list "<mo>-</mo> ")) - (setq l (car x) dissym (list "<mo>+</mo> "))) - (setq nl (append nl (mathml l dissym nil 'mplus 'mplus)) - x (cdr x)))))) - -(defprop mminus mathml-prefix mathml) -(defprop mminus ("-") mathmlsym) -(defprop mminus 100. mathml-rbp) -(defprop mminus 100. mathml-lbp) - -(defprop min mathml-infix mathml) -(defprop min ("<mo>∈</mo> ") mathmlsym) -(defprop min 80. mathml-lbp) -(defprop min 80. mathml-rbp) - -(defprop mequal mathml-infix mathml) -(defprop mequal ("<mo>=</mo> ") mathmlsym) -(defprop mequal 80. mathml-lbp) -(defprop mequal 80. mathml-rbp) - -(defprop mnotequal mathml-infix mathml) -(defprop mnotequal 80. mathml-lbp) -(defprop mnotequal 80. mathml-rbp) - -(defprop mgreaterp mathml-infix mathml) -(defprop mgreaterp ("<mo>></mo> ") mathmlsym) -(defprop mgreaterp 80. mathml-lbp) -(defprop mgreaterp 80. mathml-rbp) - -(defprop mgeqp mathml-infix mathml) -(defprop mgeqp ("<mo>≥</mo> ") mathmlsym) -(defprop mgeqp 80. mathml-lbp) -(defprop mgeqp 80. mathml-rbp) - -(defprop mlessp mathml-infix mathml) -(defprop mlessp ("<mo><</mo> ") mathmlsym) -(defprop mlessp 80. mathml-lbp) -(defprop mlessp 80. mathml-rbp) - -(defprop mleqp mathml-infix mathml) -(defprop mleqp ("<mo>≤</mo> ") mathmlsym) -(defprop mleqp 80. mathml-lbp) -(defprop mleqp 80. mathml-rbp) - -(defprop mnot mathml-prefix mathml) -(defprop mnot ("<mo>¬</mo> ") mathmlsym) -(defprop mnot 70. mathml-rbp) - -(defprop mand mathml-nary mathml) -(defprop mand ("<mo>∧</mo> ") mathmlsym) -(defprop mand 60. mathml-lbp) -(defprop mand 60. mathml-rbp) - -(defprop mor mathml-nary mathml) -(defprop mor ("<mo>∨</mo> ") mathmlsym) - -;; make sin(x) display as sin x , but sin(x+y) as sin(x+y) -;; etc - -(defun mathml-setup (x) - (let((a (car x)) - (b (cadr x))) - (setf (get a 'mathml) 'mathml-prefix) - (setf (get a 'mathmlword) b) ;This means "sin" will always be roman - (setf (get a 'mathmlsym) (list b)) - (setf (get a 'mathml-rbp) 130))) - -(mapc #'mathml-setup - '( - (%acos "<mi>arccos</mi> ") - (%asin "<mi>arcsin</mi> ") - (%atan "<mi>arctan</mi> ") - (%arg "<mi>arg</mi> ") - (%cos "<mi>cos</mi> ") - (%cosh "<mi>cosh</mi> ") - (%cot "<mi>cot</mi> ") - (%coth "<mi>coth</mi> ") - (%csc "<mi>cosec</mi> ") - (%deg "<mi>deg</mi> ") - (%determinant "<mi>det</mi> ") - (%dim "<mi>dim</mi> ") - (%exp "<mi>exp</mi> ") - (%gcd "<mi>gcd</mi> ") - (%hom "<mi>hom</mi> ") - (%inf "<mi>∞</mi> ") - (%ker "<mi>ker</mi> ") - (%lg "<mi>lg</mi> ") - ;;(%limit "<mi>lim</mi> ") - (%liminf "<mi>lim inf</mi> ") - (%limsup "<mi>lim sup</mi> ") - (%ln "<mi>ln</mi> ") - (%log "<mi>log</mi> ") - (%max "<mi>max</mi> ") - (%min "<mi>min</mi> ") - ; Latex's "Pr" ... ? - (%sec "<mi>sec</mi> ") - (%sech "<mi>sech</mi> ") - (%sin "<mi>sin</mi> ") - (%sinh "<mi>sinh</mi> ") - (%sup "<mi>sup</mi> ") - (%tan "<mi>tan</mi> ") - (%tanh "<mi>tanh</mi> ") - ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual - ;(%laplace "{\\cal L}") - )) ;; etc - -(defprop mor mathml-nary mathml) -(defprop mor 50. mathml-lbp) -(defprop mor 50. mathml-rbp) - -(defprop mcond mathml-mcond mathml) -(defprop mcond 25. mathml-lbp) -(defprop mcond 25. mathml-rbp) - -(defprop %derivative mathml-derivative mathml) - -(defun mathml-derivative (x l r) - (mathml (mathml-d x "ⅆ") l r lop rop )) - -(defun mathml-d(x dsym) ;dsym should be "ⅆ" or "∂" - ;; format the macsyma derivative form so it looks - ;; sort of like a quotient times the deriva-dand. - (let* - ((arg (cadr x)) ;; the function being differentiated - (difflist (cddr x)) ;; list of derivs e.g. (x 1 y 2) - (ords (odds difflist 0)) ;; e.g. (1 2) - (vars (odds difflist 1)) ;; e.g. (x y) - (numer `((mexpt) ,dsym ((mplus) ,@ords))) ; d^n numerator - (denom (cons '(mtimes) - (mapcan #'(lambda(b e) - `(,dsym ,(simplifya `((mexpt) ,b ,e) nil))) - vars ords)))) - `((mtimes) - ((mquotient) ,(simplifya numer nil) ,denom) - ,arg))) - -(defun mathml-mcond (x l r) - (append l - (mathml (cadr x) '("<mi>if</mi> <mspace width='mediummathspace'/>") - '("<mspace width='mediummathspace'/> <mi>then</mi><mspace width='mediummathspace'/> ") 'mparen 'mparen) - (if (eql (fifth x) '$false) - (mathml (caddr x) nil r 'mcond rop) - (append (mathml (caddr x) nil nil 'mparen 'mparen) - (mathml (fifth x) '("<mspace width='mediummathspace'/> <mi>else</mi><mspace width='mediummathspace'/> ") r 'mcond rop))))) - -(defprop mdo mathml-mdo mathml) -(defprop mdo 30. mathml-lbp) -(defprop mdo 30. mathml-rbp) -(defprop mdoin mathml-mdoin mathml) -(defprop mdoin 30. mathml-rbp) - -(defun mathml-lbp(x)(cond((get x 'mathml-lbp))(t(lbp x)))) -(defun mathml-rbp(x)(cond((get x 'mathml-rbp))(t(lbp x)))) - -;; these aren't quite right - -(defun mathml-mdo (x l r) - (mathml-list (mathmlmdo x) l r "<mspace width='mediummathspace'/> ")) - -(defun mathml-mdoin (x l r) - (mathml-list (mathmlmdoin x) l r "<mspace width='mediummathspace'/> ")) - -(defun mathmlmdo (x) - (nconc (cond ((second x) `("<mi>for</mi> " ,(second x)))) - (cond ((equal 1 (third x)) nil) - ((third x) `("<mi>from</mi> " ,(third x)))) - (cond ((equal 1 (fourth x)) nil) - ((fourth x) `("<mi>step</mi> " ,(fourth x))) - ((fifth x) `("<mi>next</mi> " ,(fifth x)))) - (cond ((sixth x) `("<mi>thru</mi> " ,(sixth x)))) - (cond ((null (seventh x)) nil) - ((eq 'mnot (caar (seventh x))) - `("<mi>while</mi> " ,(cadr (seventh x)))) - (t `("<mi>unless</mi> " ,(seventh x)))) - `("<mi>do</mi> " ,(eighth x)))) - -(defun mathmlmdoin (x) - (nconc `("<mi>for</mi>" ,(second x) "<mi>in</mi> " ,(third x)) - (cond ((sixth x) `("<mi>thru</mi> " ,(sixth x)))) - (cond ((null (seventh x)) nil) - ((eq 'mnot (caar (seventh x))) - `("<mi>while</mi> " ,(cadr (seventh x)))) - (t `("<mi>unless</mi> " ,(seventh x)))) - `("<mi>do</mi> " ,(eighth x)))) - -;; Undone and trickier: -;; Maybe do some special hacking for standard notations for -;; hypergeometric fns, alternative summation notations 0<=n<=inf, etc. diff --git a/stack/2014083000/maxima/multiply_cross.lisp b/stack/2014083000/maxima/multiply_cross.lisp deleted file mode 100644 index ec0052c..0000000 --- a/stack/2014083000/maxima/multiply_cross.lisp +++ /dev/null @@ -1,6 +0,0 @@ -;; Customize Maxima's TEX() function. -;; Useful files: -;; \Maxima-5.9.0\share\maxima\5.9.0\share\utils\mactex-utilities.lisp -;; \Maxima-5.9.0\share\maxima\5.9.0\src\mactex.lisp - -(defprop mtimes ("\\times ") texsym) diff --git a/stack/2014083000/maxima/multiply_dot.lisp b/stack/2014083000/maxima/multiply_dot.lisp deleted file mode 100644 index fb7cb69..0000000 --- a/stack/2014083000/maxima/multiply_dot.lisp +++ /dev/null @@ -1,6 +0,0 @@ -;; Customize Maxima's TEX() function. -;; Useful files: -;; \Maxima-5.9.0\share\maxima\5.9.0\share\utils\mactex-utilities.lisp -;; \Maxima-5.9.0\share\maxima\5.9.0\src\mactex.lisp - -(defprop mtimes ("\\cdot ") texsym) diff --git a/stack/2014083000/maxima/noun_arith.lisp b/stack/2014083000/maxima/noun_arith.lisp deleted file mode 100644 index 929a906..0000000 --- a/stack/2014083000/maxima/noun_arith.lisp +++ /dev/null @@ -1,28 +0,0 @@ -;; Customize Maxima's tex() function. -;; Chris Sangwin 21 Oct 2005. -;; Useful files: -;; \Maxima-5.9.0\share\maxima\5.9.0\share\utils\mactex-utilities.lisp -;; \Maxima-5.9.0\share\maxima\5.9.0\src\mactex.lisp - -(defprop $noun+ tex-mplus tex) -(defprop $noun+ ("+") texsym) -(defprop $noun+ 100. tex-lbp) -(defprop $noun+ 100. tex-rbp) - -(defprop $noun- tex-prefix tex) -(defprop $noun- ("-") texsym) -(defprop $noun- 100. tex-rbp) -(defprop $noun- 100. tex-lbp) - -(defprop $noun* tex-nary tex) -(defprop $noun* "\\," texsym) -(defprop $noun* 120. tex-lbp) -(defprop $noun* 120. tex-rbp) - -(defprop $noun/ tex-mquotient tex) -(defprop $noun/ 122. tex-lbp) ;;dunno about this -(defprop $noun/ 123. tex-rbp) - -(defprop $noun^ tex-mexpt tex) -(defprop $noun^ 140. tex-lbp) -(defprop $noun^ 139. tex-rbp) diff --git a/stack/2014083000/maxima/rtest_assessment_simpboth.mac b/stack/2014083000/maxima/rtest_assessment_simpboth.mac deleted file mode 100644 index 5e47a7f..0000000 --- a/stack/2014083000/maxima/rtest_assessment_simpboth.mac +++ /dev/null @@ -1,297 +0,0 @@ -safe_op(1); -""$ -safe_op(x); -""$ -safe_op(%pi); -""$ -safe_op(z+3); -"+"$ -safe_op(3*z); -"*"$ -safe_op(3^z); -"^"$ -safe_op(3/z); -"/"$ -safe_op(sin(3*z)); -"sin"$ -safe_op((-1)/(1+x^2)); -"/"$ -safe_op(1-x); -"+"$ -safe_op(x-1); -"+"$ -safe_op(-(x-1)); -"-"$ -safe_op(-1/(1+x^2)); -"/"$ -safe_op(-2*x); -"*"$ - -coeff_list(x^2-3*x+5,x); -[5,-3,1]$ - -decimalplaces(1.123456789,3); -1.123$ -decimalplaces(1.123456789,8); -1.12345679$ -decimalplaces(1.1292,2); -1.13$ -decimalplaces(-1.1292,2); --1.13$ -decimalplaces(%pi,5); -3.14159$ -decimalplaces(%pi,4); -3.1416$ - -significantfigures(11292,2); -11000$ -significantfigures(11292,3); -11300$ -significantfigures(1.1292,3); -1.13$ -significantfigures(0.011292,3); -0.0113$ -significantfigures(0.09999,3); -0.1$ -scientific_notation(1.123); -1.123$ -scientific_notation(1123); -1123.0$ -significantfigures(-0.99,1); --1$ - -all_listp(real_numberp,[1,exp(1)^(%i*%pi),sqrt(2)+1,sin(1)]); -true$ -any_listp(real_numberp,[%i,%i+1,3+x,sqrt(-3)+1]); -false$ - -expandp((x-1)*(1+x)); -false$ -expandp(2*(x-1)); -false$ -expandp(2*x-1); -true$ -expandp(x-1); -true$ -expandp((p-1)*(1+p)); -false$ -expandp(2*(p-1)); -false$ -expandp(3*y+6*p); -true$ - -ineqprepare(x>1); -x-1>0$ -ineqprepare(3*x<=7-x); -7-4*x>=0$ - -list_expression_numbers(x); -[]$ -list_expression_numbers(%pi); -[]$ -list_expression_numbers(1+x); -[1]$ -list_expression_numbers(1/2+x); -[1/2]$ -list_expression_numbers(4/2+x); -[4/2]$ -list_expression_numbers(1/sin(2*x)); -[1,2]$ - -sublist([0.5],floatnump); -[0.5]$ -sublist([1,0.5],floatnump); -[0.5]$ - -anyfloatex(0.5); -true$ -anyfloatex(x); -false$ -anyfloatex(1+x); -false$ -anyfloatex(0.5*x); -true$ -anyfloatex(sin(x*0.2)); -true$ - -irred_Q(0,x); -[true,"",false]$ -irred_Q(x,x); -[true,"",false]$ -irred_Q(1+x,x); -[true,"",false]$ -irred_Q(1-x,x); -[true,"",false]$ -irred_Q(2-3*x,x); -[true,"",false]$ -irred_Q(2*x-2,x); -[false,"stack_trans('irred_Q_commonint'); ",true]$ -irred_Q(t+t*x,x); -[false,"",false]$ -irred_Q(3*x^2,x); -[true,"",false]$ -irred_Q(4*x^2,x); -[true,"stack_trans('irred_Q_optional_fac' , !quot!\\(4\\,x^2\\)!quot! ); ",false]$ -irred_Q(x^2-4,x); -[false,"",false]$ -irred_Q(x^2-2,x); -[true,"",false]$ -irred_Q(n+n^2,n); -[false,"",false]$ -irred_Q(n*(1+n),n); -[false,"",false]$ -irred_Q(n*(n-1),n); -[false,"",false]$ -irred_Q(0.5+x,x); -[true,"",false]$ -irred_Q(2-3*x+x^2,x); -[false,"",false]$ -irred_Q(1+x^2+x^5,x); -[true,"",false]$ -irred_Q(n^3-1,n); -[false,"",false]$ -irred_Q(3*x-6*x^3+3*x^6,x); -[false,"stack_trans('irred_Q_commonint'); ",false]$ -irred_Q(9-3*x+3*x^5,x); -[false,"stack_trans('irred_Q_commonint'); ",true]$ - -irred_power_Qp(2,x); -true$ -irred_power_Qp((x-1)^2,x); -true$ -irred_power_Qp((3*x-6)^4,x); -true$ -irred_power_Qp(x^2-1,x); -false$ -irred_power_Qp(3*x-6*x^3+3*x^6,x); -false$ -irred_power_Qp(9-3*x+3*x^5,x); -true$ - -continuousp(x^2,x,1); -true$ -continuousp(abs(x),x,1); -true$ -continuousp(abs(x),x,0); -true$ -continuousp(sgn(x),x,0); -false$ -continuousp(sin(1/x),x,0); -false$ -continuousp(x*sin(1/x),x,0); -true$ - -diffp(x^2,x,1); -true$ -diffp(abs(x),x,1); -true$ -diffp(abs(x),x,0); -false$ -diffp(sgn(x),x,0); -false$ -diffp(sin(1/x),x,0); -false$ -diffp(x^2*sin(1/x),x,0); -false$ -diffp(x^3*sin(1/x),x,0); -true$ - -listsoverlap([1,2],[2,3]); -true$ -listsoverlap([8,9],[2,3]); -false$ -listscontain([1,2],[2,3],1); -false$ -listscontain([8,9],[2,3],1); -false$ -listscontain([1,2],[1,3],1); -true$ - -subst_int_const(x^4/4+c*x+x = %c9,k); -x^4/4+c*x+x = k$ -subst_int_const(x^4/4+c*x+x = %c9,v); -x^4/4+c*x+x = v$ -subst_int_const(x^2,k); -x^2$ -subst_int_const(c*x^4/4+c^2*x/2+c*x = %c9*c+%c10,[v]); -c*x^4/4+c^2*x/2+c*x = %c9*c+v$ -subst_int_const(c*x^4/4+c^2*x/2+c*x = %c9*c+%c10,[k1,k2]); -c*x^4/4+c^2*x/2+c*x = k1+c*k2$ -subst_int_const(c*x^4/4+c^2*x/2+c*x = %c9*c+%c10,[k1,k2,k3]); -c*x^4/4+c^2*x/2+c*x = k1+c*k2$ - -subst_equiv(y+x^2,1+a^2); -[]$ -subst_equiv(1-2*x+x^2,(X-1)^2); -[x = X]$ -subst_equiv(y+x^2,b+a^2); -[x = a,y = b]$ -subst_equiv(y+x^2,b+a^2); -[x = a,y = b]$ -subst_equiv(y/z+x^2,c/b+a^2); -[x = a,y = c,z = b]$ -subst_equiv(y/z+x^2,z/x+y^2); -[x = y,y = z,z = x]$ -subst_equiv(y+x^2,x^2+y^2); -[]$ -subst_equiv(u^6+w^5+v^4+z^3+y^2+x,f+g^2+d^3+c^4+b^5+a^6); -false$ -subst_equiv(w+u+v+y+x^2,w+v+y+b+a^2); -[u = b,x = a]$ - -exdowncase(1+X+X^2); -1+x+x^2$ - -exdowncase(%pi); -%pi$ - -stack_assignmentp(x = 1); -true$ -stack_assignmentp(x = sqrt(2)); -true$ -stack_assignmentp(3 = 1); -false$ -stack_assignmentp(d = v*t); -false$ -stack_assignmentp(1 = x); -false$ - -StackDISP(a/b,""); -"\\frac{a}{b}"$ -StackDISP(-27,""); -"-27"$ -StackDISP(-sin(x^2),""); -"-\\sin \\left( x^2 \\right)"$ -StackDISP(asin(x),""); -"\\sin^{-1} \\left( x \\right)"$ -StackDISP(log(x),""); -"\\ln \\left( x \\right)"$ -StackDISP(y^3-2*y^2-8*y,""); -"y^3-2\\,y^2-8\\,y"$ -StackDISP(y^2-2*y-8,""); -"y^2-2\\,y-8"$ -StackDISP(y^2-2*y-0.5,""); -"y^2-2\\,y-0.5"$ - -strip_int_const(k+x,x); -x$ -strip_int_const(k+1+x,x); -1+x$ -strip_int_const(k^2+(x-1)^2,x); -(x-1)^2$ -strip_int_const(c+(t-1)^4/4,t); -(t-1)^4/4$ - -buggy_pow((x+1)^2); -1^2+x^2$ -buggy_pow(sin((x+y)^3)); -sin(x^3+y^3)$ - -degree(y^3 * x^2 + x * y^4, x); -2$ -degree((x + y)^5, x); -5$ -degree((x + y)^5, x + y); -0$ - - diff --git a/stack/2014083000/maxima/rtest_assessment_simpfalse.mac b/stack/2014083000/maxima/rtest_assessment_simpfalse.mac deleted file mode 100644 index edf6677..0000000 --- a/stack/2014083000/maxima/rtest_assessment_simpfalse.mac +++ /dev/null @@ -1,121 +0,0 @@ -scientific_notation(123.456); -1.23456*10^2$ - -factorp(x); -true$ -factorp(2); -true$ -factorp(4); -false$ -factorp(2^2); -true$ -factorp(2^2*x^3); -true$ -factorp(x^2); -true$ -factorp(y^2*x^2); -true$ -factorp((y*x)^2); -true$ -factorp((x-1)*(1+x)); -true$ -factorp((x-1)^2); -true$ -factorp((1-x)^2); -true$ -factorp(2*(x-1)); -true$ -factorp(2*x-1); -true$ -factorp(x^2-1); -false$ -factorp(1+x^2); -true$ -factorp((x-1)*(1+x)); -true$ -factorp((x-%i)*(%i+x)); -true$ -factorp(4*(x-1/2)^2); -false$ - -commonfaclist([12,15]); -3$ -commonfaclist([12,15,60,9]); -3$ -commonfaclist([x^2-1,x^3-1]); -x-1$ -commonfaclist([x = 6,8]); -1$ - -factorlist(15); -[3,5]$ -factorlist(x^3-1); -[x-1,1+x+x^2]$ - -lowesttermsp(x); -true$ -lowesttermsp(0.5); -true$ -lowesttermsp(1/2); -true$ -lowesttermsp((-1)/2); -true$ -lowesttermsp(1/(-2)); -true$ -lowesttermsp((-3)/6); -false$ -lowesttermsp((-x)/x^2); -false$ -lowesttermsp(15/3); -false$ -lowesttermsp(3/15); -false$ -lowesttermsp((x-1)/(x^2-1)); -false$ -lowesttermsp(x/(x^2-1)); -true$ -lowesttermsp((2+x)/(x^2-1)); -true$ - -all_lowest_termsex(x); -true$ -all_lowest_termsex(0.5); -true$ -all_lowest_termsex(1/2); -true$ -all_lowest_termsex(2/4); -false$ -all_lowest_termsex(15/3); -false$ -all_lowest_termsex(0.3*x^2+3/15); -false$ -all_lowest_termsex(x/(x^3+x)); -true$ - -list_expression_numbers(0.3*x+1/2); -[1/2,0.3]$ - -exdowncase(X-x); -x-x$ - -StackDISP(-(x-1),""); -"-\\left(x-1\\right)"$ - -buggy_pow( 3*(x+1)^2 ); -3*(x^2+1^2)$ -buggy_pow(x^(a+b)^2); -x^(a^2+b^2)$ -buggy_pow(x^(a+b)^(1/2)); -x^(a^(1/2)+b^(1/2))$ -buggy_pow((x+1)^(a+b)^2); -x^(a^2+b^2)+1^(a^2+b^2)$ -buggy_pow( 3*(x+1)^-1 ); -3*(1/x+1/1)$ -buggy_pow( 3*(x+1)^-2 ); -3*(1/x^2+1/1^2)$ -buggy_pow(sin(sqrt(a+b))); -sin(sqrt(a)+sqrt(b))$ - -mediant(1/2,2/3); -(1+2)/(2+3)$ - diff --git a/stack/2014083000/maxima/rtest_assessment_simptrue.mac b/stack/2014083000/maxima/rtest_assessment_simptrue.mac deleted file mode 100644 index ddccba9..0000000 --- a/stack/2014083000/maxima/rtest_assessment_simptrue.mac +++ /dev/null @@ -1,20 +0,0 @@ -exdowncase(X-x); -0$ - -list_expression_numbers(0.3*x+1/2); -[0.3,1/2]$ - -StackDISP(-(x-1),""); -"1-x"$ - -mediant(1/2,2/3); -3/5$ -mediant(1,1); -1$ -mediant(x/y,z); -(x+z)/(y+1)$ - -comp_square(x^2+2*x+1,x); -(x+1)^2$ -comp_square(3*x^2+6*x+1,x); -3*((x+1)^2-2/3)$ diff --git a/stack/2014083000/maxima/rtest_elementary.mac b/stack/2014083000/maxima/rtest_elementary.mac deleted file mode 100644 index f0034a8..0000000 --- a/stack/2014083000/maxima/rtest_elementary.mac +++ /dev/null @@ -1,179 +0,0 @@ -zeroAdd(x); -x$ -zeroAdd(0+x); -x$ -zeroAdd(0+0+x); -0+x$ -zeroAdd(x+0); -x+0$ -zeroAdd(0*x); -0*x$ -zeroAdd(x*0); -x*0$ -zeroAdd(0^x); -0^x$ -zeroAdd(x^0); -x^0$ - -zeroMul(x); -x$ -zeroMul(x+0); -x+0$ -zeroMul(0*x); -0$ -zeroMul(x*0); -x*0$ -zeroMul(0^x); -0^x$ -zeroMul(x^0); -x^0$ -zeroMul(0*0*x); -0$ -zeroMul(sin(0*x)); -sin(0*x)$ - -oneMul(x); -x$ -oneMul(x+1); -x+1$ -oneMul(1*x); -x$ -oneMul(x*1); -x*1$ -oneMul(1^x); -1^x$ -oneMul(x^1); -x^1$ -oneMul(1*1*x); -1*x$ -oneMul(sin(1*x)); -sin(1*x)$ - - -onePow(1); -1$ -onePow(x^1); -x^1$ -onePow(1^x); -1$ -onePow((1+x)^1); -(1+x)^1$ -onePow(0^1); -0^1$ -onePow(1^0); -1$ - -idPow(1); -1$ -idPow(x^1); -x$ -idPow(1^x); -1^x$ -idPow((1+x)^1); -(1+x)$ -idPow(0^1); -0$ - -zeroPow(1); -1$ -zeroPow(x^0); -x^0$ -zeroPow(0^x); -0$ -zeroPow(0^0); -0^0$ -zeroPow(1+x); -1+x$ - -zPow(1); -1$ -zPow(x^0); -1$ -zPow(0^x); -0^x$ -zPow(0^0); -0^0$ -zPow(1+x); -1+x$ - -unaryAdd(x); -x$ -unaryAdd("+"(x)); -x$ -unaryAdd("*"(x)); -"*"(x)$ -unaryAdd("+"(x,y)); -x+y$ - -unaryMul("*"(x)); -x$ -unaryMul("*"(x,y)); -x*y$ - - -assAdd((a+b)+c); -a+b+c$ -assAdd(a+(b+c)); -a+b+c$ -assAdd((a+b)+(c+d)); -a+b+c+d$ - -assMul((a*b)*c); -a*b*c$ - -comMul(x); -x$ -comMul(1); -1$ -comMul(2*x*3); -2*3*x$ -comMul(2*3.0*%pi); -2*3.0*%pi$ - -negNeg(x); -x$ -negNeg(-x); --x$ -negNeg(-(-x)); -x$ - -negZero(-x); --x$ -negZero(-0); -0$ -negZero("-"(0)); -0$ - -negDef(a-a); -0$ -negDef(a+b-a); -b$ -negDef(a-a-a); --a$ -negDef(a-a+b-b); -0$ - -negDistAdd(-(a+b)); --a-b$ - -intAdd(1+2); -3$ -intAdd(1+x+2); -x+3$ - -intMul(2*3); -6$ -intMul(2*x*3); -6*x$ - -intPow(2^3); -8$ -intPow(2^x); -2^x$ -intPow(0^0); -0^0; - - - - - diff --git a/stack/2014083000/maxima/rtest_experimental.mac b/stack/2014083000/maxima/rtest_experimental.mac deleted file mode 100644 index 9ed077a..0000000 --- a/stack/2014083000/maxima/rtest_experimental.mac +++ /dev/null @@ -1,104 +0,0 @@ -linear_inequalityp(x>1); -true$ - -linear_inequalityp(x>=1); -true$ - -linear_inequalityp(x=1); -false$ - -linear_inequalityp(x); -false$ - -ineq_rem_redundant(x>6 and 1<=x); -x>6$ -ineq_rem_redundant(x>=6 and 1<=x); -x>=6$ -ineq_rem_redundant(x>6 and 6<=x); -x>6$ -ineq_rem_redundant(x<1 and 1>=x); -1>x$ -ineq_rem_redundant(x>6 or 6<=x); -x>=6$ -ineq_rem_redundant(x>6 or 1<=x); -x>=1$ -ineq_rem_redundant(x<2 or 2>=x); -2>=x$ -ineq_rem_redundant((x>6 or x>1) and x>=4); -x>=4$ -ineq_rem_redundant((x>6 and 6<=x and y>2 and 6<x)); -x>6 and y>2$ -ineq_rem_redundant(1<x and x<%pi and x<20); -x>1 and %pi>x$ - -neg_ineq(x>6); -x<6; -neg_ineq(x>=6); -x<=6; -neg_ineq(x^2<x); -x^2>x; -neg_ineq(x); -x; - -neg_ineq_list([x>1,x>2,x>3],[]); -[x>1,x>2,x>3]$ -neg_ineq_list([x>1,x>2,x>3],[1]); -[x<1,x>2,x>3]$ -neg_ineq_list([x>1,x>2,x>3],[1,3]); -[x<1,x>2,x<3]$ - -interval_inequalityp(true); -true$ -interval_inequalityp(false); -true$ -interval_inequalityp(x>1); -true$ -interval_inequalityp(1<x and x<%pi); -true$ -interval_inequalityp(1<x and y<%pi); -false$ -interval_inequalityp(x<1 or x>7); -false$ -interval_inequalityp(1<x and x<%pi and x<20); -true$ - -rev_ineq(x>6); -6<x; -rev_ineq(x>=6); -6<=x; -rev_ineq(x^2<x); -x>x^2; -rev_ineq(x); -x; - -inequality_disp(x>1); -1<x$ -inequality_disp(2*x>%pi); -%pi/2<x$ -inequality_disp(x>=4); -4<=x$ -inequality_disp(x<1); -x<1$ -inequality_disp(4*x<=28); -x<=7$ - -interval_simplify(x>4 and x>7); -7<x$ -interval_simplify(1<x and x<7); -1<x and x<7$ -interval_simplify(1<x and 7>x); -1<x and x<7$ -interval_simplify(x>4 and x<1); -false; - - -factor_ineq_solve((x-1)^2<=-1); -false; -factor_ineq_solve(x^2>=4); -x <= -2 or 2 <= x$ -factor_ineq_solve(x^2<=4); --2 <= x and x <= 2$ -factor_ineq_solve(x^4-5*x^2>-4); -(x < -2) or (-1 < x and x < 1) or (2 < x)$ -factor_ineq_solve(x^4-5*x^2<=-4); -(1 <= x and x <= 2) or (-2 <= x and x <= -1); diff --git a/stack/2014083000/maxima/stackmaxima.mac b/stack/2014083000/maxima/stackmaxima.mac deleted file mode 100644 index a3bcb66..0000000 --- a/stack/2014083000/maxima/stackmaxima.mac +++ /dev/null @@ -1,2293 +0,0 @@ -/* Author Chris Sangwin - Loughborough University - Copyright (C) 2014 Chris Sangwin - - This program is free software: you can redistribute it or modify - it under the terms of the GNU General Public License version two. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - - -/* ********************************** */ -/* Global variable options */ -/* ********************************** */ - -stack_reset(rand_seed) := block( - kill(allbut [functions]), - kill(trigsimp), - /* We need some kind of numerical number to compare against. */ - /* This does not work in Maxima 5.13.0, but keep for future reference */ - /* MAXIMA_VERSION_NUM:parse_string(?subseq(MAXIMA_VERSION,2)) */ - /* */ - simpsum:true, - negdistrib:true, /* When negdistrib is true, -1 distributes over an expression. E.g., -(x + y) becomes - y - x. */ - display2d:false, - nolabels:true, - logabs:true, - exptdispflag:true, - linsolvewarn:false, - ratprint:false, - fpprintprec:12, /* print only 12 digits */ - fpprec:20, /* work with 20 digits */ - %E_TO_NUMLOG:true, /* "r" some rational number, and "x" some expression, %E^(r*LOG(x)) => x^r .*/ - /* Synonyms to help students */ - e:exp(1), - pi:%pi, Pi:%pi, PI:%pi, - pi():=%pi, /* Why does Excel do this?! */ - /* Display of matrixes */ - lmxchar:"[", - /* Sets up randomization, using Maxima's internal random command */ - stack_randseed(10000), - - /*Reload local settings*/ - STACK_SETUP(true), - - MAXIMA_VERSION:map(parse_string, tokens(?\*autoconf\-version\*, 'digitcharp)), - MAXIMA_VERSION_NUM:float(MAXIMA_VERSION[2]+MAXIMA_VERSION[3]/10), - - /* */ - OPT_OUTPUT:"LaTeX", - /* */ - DIV_OP:"//", - if MAXIMA_VERSION_NUM>=15.0 then DIV_OP:"/", - - true -)$ - -/* Sometimes we need i,j,e etc to be *symbols*, not values.... */ -stack_reset_vars(ex) := block(kill(i, j, e, pi, Pi, PI)); - -/* Execute this command to ensure values have been set */ -stack_reset(1000); - -alias(int,integrate); /* Allows integrate to be called with int() */ -alias(cosec,csc); /* Corresponds to current student expectations */ - -simplify(ex) := ev(fullratsimp(ex), simp); /* Allows simplify to be something */ -degree(ex,v) := ev(hipow(expand(ex), v), simp); /*See notes on hipow*/ - - -/* ********************************** */ -/* Logarithms */ -/* ********************************** */ -alias(ln, log); -load("log10"); -texput(log10, "\\log\\mathrm{10}", prefix); -alias(lg, log10); -texput(lg, "\\mathrm{lg}", prefix); -load ("functs"); - -/* We don't want to allow people to put boxes round things. */ -box(ex):=ex; - -/* ********************************** */ -/* Load contributed packages */ -/* ********************************** */ - -/* Although this works well in MAXIMA, |'s are not allowed in STACK */ -/* The heuristics to catch the various errors do not work, since | is symmetrical */ -matchfix("|", "|"); -"|"([a]) := apply(abs, a); - -/* Does not quite work yet ..... */ -/* load("noninteractive.mac"); */ - - -/*load("expandfeedback.mac");*/ - -/*load("sqdnst")*/ -sqrtdenest(a) := - subst("^" = lambda([a, b], - block([discr, max, min], - if evenp(denom(b)) and not atom(a) and inpart(a, 0) = "+" - and (max:max(first(a), rest(a)), - min:a-max, - numberp(discr:sqrt(1-(min/max)^2))) - then (sqrt(max*(1+discr)/2)+signum(min)*sqrt(max*(1-discr)/2))^(2*b) - else a^b)), - a -)$ - -/* ********************************** */ -/* Load stack packages */ -/* ********************************** */ - -load("assessment.mac"); /* Currently part of the STACK distribution */ - -load("stacktex.lisp"); /* Loads LaTeX changes and preferences */ -texput(QMCHAR, "\\color{red}{?}"); - -alias(arccos, acos); /* At the request of the OU, 4 Feb 2013 */ -alias(arcsin, asin); -alias(arctan, atan); - -load("mathml.lisp"); /* loads MathML */ - - -make_complexJ(OPT_COMPLEXJ) := block( - if OPT_COMPLEXJ = "i" then - (i:%i,load("complexi.lisp")) - else if OPT_COMPLEXJ = "j" then - (%j:%i,j:%i,load("complexj.lisp")) - else if OPT_COMPLEXJ = "symi" then - (load("complexi.lisp")) - else if OPT_COMPLEXJ = "symj" then - (load("complexj.lisp")) - else true -); - -/* Makes multiplication signs look correct */ -make_multsgn(OPT_MULTSGN) := block( - if OPT_MULTSGN = "cross" then load("multiply_cross.lisp"), - if OPT_MULTSGN = "dot" then load("multiply_dot.lisp") -); - -/* Options for cos^(-1), acos or arccos */ -make_arccos(OPT_ACOS) := block( - if OPT_ACOS = "cos-1" then load("cos-1.lisp"), - if OPT_ACOS = "arccos" then load("arccos.lisp") -); - - -/* ****************************************************** */ -/* Random numbers */ -/* ****************************************************** */ -/* http://random.mat.sbg.ac.at/generators/ */ -/* ****************************************************** */ -/* Developer warning: random functions determining */ -/* whether a question is a singleton. */ -/* When adding new "random" functions, also update */ -/* question->has_random_variants() */ -/* ****************************************************** */ - -/* Change the random seed */ -stack_randseed(s) := block(RANDOM_STATE:make_random_state(s), errcatch(ev(set_random_state(RANDOM_STATE), simp)))$ - -/* The top level function */ -rand(ex) := block( - ex:ev(ex, simp), - if (integerp(ex)) then return(random(ex)), - if (floatnump(ex)) then return(random(ex)), - if (matrixp(ex)) then return(matrixmap(random, ex)), - if (listp(ex)) then return(randlist(ex)) -)$ - -randlist(ex) := block( - if (length(ex) > 0) then return(ev(ex[(1+random(length(ex)))], simp)) else return([]) -)$ - -/* Returns a random number from the set {lower, lower+step, lower+2*step, ... , final}. */ -/* Jarno Ruokokoski, 29/10/2009 */ -rand_with_step(lower, upper, step_parameter) := block([temprand], - temprand:rand(floor((upper-lower)/step_parameter)+1), - return(step_parameter*temprand+lower) -)$ - -/* Returns a random integer from the set [lower,upper] such that it cannot be any value in list. This list can include values which are also random variables, for example, generated by rand_with_step. */ -/* Jarno Ruokokoski, 29/10/2009 */ -rand_with_prohib(lower, upper, list) := block([currents, retVal], - currents:ev((makelist(i, i, lower, upper)), simp), - for i:1 thru length(list) do block( - currents:simplify(delete(list[i], currents)) - ), - retVal:rand(currents), - return(retVal) -)$ - -/* ********************************** */ -/* Display */ -/* ********************************** */ -/* expr - expression to be displayed */ -/* m - mode, either */ -/* "i" inline or */ -/* "d" for displayed, or */ -/* "" for no delimiters. */ - -StackDISP(expr,m) := block([str:""], - /* LaTeX display */ - if OPT_OUTPUT = "LaTeX" then - if not(ev(elementp(m, {"", "i", "d"}), simp)) then print(concat("ERROR: illegal delimiter option found: ", m)), - str:block([expru, expstr, offset, ld, rd], - ld:"", - rd:"", - if m = "i" then block(ld:"\\(", rd:"\\)"), - if m = "d" then block(ld:"\\[", rd:"\\]"), - expru:unary_minus_sort(expr), - expstr:tex(expru, false), - /* Remove $$'s from Maxima's TEX command */ - if ?subseq(expstr, 0, 2) = "$$" then - expstr:concat(ld, ?subseq(expstr, 2, ev(?length(expstr)-3, simp)), rd) - /* Remove \begin{verbatim}'s from Maxima's TEX command */ - else if ?length(expstr) > 17 and ?subseq(expstr,1,17) = "\\begin{verbatim}" then - expstr:concat(ld, ?subseq(expstr, 18, ev(?length(expstr)-18, simp)), rd), - expstr - ), - /* MathML display */ - if OPT_OUTPUT = "MathML" then - str:mathml(expr, false), - /* String display */ - if OPT_OUTPUT="String" then str:string(expr), - /* If no correct options have been set */ - if str = "" then str:string(expr), - return(str) -)$ - -COLOR_LIST:["red", "Blue" , "YellowOrange", "Bittersweet" , "BlueViolet" , "Aquamarine", "BrickRed" , - "Apricot" , "Brown" , "BurntOrange", "CadetBlue" , "CarnationPink" , "Cerulean" , "CornflowerBlue" , - "CyanDandelion" , "DarkOrchid" , "Emerald" , "ForestGreen" , "Fuchsia", "Goldenrod" , "Gray" , - "Green" , "JungleGreen", "Lavender" , "LimeGreen" , "Magenta" , "Mahogany" , "Maroon" , "Melon", - "MidnightBlue" , "Mulberry" , "NavyBlue" , "OliveGreen" , "Orange", "OrangeRed" , "Orchid" , - "Peach" , "Periwinkle" , "PineGreen" , "Plum", "ProcessBlue" , "Purple" , "RawSienna" , "Red" , - "RedOrange" , "RedViolet" , "Rhodamine" , "RoyalBlue" , "RoyalPurple" , "RubineRed", "Salmon" , - "SeaGreen" , "Sepia" , "SkyBlue" , "SpringGreen" , "Tan", "TealBlue" , "Thistle" , "Turquoise" , - "Violet" , "VioletRed" ,"WildStrawberry" , "Yellow" , "YellowGreen" , "BlueGreen"]$ -COLOR_LIST_LENGTH:length(COLOR_LIST)$ - -/* Decolour function */ -detexcolor(ex) := block([argsex], - if mapatom(ex) then return(ex), - argsex:args(ex), - if op(ex) = texcolor then return(detexcolor(argsex[2])), - if op(ex) = "/" then return(detexcolor(argsex[1])/detexcolor(argsex[2])), - map(detexcolor, ex) -)$ - -detexdecorate(ex) := block([argsex], - if mapatom(ex) then return(ex), - argsex:args(ex), - if op(ex) = texdecorate then return(detexdecorate(argsex[2])), - if op(ex) = "/" then return(detexdecorate(argsex[1])/detexdecorate(argsex[2])), - map(detexdecorate, ex) -)$ - -/* Assume all non-numeric atoms are to be displayed in bold. */ -texboldatoms(ex) := block( - if numberp(ex) then return(ex), - if atom(ex) then return(texdecorate("\\bf", ex)), - apply(op(ex), maplist(texboldatoms, args(ex))) -)$ - -/* We only display matrices with the following matching pairs of delimiters. - Mismatching pairs ruins the API, so we can't have lmxchar and rmxchar as arbitrary. - The list has three arguments, the first is the search string, the second is the left - parentheses, and the third is the right parentheses. -*/ -stack_matrix_pairs:[ ["[", "[", "]"], ["(", "(", ")"], ["\{", "\\{", "\\}"], ["{", "\\{", "\\}"], ["", "", ""], [".", "", ""], ["|", "|", "|"]] $ - -stack_matrix_disp(m):= block([ret, lp, rp, parens], - if not(matrixp(m)) then (print("\\mbox{ERROR: argument to stack_matrix_disp must be a matrix.} "), return("")), - if not(stringp(lmxchar)) then (print("\\mbox{ERROR: stack_matrix_disp requires lmxchar to be a string. }"), return("")), - parens:sublist(stack_matrix_pairs, lambda([ex],is(first(ex)=lmxchar))), - if emptyp(parens) then (print(concat("\\mbox{ERROR: stack_matrix_disp cannot display matrices with parentheses ", string(lmxchar), "}")), return("")), - parens:first(parens), - lp:second(parens), - rp:third(parens), - ret:maplist(lambda([ex], maplist(tex1, args(ex))), args(m)), - ret:maplist(lambda([ex], simplode(ex, " & ")), ret), - ret:simplode(ret, " \\\\ "), - ret:sconcat("\\begin{array}{", simplode(maplist(lambda([ex], "c"), first(args(m)))), "} ", ret, " \\end{array}"), - if ""#lp then - ret:sconcat("\\left", lp, ret), - if ""#rp then - ret:sconcat(ret, "\\right", rp), - ret -)$ - -texput(matrix, stack_matrix_disp)$ - -/* ********************************** */ -/* Display: Sort out the unary minus */ -/* ********************************** */ - -/* To see an interesting example, see the following. - simp:false; - p:y^3-2*y^2-8*y; - ?print(p); - - In the structure of this expression the first negative coefficient is -(2y^2) BUT the second is -(8)*y. - - ((MPLUS) ((MEXPT) $Y 3) ((MMINUS) ((MTIMES) 2 ((MEXPT) $Y 2))) ((MTIMES) ((MMINUS) 8) $Y)) - - This again is a crucial but subtle difference.... - - The following functions sort this out, pulling "-" out the front in a specific situation: that of - a product with a negative number at the front. - - Another interesting example. This illustrates the interaction with quotients. - simp:false; - p:x^7/7-2*x^6/3-4*x^3/3; -*/ - -/* Traverses an entire expression and ensures that "-"(number) really is the negative number. */ -/* Although we ultimately need to transform all integers back into "-"(number) for correct display */ -/* this function gives us a definite form for comparison purposes in the interim.*/ -unary_minus_traverse(ex) := block( - if mapatom(ex) then return(ex), - if op(ex) = "-" and numberp(first(args(ex))) then return(ev(ex,simp)), - apply(op(ex), map(unary_minus_traverse, args(ex)) ) -)$ - - -/* Pulls out "-" to the front of any expression in a sum of products which needs it. */ -/* For example, -(2*y^2) is ok */ -/* But (-3)*7 is not. */ -unary_minus_pull(ex) := block([ex2], - if mapatom(ex) then return(ex), - ex2:apply(op(ex), map(unary_minus_pull, args(ex))), - if op(ex) = "+" then ex2:apply("+", map(unary_minus_pull_helper, args(ex2))), - if op(ex) = "*" then ex2:unary_minus_pull_helper(ex2), - return(ex2) -)$ - -/* Looks for */ -/* - a negative number */ -/* - a product of an number and something. */ -/* - a quotient of an number and something. */ -/* Makes sure any minus sign is the top element */ -unary_minus_pull_helper(ex) := block([fe], - if numberp(ex) and is(ex<0) then return(-(ev(-1*ex,simp))), /* Turns -8 into "-"(8) */ - if mapatom(ex) then return(ex), - fe:first(args(ex)), /* First element of the arguments. Is this a negative number? */ - if op(ex) = "*" then - if numberp(fe) and is(fe<0) - then return(-(apply("*", append([ev(-fe,simp)], rest(args(ex)))))), - /* (-4*x^3)/4 is transformed into -(4*x^3)/4 */ - if op(ex) = "/" and safe_op(fe) = "-" then - return(-(apply("/",append(args(fe),[second(args(ex))])))), - return(ex) -)$ - - -/* Sorts out display of expressions in the case simp:false */ -unary_minus_sort(ex) := block([ex2], - if simp or mapatom(ex) then return(ex), - if op(ex) = ":=" then return(ex), - ex2:unary_minus_traverse(ex), - return(unary_minus_pull(ex2)) -)$ - - - -/* ****************************************************************** */ -/* Evaluate variables are return errors, display, and content forms */ -/* ****************************************************************** */ - -/* This function executes ex, which is assumed to be a stack expression */ -/* which is surrounded by errcatch. Hence we end up with a list. */ -cte(var,ex) := block([str], - print("], key= ["), - print(var), - print("]"), - if ex = [] then block( - ex:STACKERROR, - print(", value = [], display = []") - ) - else block( - print(", value = ["), - print(string(ex[1])), - print("], display = ["), - print(StackDISP(ex[1], "")), - print("]"), - ex:ex[1] - ), - print("], "), - return(ex) -)$ - -/* ********************************** */ -/* Generate feedback */ -/* ********************************** */ - -StackAddFeedback(fb, key, [ex]) := block([str, exprs, j], - /* Note, the ex's are assumed to already be strings. - There would be no other way to sort out the $ vs $$'s */ - /* Loop over the expressions */ - exprs:"", - ev(for j:1 thru length(ex) do - /* HACK: !quot! needs to be replaced with " when we get into PHP. */ - exprs:concat(exprs, " , !quot!", ex[j], "!quot! "), simp), - str:concat(fb, "stack_trans('", key, "'", exprs, "); "), - return(str) -)$ - -/* Separate notes with puncutation, to enable clearer reading - and the possibility to split them. */ -StackAddNote(exnote, newnote) := concat(exnote, newnote, ". ")$ - -StackTrimNote(ex) := strim(". ", ex)$ - -/* In many situations we just need the most basic object. */ -StackBasicReturn(validity, result, note) := [validity, result, StackAddNote("", note), StackAddFeedback("", note)]$ - -/* ********************************************************* */ -/* Turns answertest output to a STACK return object string */ -/* */ -/* ex[1] = validity should be true/false */ -/* ex[2] = result should be true/false, */ -/* ex[3] = feedback, a string */ -/* ex[4] = answernote, is for teacher stats */ -/* */ -/* ********************************************************* */ - -StackReturn(ex) := block([str], - if not(listp(ex)) then (print("StackReturn failed: argument not a list: "), print(string(ex)), return("")), - if length(ex)#4 then (print("StackReturn failed: argument wrong length: "), print(string(ex)), return("")), - print(" ], valid = [ "), - if ex[1] then print(1) else print(0), - print(" ], answernote = [ "), - print(ex[3]), - print(" ], feedback = [ "), - print(ex[4]), - return(ex[2]) -)$ - -/* note the extra closing ] here. The corresponding opening [ is generated in PHP */ -/* This is about the most ugly API ever, but there we go..... */ - -/* ******************************************* */ -/* Validate an expression */ -/* ******************************************* */ - -stack_validate(expr, ForbidFloats, LowestTerms, TAns) := block( [simp:false, exs, SameType], - /* Try to simply the expression to catch CAS errors */ - exs:errcatch(ev(expr, simp)), - if exs=[] then return(false), - if length(expr)#1 then print(StackAddFeedback("", "CommaError",string(expr), string(setify(expr)))), - expr:first(expr), - /* Check for floats, and if there are any then throw an error */ - if ForbidFloats and anyfloatex(expr) then - print(StackAddFeedback("", "Illegal_floats")), - /* Checks fractions are in lowest terms */ - if LowestTerms and all_lowest_termsex(expr)=false then - print(StackAddFeedback("", "Lowest_Terms")), - /* Check if the student's answer is the same type as the Teachers */ - SameType:ATSameTypefun(expr, TAns), - if SameType[2]#true then print(SameType[4]), - /* Now display the result */ - simp:false, - expr:detexcolor(expr), - expr:detexdecorate(expr), - return(expr) -)$ - -/* Validate an expression without type checking. Floats and mathematical errors only. */ -stack_validate_typeless(expr, ForbidFloats, LowestTerms) := block( [simp:false, exs], - /* Try to simply the expression to catch CAS errors */ - exs:errcatch(ev(expr, simp)), - if exs = [] then return(false), - if length(expr)#1 then print(StackAddFeedback("", "CommaError", expr, setify(expr))), - expr:first(expr), - /* Check for floats, and if there are any then throw an error */ - if ForbidFloats and anyfloatex(expr) then - print(StackAddFeedback("", "Illegal_floats")), - /* Checks fractions are in lowest terms */ - if LowestTerms and all_lowest_termsex(expr) = false then - print(StackAddFeedback("", "Lowest_Terms")), - /* Now display the result */ - simp:false, - return(expr) -)$ - -/* This function replaces all variables starting with a % sign with elements from var */ -stack_strip_percent(ex,var) := block([lv1, lv2, subcount, indx,exs], - subcount:0, - lv2:[], - lv1:listofvars(ex), - if [] = lv then return(ex), - for indx:1 thru length(lv1) do ( - if cequal(charat(string(lv1[indx]), 1),"%") then block( - subcount:subcount+1, - lv2:append(lv2, [lv1[indx] = var[subcount]]) - ) - ), - if not(emptyp(lv2)) then exs:subst(lv2, ex) else exs:ex, - return(exs) -)$ - -/* These functions convert all variables in an expression to products of single letter variable names. */ -stack_singlevar_make_helper(ex) := block([s], - s:maplist(eval_string, charlist(string(ex))), - apply("*", s) -)$ - -stack_singlevar_make(ex) := block([vars, subs], - vars:sublist(listofvars(ex), lambda([ex], if slength(string(ex))>1 then true else false)), - if emptyp(vars) then return(ex), - vars:maplist(lambda([ex], ex=stack_singlevar_make_helper(ex)), vars), - sublis(vars, ex) -)$ - - -/* *************************************/ -/* Output graphics, */ -/* *************************************/ - -set_plot_option([run_viewer, false]); -set_plot_option([plot_format, gnuplot]); -set_plot_option([nticks, 50]); -set_plot_option([adapt_depth, 10]); -set_plot_option([gnuplot_default_term_command, ""]); - -plot(ex,[ra]) := /*stack_web_plot*/ - block([simp:true, tfn, afn, ufn, lvs, preamble, sysp, sysr, filename, tn, alt, altc, alttext, ral, ralforbid, pltargs, plotfunmake], - /* Arguments to plot must be lists */ - ral:sublist(ra, listp), /* The actual arguments used by plot */ - /* Check expressions to be plotted has/have only one variable. */ - ex:ev(ex, nouns, simp), - lvs:listofvars(ex), - lvs:sublist(lvs,lambda([ex],not(ex=discrete or ex=parametric))), - if length(lvs)>1 then - (print(concat("Plot error: Can't create a plot with more than one variable, whereas you have: \\(",string(lvs),"\\)")), - return("<center>[Empty plot]</center>")), - /* Sort out alt-text */ - kill(alt), - alttext:concat("STACK auto-generated plot of ", string(ex), " with parameters ", string(ral)), - altc:sublist(ral, lambda([ex], if listp(ex) then is(first(ex)=alt) else false)), - if not(emptyp(altc)) then (ral:delete(first(altc), ral), alttext:second(first(altc))), - if not(stringp(alttext)) then (alttext:"ERROR", print("Plot error: the alt tag definition must be a string, but is not."), return("")), - /* remove from option list ral any non-permitted options */ - kill(y), - permitted_options: [y, xlabel, ylabel, legend, color, style, point_type, nticks, logx, logy, axes, box, plot_realpart], - if not(emptyp(lvs)) then permitted_options:append([first(lvs)], permitted_options), - ralforbid:sublist(ral, lambda([ex], not(member(first(ex), permitted_options)))), - if not(emptyp(ralforbid)) then - (print(concat("Plot error: STACK does not currently support the following plot2d options: \\(",string(ralforbid),"\\)")), - return("<center>[Empty plot]</center>")), - /* Assemble files names and URLs */ - tn:string(absolute_real_time()), - filename:concat("stackplot","-",tn,"-",string(rand(10^8))), - tfn:concat(TMP_IMAGE_DIR, filename, ".plt"), - afn:concat("'", IMAGE_DIR, filename, ".", PLOT_TERMINAL, "'"), - ufn:concat("<div class=\"stack_plot\"><img src='", URL_BASE, filename, ".", PLOT_TERMINAL, "' alt='", alttext, "' /></div>"), - if OPT_OUTPUT#"MathML" then - ufn:concat(" <html>", ufn, "</html> "), - /* Sort out plot_options and preamble*/ - preamble:"", - if not(member(xlabel, maplist(first, ral))) then ral:append(ral, [[xlabel, ""]]), - if not(member(ylabel, maplist(first, ral))) then ral:append(ral, [[ylabel, ""]]), - if member(legend, maplist(first, ral)) then block([lv], - /* If we have [legend, true] then we should use the default legend */ - lv:sublist(ral, lambda([ex], (first(ex)=legend))), - if second(first(lv))=true then ral:delete([legend, true], ral) - ) else block( - ral:append(ral, [[legend, false]]) - ), - if not(member(axes, maplist(first, ral))) then block([lv], - preamble:"set zeroaxis -set grid -" - ), - /* Note, the axes option in Maxima doesn't seem to work.... */ - preamble:concat(preamble, "set terminal ",PLOT_TERMINAL," ",PLOT_TERM_OPT," -set output ",afn), - set_plot_option([gnuplot_out_file, tfn]), - set_plot_option([gnuplot_preamble, preamble]), - /* Create and execute the actual plot commands */ - pltargs:append([ex], ral), - plotfunmake:funmake(plot2d, pltargs), - ev(plotfunmake), - sysp:concat(GNUPLOT_CMD, " ", tfn), - sysr:concat(DEL_CMD, " ", tfn), - system(sysp), - system(sysr), - simp:old_simp, - return(ufn) -)$ - -/* ********************************** */ -/* Numerical operations */ -/* ********************************** */ - -ATNumAbsolute(SA, SB) := ATNumerical(SA, SB, "ABSOLUTE")$ -ATNumRelative(SA, SB) := ATNumerical(SA, SB, "RELATIVE")$ - - -ATNumerical(SA, SB, numtype) := block([simp:true, RawMark, FeedBack, AnswerNote, ret, SAN, tol], - Validity:false, RawMark:false, - FeedBack:StackAddFeedback("", "ATNumerical_FAILED"), - AnswerNote:StackAddNote("", "ATNumerical_FAILED"), - /* Turn on simplification and error catch */ - SA:errcatch(ev(float(SA), simp, nouns)), - if is(SA = [STACKERROR]) then return(StackBasicReturn(false, false, "ATNumerical_STACKERROR_SAns")), - SA:SA[1], - SAN:copy(SA), /* Need this for when we have lists etc */ - SB:errcatch(ev(float(SB), simp, nouns, rat)), - if is(SB = [STACKERROR]) then return(StackBasicReturn(false, false, "ATNumerical_STACKERROR_TAns")), - SB:SB[1], - if not(listp(SB)) then (print("TEST_FAILED"), return(StackBasicReturn(false, false, "ATNumerical_STACKERROR_TA_not_list"))), - if not(is(length(SB)=2)) then (print("TEST_FAILED"), return(StackBasicReturn(false, false, "ATNumerical_STACKERROR_TA_wrong_length"))), - tol:SB[2], - if not(numberp(tol)) then (print("TEST_FAILED"), return(StackBasicReturn(false, false, "ATNumerical_STACKERROR_tol"))), - if not(elementp(numtype, {"ABSOLUTE", "RELATIVE"})) then (print("TEST_FAILED"), return(StackBasicReturn(false, false, "ATNumerical_testname_invalid"))), - SB:SB[1], - - /* Are we dealing with lists? */ - if listp(SB) then - if listp(SAN)#true then - return(StackBasicReturn(false, false, "ATNumerical_SA_not_list")) - else - return(ATNumerical_list(SA, SB, numtype, tol)), - - /* Are we dealing with lists? */ - if setp(SB) then - if setp(SAN)=false then - return(StackBasicReturn(false, false, "ATNumerical_SA_not_set")) - else - return(ATNumerical_set(SA, SB, numtype, tol)), - - /* Are we dealing with numbers? */ - /*print(ev(abs(float(SA-SB)), simp)), - print(ev(abs(tol)+STACK_NUM_TOL, simp)),*/ - if numberp(SAN) then - if numberp(TA) then - return(StackBasicReturn(false, false, "ATNumerical_SA_not_number")) - else - if numtype = "ABSOLUTE" then - return([false, numabsolutep(SA, SB, tol), "", ""]) - else - return([false, numrelativep(SA, SB, tol), "", ""]), - - ret:[Validity, RawMark, AnswerNote, FeedBack], - return(ret) -)$ - -/* We have to define our own working precision. */ -STACK_NUM_TOL:10E-10$ -numabsolutep(sa,ta,tol) := if ev(abs(float(sa-ta)), simp) < ev(abs(tol)+STACK_NUM_TOL, simp) then true else false; -numrelativep(sa,ta,tol) := if ev(abs(float(sa-ta)), simp) < ev(abs(ta*tol)+STACK_NUM_TOL, simp) then true else false; - -ATNumerical_list(SA, SB, numtype, tol) := block([SAl, SBl, cl, res, fb:"", an:""], - SAl:length(SA), - SBl:length(SB), - if (SAl#SBl) then - return([true, false, StackAddNote("","ATNumerical_wronglen"), StackAddFeedback("", "ATList_wronglen", StackDISP(SBl, "i"), StackDISP(SAl, "i"))]), - - if numtype = "ABSOLUTE" then - cl:zip_with(lambda([ex1,ex2], numabsolutep(ex1, ex2, tol)), SA, SB) - else - cl:zip_with(lambda([ex1,ex2], numrelativep(ex1, ex2, tol)), SA, SB), - - res:apply("and", cl), - if not(res) then block([we], - fb:zip_with(lambda([ex1,ex2],if ex1 then ex2 else texcolor("red", ex2)), cl, SA), - we:maplist(second, sublist(zip_with("[", cl, SA), lambda([ex], not(first(ex))))), - an:StackAddNote("", concat("ATNumerical_wrongentries SA/TA=", string(we))), - fb:StackAddFeedback("", "ATList_wrongentries", StackDISP(fb, "d")) - ), - - return([true, res, an, fb]) -)$ - -ATNumerical_set(SA, SB, numtype, tol) := block([SAl, SBl, cl, res, fbl, fb:"", an:""], - SAl:length(SA), - SBl:length(SB), - if (SAl#SBl) then - return([true, false, StackAddNote("","ATNumerical_wronglen"), StackAddFeedback("", "ATSet_wrongsz", StackDISP(SBl, "i"), StackDISP(SAl, "i"))]), - - SA:sort(float(listify(SA))), - SB:sort(float(listify(SB))), - fbl:num_compare_helper(SA, SB, [], [], tol, numtype), - if emptyp(first(fbl)) and emptyp(second(fbl)) then res:true else res:false, - - if not(res) then block( - fb:setify(reverse(maplist(lambda([ex], texcolor("red", ex)), second(fbl)))), - fb:StackAddFeedback("", "ATList_wrongentries", StackDISP(fb, "d")), - an:StackAddNote("", concat("ATNumerical_wrongentries: TA/SA=", string(reverse(first(fbl))), ", SA/TA=", string(reverse(second(fbl))))) - ), - - return([true, res, an, fb]) -)$ - -/*************************************************** -Need a function which identifies which elements of the student's set, fall within "tolerance-balls" of elements of the teacher's set. - -Takes various arguments -(1) student's list -(2) teacher's list -(3) numbers in the student's list, not within appropriate tolerance of any in the teacher's list -(4) numbers in the teacher's list, which do not occur (approximated) in the student's -(5) tolerance - whether this is absolute or relative to the teacher's answer needs to be sorted out internally to the function. -(6) type - either "ABSOLUTE" or "RELATIVE" - -Returns all of the above + a feedback list. - -All arguments 1-2 are ordered lists of floats, smallest to largest. - -Want sa to lie between -(ta-tol,ta+tol) or (ta-ta*tol,ta+ta*tol) depending on "ABSOLUTE" or "RELATIVE" (respectively) -****************************************************/ -num_compare_helper(sal, tal, missing, excessive, tol, type) := block([sa, ta, f1, f2], - /* If we've run out of answers */ - if emptyp(sal) and emptyp(tal) then return([missing, excessive]), - if emptyp(sal) then return([append(tal, missing), excessive]), - if emptyp(tal) then return([missing, append(sal, excessive)]), - /* Otherwise, we take the first element of the list and calculate */ - /* if sa<ta-tol, then f1<0. */ - /* if abs(sa-ta)<abs(tol), then f2<0. */ - /* We appear to need to calulate f1 & f2 as variables, */ - /* otherwise Maxima's is complains "undefined". Odd... */ - sa:first(sal), - ta:first(tal), - if type="ABSOLUTE" then - (f1:ev(float(sa-ta+tol),simp), - f2:ev(float(abs(sa-ta)-abs(tol)), simp)) - else - (f1:ev(float(sa-ta*(1-tol)),simp), - f2:ev(float(abs(sa-ta)-abs(ta*tol)), simp)), - /*print([sa,ta,f1,f2]),*/ - if is(f1<0) then return(num_compare_helper(rest(sal), tal, missing, append([sa], excessive), tol, type)), - if is(f2<0) - then return(num_compare_helper(rest(sal), rest(tal), missing, excessive, tol, type)), - return(num_compare_helper(sal, rest(tal), append([ta], missing), excessive, tol, type)) -)$ - - - -ATNumSigFigs(SA,SBL) := block([Validity, RawMark, FeedBack, AnswerNote, ret, ol, nsf, asf, c0, c1, c2, SAA, SBB], - Validity:true, RawMark:true, FeedBack:"", AnswerNote:"", - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA = [STACKERROR]) or is(SAA = [])) then return([false, false, StackAddNote("","ATNumSigFigs_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(SBL, simp, nouns)), - if (is(SBB = [STACKERROR]) or is(SBB = [])) then return([false, false, StackAddNote("","ATNumSigFigs_STACKERROR_TAns"), ""]), - - /* SBL is a list: the teacher's answer, the variable, and whether formative feedback is to be provided. */ - /* Sort out options */ - if listp(SBL) then (SB:SBL[1], ol:SBL[2]) else - (print("TEST_FAILED"), return([false, false, StackAddNote("", "ATNumSigFigs_STACKERROR_no_option"), StackAddFeedback("", "TEST_FAILED_Q")])), - if listp(ol) then - if length(ol)#2 then - (print("TEST_FAILED"), return([false, false, StackAddNote("", "ATNumSigFigs_STACKERROR_list_wrong_length"), StackAddFeedback("", "TEST_FAILED_Q")])) - else - (nsf:ol[1], asf:ol[2]) - else (nsf:ol, asf:ol), - if not(integerp(nsf) and integerp(asf)) then - (print("TEST_FAILED"),return([false, false, StackAddNote("", "ATNumSigFigs_STACKERROR_not_integer"), StackAddFeedback("", "TEST_FAILED_Q")])), - /* SA should be only a number. */ - SA:errcatch(ev(SA, simp, nouns)), - if is(SA = [STACKERROR]) then return([false, false, StackAddNote("", "ATNumSigFigs_Error simplifying SAns"),""]), - SA:SA[1], - if (not(floatnump(SA)) and not(integerp(SA))) then - return([false, false, StackAddNote("", "ATNumSigFigs_NotDecimal"), StackAddFeedback("", "ATNumSigFigs_NotDecimal")]), - /* Puts Teacher's answer between 0 & 1 */ - c0:-floor(log(abs(float(SB)))/log(10)+1), - c1:SA*10^(c0+floor(nsf)), - if is(float(c1-floor(c1))=0.0)=false then block( - Validity:true, - RawMark:false, - FeedBack:StackAddFeedback(FeedBack, "ATNumSigFigs_WrongDigits"), - AnswerNote:StackAddNote(AnswerNote, "ATNumSigFigs_WrongDigits") - ), - c2:abs(abs(SA*10^(c0+floor(asf)))-abs(SB*10^(c0+floor(asf)))), - if not(is(c2<0.5)) then block( - Validity:true, - RawMark:false, - FeedBack:StackAddFeedback(FeedBack, "ATNumSigFigs_Inaccurate"), - AnswerNote:StackAddNote(AnswerNote, "ATNumSigFigs_Inaccurate") - ), - if RawMark = true then AnswerNote:"", - ret: [Validity, RawMark, AnswerNote, FeedBack], - return(ret) -)$ - -/* ********************************** */ -/* Algebraic tests */ -/* ********************************** */ - -/* A general, all purpose answer test based maximum simplification. - This function is a wrapper for AtAlgEquivfun(SA,SB) -*/ -ATAlgEquiv(SA,SB) := block([simp:true, ret, newret, SAN], - /* Turn on simplification and error catch */ - SA:errcatch(ev(SA, simp, nouns)), - if is(SA = [STACKERROR]) then return([false, false, StackAddNote("", "ATAlgEquiv_STACKERROR_SAns"), ""]), - SA:SA[1], - SAN:copy(SA), /* Need this for when we have lists etc */ - SB:errcatch(ev(SB, simp, nouns, rat)), - if is(SB = [STACKERROR]) then return([false, false, StackAddNote("", "ATAlgEquiv_STACKERROR_TAns"),""]), - SB:SB[1], - /* Start recursive process */ - ret:ATAlgEquivfun(SA, SB), - /* Can we find a permutation of the variables? */ - if ret[2]=0 then block([p1], - p1:subst_equiv(SAN, SB), - /* Actually, at this point 2008/7/7, we don't want to give this feedback. Just leave an answer note. */ - /* if p1#[] and p1#false then ret:[ret[1], ret[2], StackAddNote(ret[3], concat("ATAlgEquiv_Subst ", string(p1))), StackAddFeedback(ret[4], "Subst", StackDISP(p1, "d"))] */ - if p1#[] and p1#false then ret:[ret[1], ret[2], StackAddNote(ret[3], concat("ATAlgEquiv_Subst ", string(p1))), ret[4]] - ), - return(ret) -)$ - -/* ATAlgEquivfun is a recursive "thing" comparing function. It is designed to - cope with a variety of different objects, eg lists of inequalities etc. - - Returns [valid, RawMark, AnswerNote, FeedBack] - where valid = true/false - RawMark = true or false - AnswerNote = "string", - FeedBack = StackFeedback -*/ -ATAlgEquivfun(SA, SB) := block([keepfloat, RawMark, FeedBack, AnswerNote, ret], - Validity:true, RawMark:false, FeedBack:"", AnswerNote:"", - keepfloat:true, - /* Are we dealing with matrices? */ - if matrixp(SB) then - if matrixp(SA)#true then - return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_matrix")) - else - return(ATMatrix(SA, SB)), - /* Are we dealing with lists? */ - if listp(SB) then - if listp(SA)#true then - return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_list")) - else - return(ATList(SA, SB)), - /* Are we dealing with a function? */ - if functionp(SB) then - if functionp(SA)#true then - return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_function")) - else - return(ATFunction(SA, SB)), - /* Are we dealing with an equation? */ - if equationp(SB) then - if equationp(SA)#true then - return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_equation")) - else - return(ATEquation(SA, SB)), - /* Did the student type in an equation, but the teacher did not? */ - if equationp(SA) then return(StackBasicReturn(false, false, "ATAlgEquiv_TA_not_equation")), - /* Are we dealing with an inequality? */ - if inequalityp(SB) then - if inequalityp(SA)#true then - return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_inequality")) - else - return(ATInequality(SA, SB)), - /* Are we dealing with lists? */ - if setp(SB) then - if setp(SA)=false then - return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_set")) - else - return(ATSet(SA, SB)), - /* Has the student typed in the wrong type?*/ - if expressionp(SA)=false then - return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_expression")), - /* Otherwise we have two expressions*/ - if algebraic_equivalence(SA, SB) then - RawMark:true - else if algebraic_equivalence(exdowncase(SA), exdowncase(SB)) then - AnswerNote:StackAddNote("", "ATAlgEquiv_WrongCase"), - ret:[Validity, RawMark, AnswerNote, FeedBack], - return(ret) - )$ - -/* An answer test based on two lists for SA and SB */ -ATList(SA,SB) := block([AddFeedBack, SAN, SAl, SBl, ret, retnew, k, AnsNotes], - /* Get sizes of lists */ - SAN:SA, - SAl:length(SA), - SBl:length(SB), - if (SAl#SBl) then - return([true, false, StackAddNote("","ATList_wronglen"), StackAddFeedback("", "ATList_wronglen", StackDISP(SBl, "i"), StackDISP(SAl, "i"))]), - - /* Apply ATAlgEquivfun to each element pair */ - ret:[true, true, "", ""], - AddFeedBack:false, - AnsNotes:[], - for k:1 thru SAl do block([retnew], - retnew:ATAlgEquivfun(SA[k], SB[k]), - ret[1]:ret[1] and retnew[1], - ret[2]:ret[2] and retnew[2], - if not(retnew[3]="") then - AnsNotes:cons(concat(string(k), ": ", StackTrimNote(retnew[3])), AnsNotes) - else if retnew[2]=false then - AnsNotes:cons(string(k), AnsNotes), - if retnew[2] = false then block( - /* ret[4]:concat(ret[4],retnew[4]), */ - if not(listp(SA[k]) or matrixp(SK[k]) or setp(SK[k])) then block( - SAN[k]:texcolor("red", SA[k]) - ), - AddFeedBack:true - ) - ), - if AddFeedBack = true then block( - ret[3]:StackAddNote("", concat("(ATList_wrongentries ", simplode(reverse(AnsNotes), ", "), ")") ), - ret[4]:concat(StackAddFeedback("", "ATList_wrongentries", StackDISP(SAN, "d")), ret[4]) - ), - return(ret) -)$ - -/* Equations */ -/* Note, this uses exand, which will break large expressions */ -stack_eqnprepare(ex) := block([ret, keepfloat], - keepfloat:true, - ret:fullratsimp(trigexpand(rhs(ex)-lhs(ex))), - ret:ret*denom(ret), - return(expand(ret)) -)$ - -stack_eqncompare(SA, SB, sl) := block([ret,G0,G1], - G0 :poly_buchberger(SA, sl), - G1 :poly_buchberger(SB ,sl), - ret:poly_grobner_equal(G0, G1, sl), - return(ret) -)$ - -stack_assignmentp(ex) := block( - if atom(ex) then return(false) - else if op(ex)#"=" then return(false) - else if atom(lhs(ex)) and not(real_numberp(lhs(ex))) and real_numberp(rhs(ex)) then return(true) - else return(false) -)$ - -stack_assignmentrev(ex) := block( - if atom(ex) then return(ex) - else if op(ex)#"=" then return(ex) - else if real_numberp(lhs(ex)) and not(real_numberp(rhs(ex))) then return(rhs(ex)=lhs(ex)) - else return(ex) -)$ - -/* Take a list of equations, and re-evaluate it in the context of any assignments of the form d=10 - This is needed in practice with systems of equations, as students may write [d=10, d=v*t] */ -stack_eval_assignments(ex) := block([asl, sl], - if not(listp(ex)) then return(ex), - sl:maplist(stack_assignmentrev, ex), - asl:sublist(sl, stack_assignmentp), - if not(emptyp(asl)) then block( - sl:listify(setdifference(setify(sl), setify(asl))), - sl:ev(sl, asl) - ), - return(sl) -)$ - -/* Two equations are the "same" when they have identical roots - with identical multiplicities */ -ATEquation(SA, SB) := block([keepfloat, RawMark, SA1, SB1, SB2, R1, R2], - keepfloat:false, - RawMark:false, - - /* First try without expanding out the equations */ - R1:ev(lhs(factor(SA))-rhs(factor(SA)), simp), - R2:ev(lhs(factor(SB))-rhs(factor(SB)), simp), - if (R1=0 and R2=0) then - return([true, true, "", ""]), - if numberp(float(abs(R1/R2))) then - return([true, true, "", ""]), - /* Next, expand out the equations */ - SA1:stack_eqnprepare(SA), - SB1:stack_eqnprepare(SB), - if SA1#0 then - /* We need a slight hack to turn %i+1 into a number */ - RawMark:block( - SB2:float(abs(ev(fullratsimp(SA1/SB1),simp))), - if numberp(SB2) then true else false - ) - else - RawMark:if SB1=0 then true else false, - return([true, RawMark, "ATEquation_expanded", ""]) - )$ - -ATInequality(SA, SB) := block([RawMark, FeedBack, AnswerNote, SA1, SB1, samex], - RawMark:false, FeedBack:"", AnswerNote:"", - /* Write the inequalities in canonical form then compare. */ - SA:ineqorder(SA), - SB:ineqorder(SB), - if SA = SB then RawMark:true, - /* Now try to give some basic feedback: potential for more work to recurse over complex expressions... */ - if op(SA) = ">" and op(SB) =">=" then block( - AnswerNote:StackAddNote("", "ATInequality_strict"), - FeedBack:StackAddFeedback("", "ATInequality_strict") - ), - if op(SA) = ">=" and op(SB) =">" then block( - AnswerNote:StackAddNote("", "ATInequality_nonstrict"), - FeedBack:StackAddFeedback("", "ATInequality_nonstrict") - ), - if (">" = op(SA) or ">=" = op(SA)) and (">" = op(SB) or ">=" = op(SB)) then block( - SA1:ev(part(SA, 1), simp), - SB1:ev(part(SB, 1), simp), - if algebraic_equivalence(-1*SA1,SB1) then block( - AnswerNote:StackAddNote(AnswerNote, "ATInequality_backwards"), - FeedBack:StackAddFeedback(FeedBack, "ATInequality_backwards") - ) - ), - return([true, RawMark, AnswerNote, FeedBack]) -)$ - - -/* This (experimental) code decides if two functions are the same. Strict notion currently. */ -ATFunction(SA, SB) := block([RawMark, FeedBack, AnswerNote, df, SA1, SB1, SAd1, SBd1], - RawMark:true, FeedBack:"", AnswerNote:"", - if not(functionp(SA)) then return([false, 0, "ATFunction_SA_not_function", FeedBack]), - if not(functionp(SB)) then return([false, 0, "ATFunction_TA_not_function", FeedBack]), - SA1:args(SA), SAd1:second(SA1), - SB1:args(SB), SBd1:second(SB1), - /* Are the functions the same name? */ - if not(is(op(first(SA1)) = op(first(SB1)))) then block( - AnswerNote:StackAddNote("", "ATFunction_wrongname"), - RawMark:false - ), - /* Are the arguments the same? */ - if is(length(args(first(SA1))) = length(args(first(SB1)))) then block( - if not(is(args(first(SA1)) = args(first(SB1)))) then block( - AnswerNote:StackAddNote(AnswerNote, "ATFunction_arguments_different"), - SAd1:subst(zip_with("=", args(first(SA1)), args(first(SB1))), SAd1) - ) - ) else block( - AnswerNote:StackAddNote(AnswerNote, "ATFunction_length_args"), - RawMark:false - ), - df:ATAlgEquivfun(SAd1, SBd1), - if second(df) then block( - AnswerNote:StackAddNote(AnswerNote, "ATFunction_true") - ) else block ( - AnswerNote:StackAddNote(AnswerNote, "ATFunction_false"), - RawMark:false - ), - return([true, RawMark, AnswerNote, FeedBack]) -)$ - -/* An answer test based on two matrices for SA and SB. */ -ATMatrix(SA, SB) := block([RawMark, FeedBack, AnswerNote, str, ret, SAr, SAc, SBr, SBc, k, AddFeedBack], - RawMark:true, FeedBack:"", AnswerNote:"", - /* Get sizes of matrices */ - SAr:length(SA), - SAc:length(SA[1]), - SBr:length(SB), - SBc:length(SB[1]), - FeedBack:StackAddFeedback("", "ATMatrix_wrongsz", StackDISP(SBr, "i"), StackDISP(SBc, "i"), StackDISP(SAr, "i"), StackDISP(SAc, "i")), - if (SAr#SBr) then - return([true, false, StackAddNote("", "ATMatrix_wrongsz_rows"), FeedBack]), - if (SAc#SBc) then - return([true, false, StackAddNote("", "ATMatrix_wrongsz_columns"), FeedBack]), - FeedBack:"", - /* Check they are equal */ - ret:[true, true, "", ""], - AddFeedBack:false, - for k:1 thru SAr do block([retnew], - retnew:ATAlgEquivfun(SA[k],SB[k]), - ret[1]:ret[1] and retnew[1], - ret[2]:ret[2] and retnew[2], - ret[3]:concat(ret[3], " ", retnew[3]), - if retnew[2]=false then AddFeedBack:true - ), - if AddFeedBack = true then block( - /* TODO: better answernotes for matrices */ - ret[3]:StackAddNote("", "ATMatrix_wrongentries"), - ret[4]:StackAddFeedback("", "ATMatrix_wrongentries", StackDISP(SA, "d")) - ), - return(ret) - )$ - -/* An answer test based on two sets for SA and SB. */ -ATSet(SA, SB) := block([RawMark, FeedBack, AnswerNote, str, SAl, SBl, ZM], - RawMark:true, FeedBack:"", AnswerNote:"", - /* Get sizes of matrices */ - SAl:cardinality(SA), - SBl:cardinality(SB), - FeedBack:StackAddFeedback("", "ATSet_wrongsz", StackDISP(SBl, "i"), StackDISP(SAl, "i")), - if (SAl#SBl) then - return([true, false, StackAddNote("", "ATSet_wrongsz"), FeedBack]), - FeedBack:"", - /* Check they are equal */ - SA:map(ineqprepare, map(trigreduce, SA)), - SB:map(ineqprepare, map(trigreduce, SB)), - if (subsetp(SA, SB) and subsetp(SB, SA)) then - return([true, true, AnswerNote, FeedBack]), - /* Can we give feedback on which are wrong */ - FeedBack:StackAddFeedback("", "ATSet_wrongentries", StackDISP(setdifference(SA, SB), "d")), - return([true, false, StackAddNote("","ATSet_wrongentries"), FeedBack]) -)$ - -/* A wrapper for an all purpose answer test which checks things are of the - same "type". Based upon the results of AtAlgEquivfun(SA,SB) -*/ -ATSameType(SA, SB) := block([ret], - ret:ATSameTypefun(SA,SB), - /* This test gives no feedback */ - ret[3]:"", - ret[4]:"", - return([true, ret[2], ret[3], ret[4]]) -)$ - - -/* A general, all purpose answer test which checks things are of the - same "type". Based upon the results of AtAlgEquivfun(SA,SB) -*/ -ATSameTypefun(SA, SB) := block([simp:true, ret], - /* Turn on simplification and error catch */ - SA:errcatch(ev(SA, simp, nouns)), - if is(SA = [STACKERROR]) then return([false, false, StackAddNote("", "ATSameTypefun_STACKERROR_SAns"), ""]), - SA:SA[1], - SB:errcatch(ev(SB, simp, nouns)), - if is(SB = [STACKERROR]) then return([false, false, StackAddNote("", "ATSameTypefun_STACKERROR_TAns"), ""]), - SB:SB[1], - /* Start recursive process */ - ret:ATAlgEquivfun(SA, SB), - /* Send back result */ - if ret[1] then - return([true, true, ret[3], ret[4]]) - else - return([true, false, ret[3], ret[4]]) -)$ - -/* Tests if the SA equals SB in lowest terms, and gives feedback. - Note, this is identical to ATAlgEquiv with simp:false otherwise. */ -ATLowestTerms(SA, SB) := block([simp:false, ret, validity, mark, FeedBack, AnswerNote, SAA], - /* Turn on simplification and error catch */ - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA = [STACKERROR]) or is(SAA = [])) then - return([false, false, StackAddNote("", "ATLowestTerms_STACKERROR_SAns"), ""]), - SB:errcatch(ev(SB, simp, nouns)), - if (is(SB = [STACKERROR]) or is(SB = [])) then - return([false, false, StackAddNote("", "ATLowestTerms_STACKERROR_TAns"), ""]), - SB:SB[1], - /* Unpack and check other property */ - validity:true, - mark:true, - AnswerNote:"", - FeedBack:"", - if all_lowest_termsex(SA) = false then block([badNos,a], - mark:false, - badNos:list_expression_numbers(SA), - badNos:sublist(badNos,lambda([ex], if lowesttermsp(ex) then false else true)), - AnswerNote:StackAddNote(AnswerNote, "ATLowestTerms_entries"), - if badNos=[] then - FeedBack:StackAddFeedback("", "ATLowestTerms_wrong", "") - else - FeedBack:StackAddFeedback("", "ATLowestTerms_entries", StackDISP(badNos, "d")) - ), - return([validity, mark, AnswerNote, FeedBack]) -)$ - - - -ATSubstEquiv(SA,SB) := block([simp:true, ret], - /* Turn on simplification and error catch */ - SA:errcatch(ev(SA, simp, nouns)), - if is(SA=[STACKERROR]) then return([false, false, StackAddNote("", "ATSubstEquiv_STACKERROR_SAns"), ""]), - SA:SA[1], - SB:errcatch(ev(SB, simp, nouns)), - if is(SB=[STACKERROR]) then return([false, false, StackAddNote("", "ATSubstEquiv_STACKERROR_TAns"), ""]), - SB:SB[1], - ret:ATAlgEquivfun(SA, SB), - /* Can we find a permutation of the variables? */ - if ret[2]=false then block([p1], - p1:subst_equiv(SA, SB), - if p1#[] and p1#false then ret:[true, true, StackAddNote("", concat("ATSubstEquiv_Subst: ", string(p1))), StackAddFeedback("", "Subst", StackDISP(p1, "d"))] - ), - /* Send back result */ - return(ret) -)$ - -/* A general, all purpose answer test based maximum simplification. - This function is a wrapper for AtAlgEquivfun(SA,SB) -*/ -ATAlgEquiv(SA,SB) := block([simp:true, ret, newret, SAN], - /* Turn on simplification and error catch */ - SA:errcatch(ev(SA, simp, nouns)), - if is(SA = [STACKERROR]) then return([false, false, StackAddNote("", "ATAlgEquiv_STACKERROR_SAns"), ""]), - SA:SA[1], - SAN:copy(SA), /* Need this for when we have lists etc */ - SB:errcatch(ev(SB, simp, nouns, rat)), - if is(SB = [STACKERROR]) then return([false, false, StackAddNote("", "ATAlgEquiv_STACKERROR_TAns"),""]), - SB:SB[1], - /* Start recursive process */ - ret:ATAlgEquivfun(SA, SB), - /* Can we find a permutation of the variables? */ - if ret[2]=0 then block([p1], - p1:subst_equiv(SAN, SB), - /* Actually, at this point 2008/7/7, we don't want to give this feedback. Just leave an answer note. */ - /* if p1#[] and p1#false then ret:[ret[1], ret[2], StackAddNote(ret[3], concat("ATAlgEquiv_Subst ", string(p1))), StackAddFeedback(ret[4], "Subst", StackDISP(p1, "d"))] */ - if p1#[] and p1#false then ret:[ret[1], ret[2], StackAddNote(ret[3], concat("ATAlgEquiv_Subst ", string(p1))), ret[4]] - ), - return(ret) -)$ - - -/**********************************************/ -/* */ -/* System Equivalence Test */ -/* */ -/* An addition to STACK using Grobner Bases */ -/* */ -/* Matthew Badger, 2011 */ -/* */ -/**********************************************/ - -/* - - What these functions do: - - - Determine whether the student's and teacher's answers are systems of equations - - Convert the two systems of equations into two systems of expressions - - Determine whether both systems are systems of multivariate polynomials - - Compare the variables in student's and teacher's answers, if they're not the same tell the student - - Find their Buchberger polynomials of the two systems - - Use the Buchberger polynomials to compare the Grobner bases of the two systems - - If the Grobner bases are not equal, determine whether the student's is a subset of the teacher's - - If student's system has equations which should not be there, tell them which ones. -*/ - - - -/* - Main function of the System Equivalence test - - Takes two inputs, checks whether they are - lists of polynomials and delegates everything - else to other functions. - - Process: - - - Is each answer a list? - - Is each list element not an atom? - - Is each list element an equation? - - Is each list element a polynomial? -*/ - -/* Edited files: SysEquiv.php, AnsTestcontroller.php, lang/en/stack.php */ - -ATSysEquiv(SA,SB):=block([keepfloat,Validity, RawMark, FeedBack, AnswerNote, SAA, SAB, S1, S2, varlist, GA, GB, ret], - Validity:true, RawMark:false, FeedBack:"", AnswerNote:"", - keepfloat:true, - - /* Turn on simplification and error catch */ - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATSysEquiv_STACKERROR_SAns"), ""]), - SAB:errcatch(ev(SB, simp, nouns)), - if (is(SAB=[STACKERROR]) or is(SAB=[])) - then return([false, false, StackAddNote("", "ATSysEquiv_STACKERROR_TAns"), ""]), - - /* Are both answers lists? */ - if not listp(SA) then - return(StackBasicReturn(false, false, "ATSysEquiv_SA_not_list")), - if not listp(SB) then - return(StackBasicReturn(false,false,"ATSysEquiv_SB_not_list")), - - /* Are all list elements not atoms? */ - if ev(all_listp(atom,SA),simp) then - return(StackBasicReturn(false,false,"ATSysEquiv_SA_not_eq_list")), - if ev(all_listp(atom,SB),simp) then - return(StackBasicReturn(false,false,"ATSysEquiv_SB_not_eq_list")), - - /* Are all list elements equations? */ - if ev(not all_listp(equationp, SA), simp) then - return(StackBasicReturn(false, false, "ATSysEquiv_SA_not_eq_list")), - if ev(not all_listp(equationp,SB), simp) then - return(StackBasicReturn(false, false, "ATSysEquiv_SB_not_eq_list")), - - /* Turn our equations into expressions */ - S1: ev(maplist(stack_eqnprepare, stack_eval_assignments(SA)), simp), - S2: ev(maplist(stack_eqnprepare, stack_eval_assignments(SB)), simp), - - /* Is S1 is empty? This means we only had assignments in the answer, - i.e. the answer was in a "solved" form, e.g. x=1. */ - if emptyp(S1) and ev(equal(setify(maplist(stack_eqnprepare, SA)), setify(maplist(stack_eqnprepare, flatten(solve(S2,listofvars(S2)))))),simp) then - return([true,true,StackAddNote("","ATSysEquiv_SA_Completely_solved"),""]), - if emptyp(S1) then - return([true,false,StackAddNote("","ATSysEquiv_SA_Not_completely_solved"),""]), - - /* Is each expression a polynomial? */ - if not all_listp(polynomialpsimp, S1) then - return(StackBasicReturn(false,false,"ATSysEquiv_SA_not_poly_eq_list")), - if not all_listp(polynomialpsimp, S2) then - return(StackBasicReturn(false,false,"ATSysEquiv_SB_not_poly_eq_list")), - - /* - At this point have two lists of polynomials. We now check whether the - student's and teacher's polynomials have the same variables. If they do, - we find their Grobner bases and determine whether the systems of - equations have the same solutions - */ - - varlist: listofvars(S2), - if not is(ev(setify(listofvars(S1)),simp)=ev(setify(varlist), simp)) then - return(ATSysEquivVars(S1,S2)), - - GA :ev(poly_buchberger(S1,varlist),simp), - GB :ev(poly_buchberger(S2,varlist),simp), - kill(S1,S2), - - /* Determine whether our two lists of polynomials have the same Grobner Bases */ - if poly_grobner_equal(GA, GB, varlist) then - return([true,true,"",""]), - - /* - We now know the student's answer is in the correct form but there is - something wrong with it. From here we use the grobner package to - determine which, if any, of their equations is correct. - */ - - return(ATSysEquivGrob(GA, GB, SA, varlist)) -)$ - - -/* Takes two lists of expressions and compares the variables in each */ - -ATSysEquivVars(S1,S2):=block([XA,XB], - XA: setify(listofvars(S1)), - XB: setify(listofvars(S2)), - if subsetp(XA,XB) then - return(StackBasicReturn(true,false,"ATSysEquiv_SA_missing_variables")), - if subsetp(XB,XA) then - return(StackBasicReturn(true,false,"ATSysEquiv_SA_extra_variables")), - return(StackBasicReturn(true,false,"ATSysEquiv_SA_wrong_variables")) -)$ - -/* - Grobner basis comparison - - This function takes two Grobner bases and a set of variables and determines - whether the student's system is underdetermined or overdetermined. It also - takes the student's original system so that if it is overdetermined it can - tell them which equations should not be there. -*/ - -ATSysEquivGrob(GA,GB,SA,varlist):=block([retl,ret], - - /* Is the student's system underdetermined? */ - - if poly_grobner_subsetp(GA,GB,varlist) then - return(StackBasicReturn(true,false,"ATSysEquiv_SA_system_underdetermined")), - - /* - Given that the student's system is neither underdetermined nor equal to - the teacher's, we need to find which equations do not belong in the system. - */ - - ret:[], - - for k:1 thru length(SA) do block([], - if ev(poly_grobner_member(stack_eqnprepare(stack_eval_assignments(SA[k])), GB, varlist),simp) then - ret:append(ret,[SA[ev(k,simp)]]) - else - ret:append(ret,[texcolor("red", SA[ev(k,simp)])])), - - return([true,false,StackAddNote("","ATSysEquiv_SA_system_overdetermined"),StackAddFeedback("","ATSysEquiv_SA_system_overdetermined", StackDISP(ret, "d"))]) -)$ - -/*****************************************************************/ - -/* An answer test based on the Maxima's notion of equals. */ -ATCASEqual(SA,SB) := - block([keepfloat:true, Validity:true, RawMark:false, FeedBack:"", AnswerNote:"", SAA, SBB], - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then return([false,false,StackAddNote("","ATCASEqual_STACKERROR_SAns"),""]), - SBB:errcatch(ev(SB, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then return([false,false,StackAddNote("","ATCASEqual_STACKERROR_TAns"),""]), - - if SA=SB then - (RawMark:true, AnswerNote:"ATCASEqual_true") - else - AnswerNote:"ATCASEqual_false", - return([Validity,RawMark,StackAddNote("",AnswerNote),FeedBack]) - )$ - -/* SA>SB? */ -ATGT(SA,SB) := - block([keepfloat, Validity, RawMark, FeedBack, AnswerNote, str, ex], - Validity:true, RawMark:false, FeedBack:"", AnswerNote:"Not number", - keepfloat:true, /* See pg 23 */ - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATGT_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(SB, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false, false, StackAddNote("", "ATGT_STACKERROR_TAns"), ""]), - - ex:ev(float(trigreduce(trigexpand(SA-SB))),simp), - if numberp(ex) then - if ex>0 then - (RawMark:true, AnswerNote:StackAddNote("","ATGT_true")) - else - ( AnswerNote:StackAddNote("","ATGT_false")), - return([Validity,RawMark,AnswerNote,FeedBack]) - )$ - -/* SA>=SB? */ -ATGTE(SA,SB) := - block([keepfloat, Validity, RawMark, FeedBack, AnswerNote, str, ex, SAA, SBB], - Validity:true, RawMark:false, FeedBack:"", AnswerNote:"Not number", - keepfloat:true, - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATGTE_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(SB, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false, false, StackAddNote("", "ATGTE_STACKERROR_TAns"), ""]), - - ex:ev(float(trigreduce(trigexpand(SA-SB))),simp), - if numberp(ex) then - if ex>=0 then - (RawMark:true, AnswerNote:StackAddNote("","ATGTE_true") ) - else - ( AnswerNote:StackAddNote("","ATGTE_false")), - return([Validity,RawMark,AnswerNote,FeedBack]) - )$ - - -/* irred_Q(p,v) is true iff */ -/* (1) p is degree 0 in v */ -/* (2.1) p is linear in v, and the coefficients have no common factors */ -/* (2.2) p is linear in v, and the coefficients of v is -1 */ -/* (3) p is quadratic, the coefficients have no common factors */ -/* and p does not factor over the **rational numberss** */ - -/* Is p an irreducible term in v, over the rationals Q? */ -/* Returns a list, of [true/false, FeedBack, true/false] */ -/* The third argument is the special case when we just have an integer factor to pull out. Needed for PartFrac. */ -irred_Q(p,v) := block([ret,deg,cl,ci], - deg:ev(hipow(expand(p),v),simp), - /* Now perform the general test */ - cl:ev(map(second,coeff_list_nz(expand(p),v)),simp), - /* all coefficients of p are integers? (note, negative number don't count as integers here!) */ - ci:all_listp(lambda([ex],integerp(ev(abs(ex),simp))),cl), - /* General starting position */ - ret:[factorp(p),"",false], - /* Special cases */ - if deg=0 then ret:[true,"",false], - /* Special situation for the linear case to avoid strange results */ - if deg=1 then block([lt], - lt:ev(bothcoef(p,v),simp), - if lt[1]=1 or lt[2]=1 then ret:[true,"",false] - ), - /* Special case of quadratics, which are irreducible over the rationals */ - if deg=2 then block([a,b,c,q], - q:ev(expand(p),simp), - a:ev(coeff(q,v,2),simp), - b:ev(coeff(q,v,1),simp), - c:ev(coeff(q,v,0),simp), - if (b=0 and c=0 and a>1 and ratnump(ev(sqrt(a),simp))) then ret:[true,StackAddFeedback("","irred_Q_optional_fac",StackDISP(p,"i")),false] - else if (b=0 and c=0) then ret:[true,"",false] - else if ratnump(ev(sqrt(b^2-4*a*c),simp)) then ret:[false,"",false] - ), - /* Check we have a common integer factor: note can't use GCD function which only allows 2 arguments */ - if length(cl)>1 and ci and commonfaclist(cl)>1 then ret:[false,StackAddFeedback("","irred_Q_commonint"),true], - if deg>2 then block([q], - /* take out any integer common factor */ - q:p, - if length(cl)>1 and ci then q:ev(expand(p/commonfaclist(cl)),simp), - if is(ev(q#factor(q),simp)) then ret:[false,ret[2],false] - ), - return(ret) -); - -/* Is p a power of an irreducible term in v, over the rationals Q, disregarding the special case of a numerical factor? */ -/* Only used by ATPartFrac */ -/* Returns true/false */ -irred_power_Qp(p,v) := block([ret], - if safe_op(p)="^" then ret:irred_Q(first(args(p)),v) else ret:irred_Q(p,v), - if third(ret) then true else first(ret) -); - -/* Picks apart an expression p of v, and gives some feedback */ -/* on why this is not a factored expression */ -FacForm_UnPick(p,v) := block([negdistrib,PARTSWITCH,fb,i,irred,res], - negdistrib:false, - partswitch:true, - fb:"", - res:true, - if atom(p) then return([true,""]) else - if op(p)="+" then return(irred_Q(p,v)) else - if op(p)="^" then return(irred_Q(part(p,1),v)), - /* So we have a *, or a / */ - for i:1 step 1 while ev(part(p,i),simp)#end do - ( /* We just need to go one level down! */ - irred:block([q], q:part(p,ev(i,simp)), - if atom(q) then return([true,""]) else - if op(q)="+" then return(irred_Q(q,v)) else - if op(q)="^" then return(irred_Q(part(q,1),v)) else return([false,""]) - ), - res:res and irred[1], - if irred[1]=false then - (fb:StackAddFeedback(fb,"FacForm_UnPick_morework",StackDISP(part(p,ev(i,simp)),"i")), - fb:concat(fb,irred[2]) - ) - ), - return([res,fb]) - )$ - - -/* Factored form of a polynomial? */ -/* Assumes all coefficients are integers */ - -ATFacForm(SA,SBL) := block([negdistrib,RawMark,FeedBack,AnswerNote,ret,str,SB,v,SAA,SBB,coefl,facdum], - negdistrib:false, - /* include facdum:'facdum, as in partfrac? */ - Validity:true, RawMark:true, FeedBack:"", AnswerNote:"", - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATFacForm_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(SBL, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false, false, StackAddNote("", "ATFacForm_STACKERROR_TAns"), ""]), - - /* SBL is a list: the teacher's answer, the variable, and whether formative feedback is to be provided. */ - if listp(SBL) then (SB:SBL[1], v:SBL[2]) else - return([false, false, StackAddNote("", "ATFacForm_STACKERROR_LIST"), StackAddFeedback("", "TEST_FAILED")]), - - /* SA should be only an expression. */ - if expressionp(SA)=false then - return([false,false,StackAddNote("","ATFacForm_SA_not_expression"), StackAddFeedback("","ATAlgEquiv_SA_not_expression")]), - - /* If we don't have an atom as the teacher's variable, then we need to make a substitution */ - if atom(v)#true then (SA:subst(facdum, v, SA),SB:subst(facdum, v, SB), v:facdum), - ret: FacFormfun(SA,SB,v), - return(ret) - )$ - -FacFormfun(SA,SB,v) := block([val, rawmk, ansnote, fb, ret, deg, aequiv, up, cont], - val:true, rawmk:true, fb: "", ansnote: "", - ret:[val,rawmk,ansnote,fb], - if errcatch(deg:hipow(expand(SA), v)) = [] then block( - val: false, - rawmk: false, - ansnote: StackAddNote("", "ATFacForm_error_degreeSA"), - fb: StackAddFeedback("", "ATFacForm_error_degreeSA") - ), - aequiv:algebraic_equivalence(SA,SB), - /* An integer answer is always correct. */ - if (integerp(SA)) then - if (SA=SB) then - ansnote: StackAddNote("","ATFacForm_int_true") - else block( - rawmk: false, - ansnote: StackAddNote("","ATFacForm_int_false") - ) - else block( - /* Check for the correct answer. */ - if (aequiv and factorp(SA)) then - ansnote: StackAddNote("","ATFacForm_true") - else block( - if (factorp(SA)) then ( /* We need to provide some feedback, if possible */ - ansnote:StackAddNote(ansnote,"ATFacForm_isfactored"), - fb:StackAddFeedback(fb,"ATFacForm_isfactored") - ) - else - ( up:FacForm_UnPick(SA,v) ), - if (up[1]=false) then ( - rawmk: false, - ansnote:StackAddNote(ansnote,"ATFacForm_notfactored"), - fb:StackAddFeedback(fb,"ATFacForm_notfactored"), - fb:concat(fb,up[2]) - ) - else - ( ansnote:StackAddNote(ansnote,"ATFacForm_default_true") ), - /* Check for algebraic equivalence */ - if (true#aequiv) then ( - rawmk:false, - ansnote:StackAddNote(ansnote,"ATFacForm_notalgequiv"), - fb:StackAddFeedback(fb,"ATFacForm_notalgequiv"), - cont:false /* Unsure what this is for - not used anywhere, or returned, in original code! */ - ) - ) - ), - ret: [val, rawmk, ansnote,fb], - return(ret) - )$ - -/* An answer test based expandp(sa). */ -/* Note, the SB is a dummy to allow one mechanism for calling functions */ -ATExpanded(SA,SB) := - block([keepfloat, Validity, RawMark, FeedBack, AnswerNote, SA1], - Validity:true, RawMark:false, FeedBack:"", AnswerNote:"", SA1:[], - keepfloat:true, - - /* SA should be only an expression. */ - SA1:errcatch(ev(SA, simp, nouns)), - if is(SA1=[STACKERROR]) then return([false, false, StackAddNote("", "ATExpanded_STACKERROR_SAns"), ""]), - /* */ - if expressionp(SA)=false then - return([false, false, StackAddNote("", "ATExpanded_SA_not_expression"), StackAddFeedback("", "ATAlgEquiv_SA_not_expression")]), - if expandp(SA) then - return([true, true, StackAddNote("", "ATExpanded_TRUE"), ""]) - else - return([true, false, StackAddNote("", "ATExpanded_FALSE"), ""]) - )$ - - -/* *************************ATPartFrac Test**************************** */ -/* requires: Student Answer, */ -/* [Teachers Question, */ -/* Respect To which the fractions are parted, */ -/* Formative Feedback] */ -/* returns: StackReturn */ -/* CASE 1: topOp is divisor - single fraction */ -/* CASE 2: CORRECT answer - true */ -/* CASE 3: Different Variables - diff vars */ -/* CASE 4: Different amount of parts - Diff parts */ -/* CASE 5: Different Numerator - ret factored expression */ -/* CASE 6: Different Denominator - ret sDenom and tDenom */ -/* ******************************************************************** */ - -ATPartFrac(SA,SBL) := block([negdistrib,Validity,rawmk,fb,ansnote,ret,SB,v,facdum,wrt,tExpr,sExpr,SAA,SBB], - negdistrib:false, - facdum:'facdum, - Validity:true, rawmk:true, fb:StackAddFeedback("",""), ansnote:"", - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATPartFrac_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(SBL, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false, false, StackAddNote("", "ATPartFrac_STACKERROR_TAns"), ""]), - - /* SBL is a list: the teacher's answer, the variable, and whether formative feedback is to be provided. */ - if listp(SBL) then (tExpr:SBL[1], wrt:SBL[2]) else - return([false,false,StackAddNote("","ATFacForm_STACKERROR_LIST"),StackAddFeedback("","TEST_FAILED")]), - - /* SA should be only an expression. */ - if expressionp(SA)=false then - return([false, false, StackAddNote("", "ATPartFrac_SA_not_expression"), StackAddFeedback("", "ATAlgEquiv_SA_not_expression")]), - - /* tExpr should be only an expression. */ - if expressionp(tExpr)=false then - return([false, false, StackAddNote("", "ATPartFrac_TA_not_expression"), StackAddFeedback("", "ATPartFrac_error_list")]), - - /* If we don't have an atom as the teacher's variable, then we need to make a substitution */ - if atom(v)#true then (SA:subst(facdum,wrt,SA),tExpr:subst(facdum,wrt,tExpr),wrt:facdum), - ret: PartFracfun(SA,tExpr,wrt), - return(ret) - )$ - -/* An expression is in partial fraction form when */ -/* it is a sum of rational terms. In each term */ -/* - the denominator of each term is a power of an */ -/* irreducible (not factorable) polynomial and */ -/* - the numerator is a polynomial of smaller degree */ -/* than that irreducible polynomial. */ -PartFracfun(sExpr,tExpr,wrt) := block([val, rawmk, ansnote, fb], - val:true, rawmk:true, fb: "", ansnote: "", - ret:[val,rawmk,ansnote,fb], - if algebraic_equivalence(sExpr,tExpr) then - block([topOp, list], - topOp: op( sExpr ), - list: args( sExpr ), - /* Sort out any factors the student may have pulled out */ - if topOp = "*" then block( - sExpr:expand(sExpr), - topOp: op(sExpr), - list: args(sExpr) - ), - if topOp = DIV_OP then list:[sExpr] else list: args( sExpr ), - block([sargs,sdenoms], - val:true, - rawmk: true, - ansnote:StackAddNote("","ATPartFrac_true"), - /* We need to check that each term in the student's sum is in lowest terms ... */ - if not all_listp(lambda([ex], real_numberp(gcd(num(ex),denom(ex)))),list) then - block( - rawmk: false, - ansnote:StackAddNote("","ATPartFrac_false_lowestterms") - ), - /* ... with the degree(num)<degree(den) */ - if not all_listp(lambda([ex],if denom(ex)=1 then true else is(ev(hipow(expand(num(ex)),wrt)<hipow(expand(denom(ex)),wrt),simp))),list) then - block( - rawmk: false, - ansnote:StackAddNote("","ATPartFrac_false_degree") - ), - /* We need to check that each denominator is the power of an irreducible factor */ - /* Note the slight cludge to check if we have a numerical factor */ - if not all_listp(lambda([ex],irred_power_Qp(denom(ex),wrt)), list) then - block( - rawmk: false, - ansnote:StackAddNote("","ATPartFrac_false_factor") - ) - ), - ret: [val,rawmk,ansnote,fb], - return(ret) - ) - else if sameVars(sExpr, tExpr) then - block([sDeg,tDeg,sNDeg,tNDeg], - sDeg: ev(hipow(expand(denom(factor(sExpr))),wrt),simp), - tDeg: ev(hipow(expand(denom(factor(tExpr))),wrt),simp), - sNDeg: ev(hipow(expand(num(factor(sExpr))),wrt),simp), - tNDeg: ev(hipow(expand(num(factor(tExpr))),wrt),simp), - if tDeg # sDeg then - block( - val:true, - rawmk: false, - ansnote: StackAddNote("","ATPartFrac_denom_ret"), - fb: StackAddFeedback("","ATPartFrac_denom_ret", StackDISP(denom(factor(sExpr)),"i"), StackDISP(denom(factor(tExpr)),"i")), - ret: [val,rawmk,ansnote,fb], - return(ret) - ) - else - block( - val: true, - rawmk: false, - ansnote: StackAddNote("","ATPartFrac_ret_expression"), - fb: StackAddFeedback("", "ATPartFrac_ret_expression", StackDISP(factor(sExpr),"i")), - ret: [val,rawmk,ansnote,fb] - ) - ) - else - block( - val: false, - rawmk: false, - ansnote : StackAddNote("","ATPartFrac_diff_variables"), - fb:StackAddFeedback("","ATPartFrac_diff_variables"), - ret: [val, rawmk, ansnote,fb] - ), - return(ret) - )$ - -/* ************************ATSingFracTest****************************** */ -/* requires: Student Answer */ -/* List: [Teachers Answer, variable with which partial */ -/* fraction occurs, whether Formative Feedback is required */ -/* returns: StackReturn */ -/* Cases: */ -/* Returns True iff algebraic equivalence with TList[1] */ -/* and Division is the Top Operator. */ -/* False if Division not the top operator */ -/* False if different Variables are used */ -/* True(0) otherwise */ -/* ******************************************************************** */ -ATSingleFrac(SA, SB):= block( - [simp:false,negdistrib, validity, rawmk, fb, fbn, ansnote, ret,SAA,SBB], - negdistrib: false, - validity:true, rawmk:false, fb:"", ansnote:"", - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATSingleFrac_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(SB, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false, false, StackAddNote("", "ATSingleFrac_STACKERROR_TAns"), ""]), - - /* sExpr should be only an expression. */ - if expressionp(SA)=false then - return([false,false,StackAddNote("","ATSingleFrac_SA_not_expression"),StackAddFeedback("","ATAlgEquiv_SA_not_expression")]), - - if atom(SA) then - if algebraic_equivalence(SA,SB) then - return([true,true,"",""]) - else - return(StackBasicReturn(true,false,"ATSingleFrac_ret_exp")), - - /* Check for single fraction */ - fbn:"", - if op(SA) = DIV_OP then block( - if (freeof(DIV_OP,num(SA)) and freeof(DIV_OP,denom(SA))) then block( - rawmk:true, - ansnote:"ATSingleFrac_true") - else block( - rawmk:false, - ansnote:"ATSingleFrac_div") - ) - else block( - rawmk:false, - ansnote:"ATSingleFrac_part"), - fb: StackAddFeedback(fb,ansnote), - ansnote:StackAddNote("",ansnote), - /* Check for algebraic equivalence */ - if not(algebraic_equivalence(SA,SB)) then block( - rawmk:false, - fbn:"ATSingleFrac_ret_exp", - fb: StackAddFeedback(fb,fbn), - ansnote:StackAddNote(ansnote,fbn) - ), - return([validity,rawmk,ansnote,fb]) -)$ - - -/*****************************************************************/ -/* Useful function for Partial Fractions */ -/*****************************************************************/ - -divthru(q):= - if (not atom(q) and part(q,0)=DIV_OP) - then - block([num,den,div,quo,rem], - num:part(q,1), - den:part(q,2), - div:divide(num,den) , - quo:div[1], - rem:div[2], - quo+rem/ den ) - else q; - -/*****************************************************************/ -/* Partial Fractions answer Test functions */ -/*****************************************************************/ - -/* *******Functions Used******** */ -/* isDenomSame(sExpr, tExpr) */ -/* isNumSame(sExpr, tExpr) */ -/* isPartFrac(sExpr, tExpr, wrt) */ -/* sameVars(expr1, expr2) */ -/* ***************************** */ - -/* ************Denominator Same Test*************************** */ -/* requires: Students partial Fraction part */ -/* Teachers Partial Fraction part */ -/* returns: Boolean true iff denominators are equivalent */ -/* false otherwise */ -/* ************************************************************ */ - -isDenomSame(sPFrac,tPFrac):= - ( - if denom(expand(sPFrac)) = denom(expand(tPFrac)) - then true - else - false - ); - - -/* When checking the form of a partial fraction, we need to ensure that the - *form* of the demoninators are the same. That is to say that the sets - of expressions on the denominators are equal, up to +/-1. For example, - we could have 1/(n+1)+1/(1-n) or 1/(n+1)-1/(n-1). This makes life harder! -*/ -sameDenoms(SA,TA) := block([k,ret,sAargs,sAset,tAargs,tAset,dTA,dTB], - tAargs:args(TA), - tAset:set(), - /* Create a set of +-1*denoms in the teacher's expression */ - for k:1 thru length(tAargs) do block( - dTA : ev(expand(denom(tAargs[k])),simp), - dTB : ev(expand(-1*denom(tAargs[k])),simp), - tAset : union(set(dTA,dTB),tAset) - ), - /* Create a set of +-1*denoms in the student's expression */ - sAargs:args(SA), - sAset:set(), - for k:1 thru length(sAargs) do block( - dTA : ev(expand(denom(sAargs[k])),simp), - dTB : ev(expand(-1*denom(sAargs[k])),simp), - sAset : union(set(dTA,dTB),sAset) - ), - ret:(subsetp(sAset,tAset) and subsetp(sAset,tAset)), - return(ret) -)$ - - -/* **************Numerator Same Test*************************** */ -/* requires: Students partial Fraction part */ -/* Teachers Partial Fraction part */ -/* returns: Boolean true iff numerators are equivalent */ -/* false otherwise */ -/* ************************************************************ */ - -isNumSame(sPFrac, tPFrac):= - ( - if num(expand(sPFrac)) = num(expand(tPFrac)) - then true - else - false - ); - - -/* ***************Variables used the Same********************** */ -/* requires: 2 Expressions */ -/* returns: true: iff expr 1 and expr2 contain same vars */ -/* false: otherwise */ -/* ************************************************************ */ - -sameVars(expr1, expr2):= - block([list1,list2], - list1: listofvars(expr1), - list2: listofvars(expr2), - if list1=list2 then true - else false - ); - -/* ********************************** */ -/* Completed squares */ -/* ********************************** */ - -ATCompSquare(SA,SBL) := block([Validity,RawMark,FeedBack,AnswerNote,ret,wrt,SB,SAA,SBB,facdum,opa,argsa,deg,cform,ae], - Validity:true,RawMark:true, FeedBack:"", AnswerNote:"", cform:false, - SAA:errcatch(ev(SA,simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATCompSquare_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(SBL,simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false, false, StackAddNote("", "ATCompSquare_STACKERROR_TAns"), ""]), - - /* SBL is a list: the teacher's answer, the variable, and whether formative feedback is to be provided. */ - if listp(SBL) then (SB:SBL[1], wrt:SBL[2]) else - return([false,false,StackAddNote("", "ATCompSquare_STACKERROR_LIST"), ""]), - - /* SA should be only an expression. */ - if expressionp(SA)=false then - return([false, false, StackAddNote("", "ATCompSquare_STACKERROR_LIST"), StackAddFeedback("", "ATAlgEquiv_SA_not_expression")]), - - /* If we don't have an atom as the teacher's variable, then we need to make a substitution */ - if atom(wrt)#true then (SA:subst(facdum, wrt, SA), SB:subst(facdum, wrt, SB), wrt:facdum), - - if member(wrt,listofvars(SB)) and not(member(wrt,listofvars(SA))) then - return([true, false, StackAddNote("", "ATCompSquare_SA_not_depend_var"), StackAddFeedback("", "ATCompSquare_SA_not_depend_var", StackDISP(SBL[2], "i"))]), - - opa:safe_op(SA), - - /* Special case of teacher using constant or linear quadratics */ - ae:algebraic_equivalence(SA,SB), - if ae and not(member(wrt,listofvars(SB))) then - return([true,true,StackAddNote("","ATCompSquare_true_trivial"),""]), - if ae and is(degree(expand(SB),wrt)=1) then - return([true,true,StackAddNote("","ATCompSquare_true_trivial"),""]), - - /* case: (x-1)^2 */ - if opa="^" and part(args(SA),2)=2 then cform:true, - - /* case: k*(x-1)^2 */ - if opa="*" then block([argsb], - argsb: sublist(args(SA),lambda([ex],elementp(wrt,setify(listofvars(ex))))), - if length(argsb)=1 then - if op(argsb[1])="^" and part(argsb[1],2)=2 then cform:true - ), - - /* case: (x-1)^2/k */ - if opa=DIV_OP and elementp(wrt,setify(listofvars(denom(SA))))#true and atom(num(SA))#true and op(num(SA))="^" and part(num(SA),2)=2 then cform:true, - - /* The sum of somthing */ - if opa="+" then block( - argsa: sublist(args(SA),lambda([ex],elementp(wrt,setify(listofvars(ex))))), - if length(argsa)>1 then - (AnswerNote:"_no_summands",return(true)), - - if length(argsa)<1 then return(true), - - if atom(argsa[1]) then return(true), - - /* case: (x-1)^2 + c*/ - if op(argsa[1])="^" and part(argsa[1],2)=2 then cform:true, - - /* case: k*(x-1)^2 + c*/ - if op(argsa[1])="*" then block([argsb], - argsb: sublist(args(argsa[1]),lambda([ex],elementp(wrt,setify(listofvars(ex))))), - if length(argsb)=1 then - if op(argsb[1])="^" and part(argsb[1],2)=2 then cform:true - ) - ), - - /* Check for algebraic equivalence */ - if cform and ae then - return([true,true,StackAddNote("","ATCompSquare_true"),""]), - - if cform then - return([true,false,StackAddNote("","ATCompSquare_true_not_AlgEquiv"),StackAddFeedback("","ATCompSquare_not_AlgEquiv")]), - - if not(ae) then - return([true,false,StackAddNote("","ATCompSquare_false_not_AlgEquiv"),""]), - - AnswerNote:concat("ATCompSquare_false",AnswerNote), - return([true,false,StackAddNote("",AnswerNote),StackAddFeedback("",AnswerNote)]) - )$ - - - -/*********************/ -/* Calculus question */ -/*********************/ - -/* This function substitutes an "integrationconstant" in ex for v. - If v is a list, this substitutes as many integration constants as possible */ -subst_int_const(ex,v):=block([lv,li,ls], - lv:listofvars(ex), - li:sublist_indices(lv, lambda([ex],is(smismatch("integrationconstant",string(ex))>19) or is(smismatch("%c",string(ex))>2)) ), - if emptyp(li) then return(ex), - /* If we have only one variable v, then use this */ - if not(listp(v)) then return(subst(lv[li[1]]=v,ex)), - ls:map(lambda([n],lv[n]),li), - subst(zip_with("=",ls,v),ex) - )$ - -/* This function strips off any trailing constant of integration from an expression, which is not a number */ -strip_int_const(ex,v):=block([ex2,fargs], - ex2:ex, - if atom(ex) then return(ex), - if op(ex)="+" then - (fargs:sublist(args(ex),lambda([ex2],not(freeof(v,ex2)) or simp_numberp(ex2))), - if length(fargs)=1 then ex2:fargs[1] else ex2:apply("+",fargs)), - return(ex2))$ - -/********************************************************************/ -/* An answer test for integration questions. */ -/* sa is the students' answer, */ -/* sbl is a list consisting of (1) the answer, and (2) the variable */ -/********************************************************************/ -ATInt(sa,sbl) := - block([oldsimp, keepfloat, Validity, RawMark, FeedBack, AnswerNote, var, sb, ret, cont], - oldsimp:simp, simp:false, Validity:true, RawMark:false, FeedBack:"", AnswerNote:"", - keepfloat:true, - - SAA:errcatch(ev(sa, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then - return([false, false, StackAddNote("", "ATInt_STACKERROR_SAns"), ""]), - SBB:errcatch(ev(sbl, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then - return([false, false, StackAddNote("", "ATInt_STACKERROR_TAns"), ""]), - - /* SBL is a list: the teacher's answer, the variable, and whether formative feedback is to be provided. */ - if listp(sbl) then - (var:sbl[2], sb:sbl[1], cont:true) - else - (cont:false, FeedBack:StackAddFeedback("", "ATInt_STACKERROR_LIST"), AnswerNote:StackAddNote("", "ATInt_STACKERROR_LIST")), - ret:[true,RawMark,AnswerNote,FeedBack], /* Once this works remove these variables and define ret in the loops */ - - /* SA should be only an expression. */ - if expressionp(sa)=false then - return([false, false, StackAddNote("", "ATInt_SA_not_expression"), StackAddFeedback("", "ATAlgEquiv_SA_not_expression")]) - else block( - keepfloat:true, - if cont then - ret:Intfun(sa, sb, var) - ), - simp:oldsimp, - return(ret) - )$ - -/* Returns true iff a and b are lists (not necessarily same length) with one or more common elements, false o/w */ -listsoverlap(a, b) :=not(emptyp(intersection(setify(a), setify(b))))$ - -/* Returns true iff a and b are lists (not necessarily same length) and contain the common element v */ -listscontain(a, b, v) := elementp(v,intersection(setify(a), setify(b)))$ - -Intfun(SA, SB, v) := block([val,rawmk,ansnote,fb,ret,ex,SAd,SBd,saa,dd,dc,lSAv,lSBv,mSAv,mSBv,SAConsistentLogs,SAUsedLogAbs,SBUsedLogAbs], - val:true, rawmk:false, fb:"", ansnote:"", debug:false, - ret:[val, rawmk, ansnote, fb], - /* Check if the teacher and student used only log abs. - Teacher must be consistent, otherwise the student doesn't have to be!*/ - SAUsedLogAbs:ATInt_logabs_p(SA,v), - SBUsedLogAbs:ATInt_logabs_p(SB,v), - if debug then print([SA,SB]), - if debug then print([SAUsedLogAbs,SBUsedLogAbs]), - /* This expands out logarithms for constants, e.g. ln(k*|x|) */ - SB:ev(SB, logexpand:super, simp), - if debug then print([SA,SB]), - /* This strips off any trailing constant of integration from the teacher's answer */ - SB:strip_int_const(SB, v), - /* This strips off any trailing constant of integration from the student's answer */ - SAa:strip_int_const(ev(SA, logexpand:super, simp), v), - /* If the teacher has not used logabs, then strip out any logabs from the student's answer. */ - /* Student consistency is a different issue. */ - SAConsistentLogs:ATInt_consistent_logabs_p(SA,v), - if not(SBUsedLogAbs) then ( - SA:subst(STACKLA=log, ATInt_logabs_to_STACKLA(SA)), - SAa:subst(STACKLA=log, ATInt_logabs_to_STACKLA(SAa)) - ), - /* Calculate derivatives */ - SAd:ev(diff(SA,v),simp), - SBd:ev(diff(SB,v),simp), - /* Check for constant of integration - code copied from algebraic_equivalence */ - ex:errcatch(ev(fullratsimp(SA-SB), simp, trigexpand:true, logexpand:super, keepfloat:true)), - if ex=[] then (return([false, false, "ATInt: simplification failed.", StackAddFeedback("", "ATInt_generic", StackDISP(SBd, "d"), StackDISP(v, "i"), StackDISP(SAd, "d"))])), - ex:ex[1], - ex:ev(trigsimp(ex), simp), - ex:ev(trigreduce(ex), simp), - dd:ev(float(ex), simp), - dc:numberp(dd) and dd#0.0, - if debug then print([SAa,SBd]), - if debug then print(ex), - if ev(algebraic_equivalence(SAd,SBd), simp) then - if ex=0 then - (rawmk:false, fb:StackAddFeedback("", "ATInt_const"), ansnote:StackAddNote("", "ATInt_const")) - else if dc then - (rawmk:false, fb:StackAddFeedback("", "ATInt_const_int"), ansnote:StackAddNote("", "ATInt_const_int")) - else if freeof(log, SA) and not(ATIntWeirdConstp(ex)) then - (rawmk:true, ansnote:StackAddNote("", "ATInt_true")) - else if freeof(log, SA) and ATIntWeirdConstp(ex) then - (rawmk:false, fb:StackAddFeedback("", "ATInt_weirdconst"), ansnote:StackAddNote("", "ATInt_weirdconst")) - /* From this point onwards we *have logarithms*. */ - else if ev(algebraic_equivalence(SA, SB), simp) then - (rawmk:false, fb:StackAddFeedback("", "ATInt_const"), ansnote:StackAddNote("", "ATInt_const_equiv")) - else if ev(algebraic_equivalence(SAa, SB), simp) then - (rawmk:true, ansnote:StackAddNote("", "ATInt_true_equiv")) - else if freeof(v,ex) and not(ATIntWeirdConstp(ex)) then - (rawmk:true, ansnote:StackAddNote("", "ATInt_true_differentconst")) - else - (rawmk:false, fb:StackAddFeedback("", "ATInt_EqFormalDiff"), ansnote:StackAddNote("", "ATInt_EqFormalDiff")) - else /* Check for the special cases where the buggy rule is true */ - if ev(algebraic_equivalence(SAa, ev(diff(SBd, v), simp)),simp) and ev(algebraic_equivalence(exp(x), SBd),simp)#true then - (rawmk:false, fb:StackAddFeedback("", "ATInt_diff"), ansnote:StackAddNote("", "ATInt_diff")) - else - (rawmk:false, fb:StackAddFeedback("", "ATInt_generic", StackDISP(SBd, "d"), StackDISP(v, "i"), StackDISP(SAd, "d")), ansnote:StackAddNote("", "ATInt_generic")), - /* Has the student used log(x) vs log(abs(x)) in their answer? */ - if not(SAUsedLogAbs) and SBUsedLogAbs then - (rawmk:false, fb:StackAddFeedback("", "ATInt_logabs"), ansnote:StackAddNote(ansnote, "ATInt_logabs")), - /* Has the student been inconsistent in using log(x) vs log(abs(x)) in their answer? */ - if not(SAConsistentLogs) then - (rawmk:false, fb:StackAddFeedback("", "ATInt_logabs_inconsistent"), ansnote:StackAddNote(ansnote, "ATInt_logabs_inconsistent")), - lSAv:listofvars(SA), - lSAv:listofvars(SA), - lSBv:listofvars(SB), - mSAv:member(v, lSAv), - mSBv:member(v, lSBv), - if not(mSBv) then ( - if mSAv then - ansnote:StackAddNote(ansnote, "ATInt_var_SA_notSB") - else if not(listscontain(lSAv, lSBv, v)) and not(listsoverlap(lSAv, lSBv)) then - ansnote:StackAddNote(ansnote, "ATInt_var_notSASB_SAnceSB") ) /* v not in SA or SB, and no variable common to SA and SB */ - else if not(mSAv) then - if mSBv then - ansnote:StackAddNote(ansnote, "ATInt_var_SB_notSA"), - - ret:[val, rawmk, ansnote, fb], - return(ret) -)$ - -/* This function decides if the constant of integration looks "weird".*/ -ATIntWeirdConstp(ex):=block([l], - l:listofvars(ex), - if length(l)#1 then return(true), - if degree(ex, first(l))#1 then return(true) - else return(false) -)$ - -/* Checks all occurances of v are inside abs, e.g. abs(v) */ -ATInt_var_in_abs_p(ex, v):=block( - if ex=v then return(false), /* v on its own is not inside abs() */ - if atom(ex) then return(true), - if freeof(v,ex) then return(true), - if safe_op(ex) = "abs" then return(true), - apply("and", maplist(lambda([ex2], ATInt_var_in_abs_p(ex2, v)), args(ex))) -)$ - -/* Check if all occurances of the variable v, which are inside a log function, are protected by abs() */ -ATInt_logabs_p(ex, v):=block( - if atom(ex) then return(true), - if safe_op(ex) = "log" then return(apply("and", maplist(lambda([ex2], ATInt_var_in_abs_p(ex2, v)), args(ex)))), - apply("and", maplist(lambda([ex2], ATInt_logabs_p(ex2, v)), args(ex))) -)$ - -/* Transform log(abs(ex)) to a single dummy function STACKLA(ex) - This enables us to strip them out. This will not catch all cases, e.g. log(k*abs(x)) isn't caught here... -*/ -ATInt_logabs_to_STACKLA(ex):=block( - if atom(ex) then return(ex), - if safe_op(ex) = "log" then ( - if atom(first(args(ex))) then - return(ex) - else if safe_op(first(args(ex))) = "abs" then - return(STACKLA(first(args(first(args(ex)))))) - ), - return(apply(op(ex),maplist(ATInt_logabs_to_STACKLA,args(ex)))) -)$ - -/* Has the student been consistent in using log(abs(ex))? */ -/* We need to check for the integration variable, inside logarithm functions. */ -/* We don't want things like log(3) to "look like" a log here. */ -ATInt_consistent_logabs_p_helper(ex,v):=block( - if atom(ex) then return(0), - if safe_op(ex) = "log" and ATInt_var_in_abs_p(ex, v) then return(STACKLOGABS), - if safe_op(ex) = "log" and member(v, listofvars(args(ex))) then return(STACKLOG), - return(apply("+",maplist(lambda([ex1],ATInt_consistent_logabs_p_helper(ex1,v)),args(ex)))) -); - -ATInt_consistent_logabs_p(ex,v):=block([helper], - helper:ev(ATInt_consistent_logabs_p_helper(ex,v),simp), - helper:listofvars(helper), - if member(STACKLOG, helper) and member(STACKLOGABS, helper) then false else true -); - -/********************************************************************/ -/* An answer test for differentiation questions. */ -/* sa is the students' answer, */ -/* sbl is a list consisting of (1) the answer, and (2) the variable */ -/********************************************************************/ -ATDiff(sa,sbl) := - block([old_simp, keepfloat, RawMark, FeedBack, AnswerNote, ret, str, da, db, dd, dc, sb, var, cont, SAA, SBB], - old_simp:simp, simp:true, RawMark:false, FeedBack:"", AnswerNote:"", - keepfloat:true, - - SAA:errcatch(ev(sa, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then return([false,false,StackAddNote("","ATDiff_STACKERROR_SAns"),""]), - SBB:errcatch(ev(sbl, simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then return([false,false,StackAddNote("","ATDiff_STACKERROR_TAns"),""]), - - /* SBL is a list: the teacher's answer, the variable, and whether formative feedback is to be provided. */ - if listp(sbl) then - (var:sbl[2], sb:sbl[1], cont:true) - else - (cont:false, FeedBack:StackAddFeedback("","ATDiff_STACKERROR_LIST"), AnswerNote:StackAddNote("","ATDiff_STACKERROR_LIST")), - ret:[cont, RawMark, AnswerNote, FeedBack], /* In case sbl not list */ - - /* SA should be only an expression. */ - if expressionp(sa)=false then - return([false,false,StackAddNote("","ATDiff_SA_not_expression"),StackAddFeedback("","ATAlgEquiv_SA_not_expression")]) - else block( - keepfloat:true, - if cont then - ret:Difffun(sa,sb,var) - ), - simp:old_simp, - return(ret) - )$ - -Difffun(SA,SB,v) := block([val,rawmk,ansnote,fb,ret,lSAv,lSBv,mSAv,mSBv], - val:true, rawmk:false, fb:"", ansnote:"", - ret:[val,rawmk,ansnote,fb], - if algebraic_equivalence(SA,SB) then - (rawmk:true, ansnote:StackAddNote("","ATDiff_true")) - else - if algebraic_equivalence(diff(SA,v),int(SB,v)) then - (rawmk:false, ansnote:StackAddNote("","ATDiff_int"), fb:StackAddFeedback("","ATDiff_int")) - else ( - lSAv:listofvars(SA), - lSBv:listofvars(SB), - mSAv:member(v,lSAv), - mSBv:member(v,lSBv), - if not(mSBv) then ( - if mSAv then - ansnote:StackAddNote(ansnote,"ATDiff_var_SA_notSB") - else if not(listscontain(lSAv,lSBv,v)) and not(listsoverlap(lSAv,lSBv)) then - ansnote:StackAddNote(ansnote,"ATDiff_var_notSASB_SAnceSB") ) /* not in SA or SB, and no variable common to SA and SB */ - else if not(mSAv) then ( - if mSBv then - ansnote:StackAddNote(ansnote,"ATDiff_var_SB_notSA") ) ), - ret:[val,rawmk,ansnote,fb], - return(ret) - )$ - -/* ****************************************************** */ -/* */ -/* The assess function takes two expressions, ex1 and ex2 */ -/* */ -/* It returns the name of the *strictest* sense in which */ -/* they are considered to be the "same" */ -/* */ -/* ****************************************************** */ - -assess(ex1,ex2):=block([ret], - - SAA:errcatch(ev(SA, simp, nouns)), - if (is(SAA=[STACKERROR]) or is(SAA=[])) then return([false,false,"assess_STACKERROR_SAns",""]), - SBB:errcatch(ev(SBL,simp, nouns)), - if (is(SBB=[STACKERROR]) or is(SBB=[])) then return([false,false,"assess_STACKERROR_TAns",""]), - - ret:ATCASEqual(ex1,ex2), - if ret[2] then return("ATCASEqual"), - - ret:ATEqualComAss(ex1,ex2), - if ret[2] then return("ATEqualComAss"), - - ret:ATAlgEquiv(ex1,ex2), - if ret[2] then return("ATAlgEquiv"), - - ret:ATSubstEquiv(ex1,ex2), - if ret[2] then return("ATSubstEquiv"), - - ret:ATSameType(ex1,ex2), - if ret[2] then return("ATSameType"), - - return("") -)$ - -/* Slight hack to compile these functions and hence suppress warnings. */ -load(linearalgebra); - -/* Stack expects some output */ -stackmaximaversion:2014083000$ -print("[ STACK-Maxima started, library version 2014083000 ]")$ diff --git a/stack/2014083000/maxima/stackreporting.mac b/stack/2014083000/maxima/stackreporting.mac deleted file mode 100644 index 1d7ba43..0000000 --- a/stack/2014083000/maxima/stackreporting.mac +++ /dev/null @@ -1,27 +0,0 @@ -/* ****************************************************** */ -/* */ -/* Reporting functions */ -/* */ -/* ****************************************************** */ - -STACKanalysis(A):=block([l0, l1, l2, l3], - l0:maplist(ineqorder, A), - l1:listify(setify(fullratsimp(l0))), - l2:maplist(lambda([ex], setify(sublist(A, lambda([ex2], second(ATAlgEquiv(ex2,ex)))))), l1), - l3:maplist(lambda([ex], length(sublist(A, lambda([ex2], second(ATAlgEquiv(ex2,ex)))))), l1), - transpose(matrix(l1, l2, l3)) -)$ - -/* This is an example function which takes a list "l" and returns the equivalence classes for the data. */ -/* Any of the other STACK answer test functions can be used here in place of ATAlgEquiv. */ -stack_equiv_classes(l):=block( - equiv_classes(setify(l), lambda([x, y], second(ATAlgEquiv(x, y)))) -); - -/* This need to be implemented in the future. */ -stack_analysis(ex):=block( - print("stack_analysis: this function has not yet been implemented. Please see the maxima code directly for examples of how to analyse data."), - false -)$ - -simp:false; diff --git a/stack/2014083000/maxima/stacktex.lisp b/stack/2014083000/maxima/stacktex.lisp deleted file mode 100644 index 9c89c85..0000000 --- a/stack/2014083000/maxima/stacktex.lisp +++ /dev/null @@ -1,181 +0,0 @@ -;; Customize Maxima's TEX() function. To give better control to the output. -;; Chris Sangwin 27 Sept 2010. -;; Useful files: -;; \Maxima-5.21.1\share\maxima\5.21.1\share\utils\mactex-utilities.lisp -;; \Maxima-5.21.1\share\maxima\5.21.1\src\mactex.lisp - -;; Additional mactex utilities taken from the distributed file -;; mactex-utilities.lisp -;; Based on code by Richard J. Fateman, copyright 1987. -;; Fateman's code was ported to Common Lisp by William -;; Schelter. - -;; If you want LaTeX style quotients, first load mactex and second -;; define tex-mquotient as follows - -(defun tex-mquotient (x l r) - (if (or (null (cddr x)) (cdddr x)) (wna-err (caar x))) - (setq l (tex (cadr x) (append l '("\\frac{")) nil 'mparen 'mparen) - r (tex (caddr x) (list "}{") (append '("}") r) 'mparen 'mparen)) - (append l r)) - -;; Define an explicit multiplication -;;(defprop mtimes "\\times " texsym) -;;(defprop mtimes "\\cdot " texsym) - - -;; patch to tex-prefix to make sin(x) always like sin(x), and not the default sin x. -;; CJS 24 June 2004 - -(defun tex-prefix (x l r) - (tex (cadr x) (append l (texsym (caar x)) '("\\left( ") ) (append '(" \\right)") r) 'mparen 'mparen)) - -;; Fix the problem with -27 being printed -(27) -;; CJS 21 Jan 2009 - -(defprop mminus tex-prefix-unaryminus tex) -;;(defprop mminus tex-prefix tex) -(defprop mminus ("-") texsym) - -(defun tex-prefix-unaryminus (x l r) - (tex (cadr x) (append l (texsym (caar x))) r (caar x) rop)) - - - -;; Display question marks correctly -(defprop &? ("?") texsym) - -;; Allow colour into TeX expressions from Maxima -;; Thanks to andrej.vodopivec@fmf.uni-lj.si Fri Jan 14 09:32:42 2005 - -(defun tex-texcolor (x l r) - (let - ((front (append '("{\\color{") - (list (stripdollar (cadr x))) - '("}"))) - (back (append '("{\\underline{") - (tex (caddr x) nil nil 'mparen 'mparen) - '("}}}")))) - (append l front back r))) - -(defprop $texcolor tex-texcolor tex) - - -(defun tex-texdecorate (x l r) - (let - ((front (append '("{") - (list (stripdollar (cadr x))) - '(""))) - (back (append '("{") - (tex (caddr x) nil nil 'mparen 'mparen) - '("}}")))) - (append l front back r))) - -(defprop $texdecorate tex-texdecorate tex) - -;; Changed log to ln, and other things -;; If changes are made here, then we also need to update arccos.lisp - -(mapc #'tex-setup - '( - (%acos "{\\rm acos}") - (%asin "{\\rm asin}") - (%atan "{\\rm atan}") - - ; Latex's arg(x) is ... ? - (%cos "\\cos ") - (%cosh "\\cosh ") - (%cot "\\cot ") - (%coth "\\coth ") - (%csc "\\csc ") - ; Latex's "deg" is ... ? - (%determinant "\\det ") - (%dim "\\dim ") - (%exp "\\exp ") - (%gcd "\\gcd ") - ; Latex's "hom" is ... ? - (%inf "\\inf ") ; many will prefer "\\infty". Hmmm. - ; Latex's "ker" is ... ? - ; Latex's "lg" is ... ? - ; lim is handled by tex-limit. - ; Latex's "liminf" ... ? - ; Latex's "limsup" ... ? - (%ln "\\ln ") - (%log "\\ln ") - (%max "\\max ") - (%min "\\min ") - ; Latex's "Pr" ... ? - (%sec "\\sec ") - (%sin "\\sin ") - (%sinh "\\sinh ") - ; Latex's "sup" ... ? - (%tan "\\tan ") - (%tanh "\\tanh ") - ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual - ;(%laplace "{\\cal L}") - - ; Maxima built-in functions which do not have corresponding TeX symbols. - - (%asec "{\\rm asec}") - (%acsc "{\\rm acsc}") - (%acot "{\\rm acot}") - - (%sech "{\\rm sech}") - (%csch "{\\rm csch}") - - (%asinh "{\\rm asinh}") - (%acosh "{\\rm acosh}") - (%atanh "{\\rm atanh}") - - (%asech "{\\rm asech}") - (%acsch "{\\rm acsch}") - (%acoth "{\\rm acoth}") - -)) ;; etc - - - -;; Remove un-needed {}s from string output -;; Chris Sangwin, 28/10/2009 - -(defun tex-string (x) - (cond ((equal x "") "") - ((eql (elt x 0) #\\) x) - (t (concatenate 'string "\\mbox{" x "}")))) - - -;; Sort out display on inequalities -;; Chris Sangwin, 21/9/2010 - -(defprop mlessp (" < ") texsym) -(defprop mgreaterp (" > ") texsym) - -;; Change the display of derivatives, at the request of the OU -;; Chris Sangwin, 18/3/2013 - -(defprop %derivative tex-derivative tex) -(defun tex-derivative (x l r) - (tex (if $derivabbrev - (tex-dabbrev x) - (tex-d x '"\\mathrm{d}")) l r lop rop )) - -(defun tex-d(x dsym) ;dsym should be $d or "$\\partial" - ;; format the macsyma derivative form so it looks - ;; sort of like a quotient times the deriva-dand. - (let* - ((arg (cadr x)) ;; the function being differentiated - (difflist (cddr x)) ;; list of derivs e.g. (x 1 y 2) - (ords (odds difflist 0)) ;; e.g. (1 2) - (vars (odds difflist 1)) ;; e.g. (x y) - (numer `((blankmult) ((mexpt) ,dsym ((mplus) ,@ords)) ,arg)) ; d^n numerator - (denom (cons '(blankmult) - (mapcan #'(lambda(b e) - `(,dsym ,(simplifya `((mexpt) ,b ,e) nil))) - vars ords)))) - `((mquotient) ,(simplifya numer nil) ,(simplifya denom nil)) - )) - - -(defprop blankmult tex-infix tex) -(defprop blankmult ("\\, ") texsym) - diff --git a/stack/2014083000/maxima/unittests_load.mac b/stack/2014083000/maxima/unittests_load.mac deleted file mode 100644 index fe125ba..0000000 --- a/stack/2014083000/maxima/unittests_load.mac +++ /dev/null @@ -1,49 +0,0 @@ -;; Author Chris Sangwin -;; University of Birmingham -;; Copyright (C) 2013 Chris Sangwin - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - - -/* This batch file load unit tests for STACK Maxima */ -/* NOTE: we need to run tests with simp:false and simp:true */ - -/* Currently a lot of these tests report a "fail", but without actually failing. */ -/* The testsuite uses the function approx-alike (defined in src/mload.lisp) to check for equality. */ -/* If we want to fix this we'll need to write your own approx-alike function. */ -/* C:\Program Files\Maxima-5.22.1\share\maxima\5.22.1\src */ - -kill(all); -/*load("C:/xampp/htdocs/stack-dev/logfiles/maximalocal.mac")$*/ -LOADDIR:"C:/xampp/data/moodledata/stack/maximalocal.mac"$ -print("Working from: ")$ -print(LOADDIR)$ -load(LOADDIR)$ - -no_fails:0$ all_pass:true$ - -simp:true$ -STT:batch("rtest_assessment_simptrue.mac", test); -STB:batch("rtest_assessment_simpboth.mac", test); - -simp:false$ -SFF:batch("rtest_assessment_simpfalse.mac", test); -SFB:batch("rtest_assessment_simpboth.mac", test); - -print("************ simp is true"); -print(STT); -print(STB); - -print("************ simp is false."); -print(SFF); -print(SFB); - - diff --git a/stack/2017121800/maximalocal.mac.template b/stack/2017121800/maximalocal.mac.template new file mode 100644 index 0000000..d84b9bb --- /dev/null +++ b/stack/2017121800/maximalocal.mac.template @@ -0,0 +1,41 @@ +/* ***********************************************************************/ +/* This file is automatically generated at installation time. */ +/* The purpose is to transfer configuration settings to Maxima. */ +/* Hence, you should not edit this file. Edit your configuration. */ +/* This file is regularly overwritten, so your changes will be lost. */ +/* ***********************************************************************/ + +/* File generated on July 29, 2020, 4:26 pm */ + +/* Add the location to Maxima's search path */ +file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LIB}/###.{lisp}")] , file_search_lisp)$ +file_search_maxima:append( [sconcat("${LOG}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LOG}/###.{lisp}")] , file_search_lisp)$ + +STACK_SETUP(ex):=block( + MAXIMA_VERSION_NUM_EXPECTED:41, + MAXIMA_PLATFORM:"server", + maxima_tempdir:"${TMP}/", + IMAGE_DIR:"${PLOT}/", + PLOT_SIZE:[450,300], + PLOT_TERMINAL:"svg", + PLOT_TERM_OPT:"dynamic font \",11\" linewidth 1.2", + DEL_CMD:"rm", + GNUPLOT_CMD:"gnuplot", + MAXIMA_VERSION_EXPECTED:"5.41.0", + URL_BASE:"!ploturl!", + /* Define units available in STACK. */ + stack_unit_si_prefix_code:[y, z, a, f, p, n, u, m, c, d, da, h, k, M, G, T, P, E, Z, Y], + stack_unit_si_prefix_multiplier:[10^-24, 10^-21, 10^-18, 10^-15, 10^-12, 10^-9, 10^-6, 10^-3, 10^-2, 10^-1, 10, 10^2, 10^3, 10^6, 10^9, 10^12, 10^15, 10^18, 10^21, 10^24], + stack_unit_si_prefix_tex:["\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mu ", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm"], + stack_unit_si_unit_code:[m, l, L, g, s, h, Hz, Bq, cd, N, Pa, cal, Cal, Btu, eV, J, W, A, ohm, C, V, F, S, Wb, T, H, Gy, rem, Sv, lx, mol, M, kat, rad], + stack_unit_si_unit_conversions:[m, m^3/1000, m^3/1000, kg/1000, s, s*3600, 1/s, 1/s, cd, (kg*m)/s^2, kg/(m*s^2), 4.2*J, 4200*J, 1055*J, 1.602177e-19*J, (kg*m^2)/s^2, (kg*m^2)/s^3, A, (kg*m^2)/(s^3*A^2), s*A, (kg*m^2)/(s^3*A), (s^4*A^2)/(kg*m^2), (s^3*A^2)/(kg*m^2), (kg*m^2)/(s^2*A), kg/(s^2*A), (kg*m^2)/(s^2*A^2), m^2/s^2, 0.01*Sv, m^2/s^2, cd/m^2, mol, mol/(m^3/1000), mol/s, rad], + stack_unit_si_unit_tex:["\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\Omega", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm"], + stack_unit_other_unit_code:[min, amu, u, mmHg, bar, cc, gal, mbar, atm, torr, rev, deg, rpm, K, day, year, in, ft, mi], + stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), K, 86400*s, 3.156e7*s, in, 12*in, 5280*12*in], + stack_unit_other_unit_tex:["\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm{{}^}", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm", "\\mathrm"], + true)$ +/* Load the main libraries. */ +/* load("stackmaxima.mac")$ */ + diff --git a/stack/2018030500/maximalocal.mac.template b/stack/2018030500/maximalocal.mac.template new file mode 100644 index 0000000..7eaf253 --- /dev/null +++ b/stack/2018030500/maximalocal.mac.template @@ -0,0 +1,41 @@ +/* ***********************************************************************/ +/* This file is automatically generated at installation time. */ +/* The purpose is to transfer configuration settings to Maxima. */ +/* Hence, you should not edit this file. Edit your configuration. */ +/* This file is regularly overwritten, so your changes will be lost. */ +/* ***********************************************************************/ + +/* File generated on July 29, 2020, 3:10 pm */ + +/* Add the location to Maxima's search path */ +file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LIB}/###.{lisp}")] , file_search_lisp)$ +file_search_maxima:append( [sconcat("${LOG}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LOG}/###.{lisp}")] , file_search_lisp)$ + +STACK_SETUP(ex):=block( + MAXIMA_VERSION_NUM_EXPECTED:41, + MAXIMA_PLATFORM:"server", + maxima_tempdir:"${TMP}/", + IMAGE_DIR:"${PLOT}/", + PLOT_SIZE:[450,300], + PLOT_TERMINAL:"svg", + PLOT_TERM_OPT:"dynamic font \",11\" linewidth 1.2", + DEL_CMD:"rm", + GNUPLOT_CMD:"gnuplot", + MAXIMA_VERSION_EXPECTED:"5.41.0", + URL_BASE:"!ploturl!", + /* Define units available in STACK. */ + stack_unit_si_prefix_code:[y, z, a, f, p, n, u, m, c, d, da, h, k, M, G, T, P, E, Z, Y], + stack_unit_si_prefix_multiplier:[10^-24, 10^-21, 10^-18, 10^-15, 10^-12, 10^-9, 10^-6, 10^-3, 10^-2, 10^-1, 10, 10^2, 10^3, 10^6, 10^9, 10^12, 10^15, 10^18, 10^21, 10^24], + stack_unit_si_prefix_tex:["\\mathrm{y}", "\\mathrm{z}", "\\mathrm{a}", "\\mathrm{f}", "\\mathrm{p}", "\\mathrm{n}", "\\mu ", "\\mathrm{m}", "\\mathrm{c}", "\\mathrm{d}", "\\mathrm{da}", "\\mathrm{h}", "\\mathrm{k}", "\\mathrm{M}", "\\mathrm{G}", "\\mathrm{T}", "\\mathrm{P}", "\\mathrm{E}", "\\mathrm{Z}", "\\mathrm{Y}"], + stack_unit_si_unit_code:[m, l, L, g, s, h, Hz, Bq, cd, N, Pa, cal, Cal, Btu, eV, J, W, A, ohm, C, V, F, S, Wb, T, H, Gy, rem, Sv, lx, mol, M, kat, rad], + stack_unit_si_unit_conversions:[m, m^3/1000, m^3/1000, kg/1000, s, s*3600, 1/s, 1/s, cd, (kg*m)/s^2, kg/(m*s^2), 4.2*J, 4200*J, 1055*J, 1.602177e-19*J, (kg*m^2)/s^2, (kg*m^2)/s^3, A, (kg*m^2)/(s^3*A^2), s*A, (kg*m^2)/(s^3*A), (s^4*A^2)/(kg*m^2), (s^3*A^2)/(kg*m^2), (kg*m^2)/(s^2*A), kg/(s^2*A), (kg*m^2)/(s^2*A^2), m^2/s^2, 0.01*Sv, m^2/s^2, cd/m^2, mol, mol/(m^3/1000), mol/s, rad], + stack_unit_si_unit_tex:["\\mathrm{m}", "\\mathrm{l}", "\\mathrm{L}", "\\mathrm{g}", "\\mathrm{s}", "\\mathrm{h}", "\\mathrm{Hz}", "\\mathrm{Bq}", "\\mathrm{cd}", "\\mathrm{N}", "\\mathrm{Pa}", "\\mathrm{cal}", "\\mathrm{cal}", "\\mathrm{Btu}", "\\mathrm{eV}", "\\mathrm{J}", "\\mathrm{W}", "\\mathrm{A}", "\\Omega", "\\mathrm{C}", "\\mathrm{V}", "\\mathrm{F}", "\\mathrm{S}", "\\mathrm{Wb}", "\\mathrm{T}", "\\mathrm{H}", "\\mathrm{Gy}", "\\mathrm{rem}", "\\mathrm{Sv}", "\\mathrm{lx}", "\\mathrm{mol}", "\\mathrm{M}", "\\mathrm{kat}", "\\mathrm{rad}"], + stack_unit_other_unit_code:[min, amu, u, mmHg, bar, cc, gal, mbar, atm, torr, rev, deg, rpm, K, day, year, in, ft, mi], + stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), K, 86400*s, 3.156e7*s, in, 12*in, 5280*12*in], + stack_unit_other_unit_tex:["\\mathrm{min}", "\\mathrm{amu}", "\\mathrm{u}", "\\mathrm{mmHg}", "\\mathrm{bar}", "\\mathrm{cc}", "\\mathrm{gal}", "\\mathrm{mbar}", "\\mathrm{atm}", "\\mathrm{torr}", "\\mathrm{rev}", "\\mathrm{{}^{o}}", "\\mathrm{rpm}", "\\mathrm{K}", "\\mathrm{day}", "\\mathrm{year}", "\\mathrm{in}", "\\mathrm{ft}", "\\mathrm{mi}"], + true)$ +/* Load the main libraries. */ +/* load("stackmaxima.mac")$ */ + diff --git a/stack/2018080600/maximalocal.mac.template b/stack/2018080600/maximalocal.mac.template new file mode 100644 index 0000000..7eaf253 --- /dev/null +++ b/stack/2018080600/maximalocal.mac.template @@ -0,0 +1,41 @@ +/* ***********************************************************************/ +/* This file is automatically generated at installation time. */ +/* The purpose is to transfer configuration settings to Maxima. */ +/* Hence, you should not edit this file. Edit your configuration. */ +/* This file is regularly overwritten, so your changes will be lost. */ +/* ***********************************************************************/ + +/* File generated on July 29, 2020, 3:10 pm */ + +/* Add the location to Maxima's search path */ +file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LIB}/###.{lisp}")] , file_search_lisp)$ +file_search_maxima:append( [sconcat("${LOG}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LOG}/###.{lisp}")] , file_search_lisp)$ + +STACK_SETUP(ex):=block( + MAXIMA_VERSION_NUM_EXPECTED:41, + MAXIMA_PLATFORM:"server", + maxima_tempdir:"${TMP}/", + IMAGE_DIR:"${PLOT}/", + PLOT_SIZE:[450,300], + PLOT_TERMINAL:"svg", + PLOT_TERM_OPT:"dynamic font \",11\" linewidth 1.2", + DEL_CMD:"rm", + GNUPLOT_CMD:"gnuplot", + MAXIMA_VERSION_EXPECTED:"5.41.0", + URL_BASE:"!ploturl!", + /* Define units available in STACK. */ + stack_unit_si_prefix_code:[y, z, a, f, p, n, u, m, c, d, da, h, k, M, G, T, P, E, Z, Y], + stack_unit_si_prefix_multiplier:[10^-24, 10^-21, 10^-18, 10^-15, 10^-12, 10^-9, 10^-6, 10^-3, 10^-2, 10^-1, 10, 10^2, 10^3, 10^6, 10^9, 10^12, 10^15, 10^18, 10^21, 10^24], + stack_unit_si_prefix_tex:["\\mathrm{y}", "\\mathrm{z}", "\\mathrm{a}", "\\mathrm{f}", "\\mathrm{p}", "\\mathrm{n}", "\\mu ", "\\mathrm{m}", "\\mathrm{c}", "\\mathrm{d}", "\\mathrm{da}", "\\mathrm{h}", "\\mathrm{k}", "\\mathrm{M}", "\\mathrm{G}", "\\mathrm{T}", "\\mathrm{P}", "\\mathrm{E}", "\\mathrm{Z}", "\\mathrm{Y}"], + stack_unit_si_unit_code:[m, l, L, g, s, h, Hz, Bq, cd, N, Pa, cal, Cal, Btu, eV, J, W, A, ohm, C, V, F, S, Wb, T, H, Gy, rem, Sv, lx, mol, M, kat, rad], + stack_unit_si_unit_conversions:[m, m^3/1000, m^3/1000, kg/1000, s, s*3600, 1/s, 1/s, cd, (kg*m)/s^2, kg/(m*s^2), 4.2*J, 4200*J, 1055*J, 1.602177e-19*J, (kg*m^2)/s^2, (kg*m^2)/s^3, A, (kg*m^2)/(s^3*A^2), s*A, (kg*m^2)/(s^3*A), (s^4*A^2)/(kg*m^2), (s^3*A^2)/(kg*m^2), (kg*m^2)/(s^2*A), kg/(s^2*A), (kg*m^2)/(s^2*A^2), m^2/s^2, 0.01*Sv, m^2/s^2, cd/m^2, mol, mol/(m^3/1000), mol/s, rad], + stack_unit_si_unit_tex:["\\mathrm{m}", "\\mathrm{l}", "\\mathrm{L}", "\\mathrm{g}", "\\mathrm{s}", "\\mathrm{h}", "\\mathrm{Hz}", "\\mathrm{Bq}", "\\mathrm{cd}", "\\mathrm{N}", "\\mathrm{Pa}", "\\mathrm{cal}", "\\mathrm{cal}", "\\mathrm{Btu}", "\\mathrm{eV}", "\\mathrm{J}", "\\mathrm{W}", "\\mathrm{A}", "\\Omega", "\\mathrm{C}", "\\mathrm{V}", "\\mathrm{F}", "\\mathrm{S}", "\\mathrm{Wb}", "\\mathrm{T}", "\\mathrm{H}", "\\mathrm{Gy}", "\\mathrm{rem}", "\\mathrm{Sv}", "\\mathrm{lx}", "\\mathrm{mol}", "\\mathrm{M}", "\\mathrm{kat}", "\\mathrm{rad}"], + stack_unit_other_unit_code:[min, amu, u, mmHg, bar, cc, gal, mbar, atm, torr, rev, deg, rpm, K, day, year, in, ft, mi], + stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), K, 86400*s, 3.156e7*s, in, 12*in, 5280*12*in], + stack_unit_other_unit_tex:["\\mathrm{min}", "\\mathrm{amu}", "\\mathrm{u}", "\\mathrm{mmHg}", "\\mathrm{bar}", "\\mathrm{cc}", "\\mathrm{gal}", "\\mathrm{mbar}", "\\mathrm{atm}", "\\mathrm{torr}", "\\mathrm{rev}", "\\mathrm{{}^{o}}", "\\mathrm{rpm}", "\\mathrm{K}", "\\mathrm{day}", "\\mathrm{year}", "\\mathrm{in}", "\\mathrm{ft}", "\\mathrm{mi}"], + true)$ +/* Load the main libraries. */ +/* load("stackmaxima.mac")$ */ + diff --git a/stack/2019090200/maximalocal.mac.template b/stack/2019090200/maximalocal.mac.template new file mode 100644 index 0000000..eef7029 --- /dev/null +++ b/stack/2019090200/maximalocal.mac.template @@ -0,0 +1,41 @@ +/* ***********************************************************************/ +/* This file is automatically generated at installation time. */ +/* The purpose is to transfer configuration settings to Maxima. */ +/* Hence, you should not edit this file. Edit your configuration. */ +/* This file is regularly overwritten, so your changes will be lost. */ +/* ***********************************************************************/ + +/* File generated on July 29, 2020, 3:17 pm */ + +/* Add the location to Maxima's search path */ +file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LIB}/###.{lisp}")] , file_search_lisp)$ +file_search_maxima:append( [sconcat("${LOG}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LOG}/###.{lisp}")] , file_search_lisp)$ + +STACK_SETUP(ex):=block( + MAXIMA_VERSION_NUM_EXPECTED:41, + MAXIMA_PLATFORM:"server", + maxima_tempdir:"${TMP}/", + IMAGE_DIR:"${PLOT}/", + PLOT_SIZE:[450,300], + PLOT_TERMINAL:"svg", + PLOT_TERM_OPT:"dynamic font \",11\" linewidth 1.2", + DEL_CMD:"rm", + GNUPLOT_CMD:"gnuplot", + MAXIMA_VERSION_EXPECTED:"5.41.0", + URL_BASE:"!ploturl!", + /* Define units available in STACK. */ + stack_unit_si_prefix_code:[y, z, a, f, p, n, u, m, c, d, da, h, k, M, G, T, P, E, Z, Y], + stack_unit_si_prefix_multiplier:[10^-24, 10^-21, 10^-18, 10^-15, 10^-12, 10^-9, 10^-6, 10^-3, 10^-2, 10^-1, 10, 10^2, 10^3, 10^6, 10^9, 10^12, 10^15, 10^18, 10^21, 10^24], + stack_unit_si_prefix_tex:["\\mathrm{y}", "\\mathrm{z}", "\\mathrm{a}", "\\mathrm{f}", "\\mathrm{p}", "\\mathrm{n}", "\\mu ", "\\mathrm{m}", "\\mathrm{c}", "\\mathrm{d}", "\\mathrm{da}", "\\mathrm{h}", "\\mathrm{k}", "\\mathrm{M}", "\\mathrm{G}", "\\mathrm{T}", "\\mathrm{P}", "\\mathrm{E}", "\\mathrm{Z}", "\\mathrm{Y}"], + stack_unit_si_unit_code:[m, l, L, g, s, h, Hz, Bq, cd, N, Pa, cal, Cal, Btu, eV, J, W, A, ohm, C, V, F, S, Wb, T, H, Gy, rem, Sv, lx, mol, M, kat, rad, K], + stack_unit_si_unit_conversions:[m, m^3/1000, m^3/1000, kg/1000, s, s*3600, 1/s, 1/s, cd, (kg*m)/s^2, kg/(m*s^2), 4.2*J, 4200*J, 1055*J, 1.602177e-19*J, (kg*m^2)/s^2, (kg*m^2)/s^3, A, (kg*m^2)/(s^3*A^2), s*A, (kg*m^2)/(s^3*A), (s^4*A^2)/(kg*m^2), (s^3*A^2)/(kg*m^2), (kg*m^2)/(s^2*A), kg/(s^2*A), (kg*m^2)/(s^2*A^2), m^2/s^2, 0.01*Sv, m^2/s^2, cd/m^2, mol, mol/(m^3/1000), mol/s, rad, K], + stack_unit_si_unit_tex:["\\mathrm{m}", "\\mathrm{l}", "\\mathrm{L}", "\\mathrm{g}", "\\mathrm{s}", "\\mathrm{h}", "\\mathrm{Hz}", "\\mathrm{Bq}", "\\mathrm{cd}", "\\mathrm{N}", "\\mathrm{Pa}", "\\mathrm{cal}", "\\mathrm{cal}", "\\mathrm{Btu}", "\\mathrm{eV}", "\\mathrm{J}", "\\mathrm{W}", "\\mathrm{A}", "\\Omega", "\\mathrm{C}", "\\mathrm{V}", "\\mathrm{F}", "\\mathrm{S}", "\\mathrm{Wb}", "\\mathrm{T}", "\\mathrm{H}", "\\mathrm{Gy}", "\\mathrm{rem}", "\\mathrm{Sv}", "\\mathrm{lx}", "\\mathrm{mol}", "\\mathrm{M}", "\\mathrm{kat}", "\\mathrm{rad}", "\\mathrm{K}"], + stack_unit_other_unit_code:[min, amu, u, mmHg, bar, cc, gal, mbar, atm, torr, rev, deg, rpm, day, year, in, ft, mi], + stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), 86400*s, 3.156e7*s, in, 12*in, 5280*12*in], + stack_unit_other_unit_tex:["\\mathrm{min}", "\\mathrm{amu}", "\\mathrm{u}", "\\mathrm{mmHg}", "\\mathrm{bar}", "\\mathrm{cc}", "\\mathrm{gal}", "\\mathrm{mbar}", "\\mathrm{atm}", "\\mathrm{torr}", "\\mathrm{rev}", "\\mathrm{{}^{o}}", "\\mathrm{rpm}", "\\mathrm{day}", "\\mathrm{year}", "\\mathrm{in}", "\\mathrm{ft}", "\\mathrm{mi}"], + true)$ +/* Load the main libraries. */ +/* load("stackmaxima.mac")$ */ + diff --git a/stack/2020042000/maximalocal.mac.template b/stack/2020042000/maximalocal.mac.template new file mode 100644 index 0000000..adb51cd --- /dev/null +++ b/stack/2020042000/maximalocal.mac.template @@ -0,0 +1,41 @@ +/* ***********************************************************************/ +/* This file is automatically generated at installation time. */ +/* The purpose is to transfer configuration settings to Maxima. */ +/* Hence, you should not edit this file. Edit your configuration. */ +/* This file is regularly overwritten, so your changes will be lost. */ +/* ***********************************************************************/ + +/* File generated on July 29, 2020, 3:22 pm */ + +/* Add the location to Maxima's search path */ +file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LIB}/###.{lisp}")] , file_search_lisp)$ +file_search_maxima:append( [sconcat("${LOG}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LOG}/###.{lisp}")] , file_search_lisp)$ + +STACK_SETUP(ex):=block( + MAXIMA_VERSION_NUM_EXPECTED:41, + MAXIMA_PLATFORM:"server", + maxima_tempdir:"${TMP}/", + IMAGE_DIR:"${PLOT}/", + PLOT_SIZE:[450,300], + PLOT_TERMINAL:"svg", + PLOT_TERM_OPT:"dynamic font \",11\" linewidth 1.2", + DEL_CMD:"rm", + GNUPLOT_CMD:"gnuplot", + MAXIMA_VERSION_EXPECTED:"5.41.0", + URL_BASE:"!ploturl!", + /* Define units available in STACK. */ + stack_unit_si_prefix_code:[y, z, a, f, p, n, u, m, c, d, da, h, k, M, G, T, P, E, Z, Y], + stack_unit_si_prefix_multiplier:[10^-24, 10^-21, 10^-18, 10^-15, 10^-12, 10^-9, 10^-6, 10^-3, 10^-2, 10^-1, 10, 10^2, 10^3, 10^6, 10^9, 10^12, 10^15, 10^18, 10^21, 10^24], + stack_unit_si_prefix_tex:["\\mathrm{y}", "\\mathrm{z}", "\\mathrm{a}", "\\mathrm{f}", "\\mathrm{p}", "\\mathrm{n}", "\\mu ", "\\mathrm{m}", "\\mathrm{c}", "\\mathrm{d}", "\\mathrm{da}", "\\mathrm{h}", "\\mathrm{k}", "\\mathrm{M}", "\\mathrm{G}", "\\mathrm{T}", "\\mathrm{P}", "\\mathrm{E}", "\\mathrm{Z}", "\\mathrm{Y}"], + stack_unit_si_unit_code:[m, l, L, g, s, h, Hz, Bq, cd, N, Pa, cal, Cal, Btu, eV, J, W, A, ohm, C, V, F, S, Wb, T, H, Gy, rem, Sv, lx, mol, M, kat, rad, K, VA], + stack_unit_si_unit_conversions:[m, m^3/1000, m^3/1000, kg/1000, s, s*3600, 1/s, 1/s, cd, (kg*m)/s^2, kg/(m*s^2), 4.2*J, 4200*J, 1055*J, 1.602177e-19*J, (kg*m^2)/s^2, (kg*m^2)/s^3, A, (kg*m^2)/(s^3*A^2), s*A, (kg*m^2)/(s^3*A), (s^4*A^2)/(kg*m^2), (s^3*A^2)/(kg*m^2), (kg*m^2)/(s^2*A), kg/(s^2*A), (kg*m^2)/(s^2*A^2), m^2/s^2, 0.01*Sv, m^2/s^2, cd/m^2, mol, mol/(m^3/1000), mol/s, rad, K, (kg*m^2)/(s^3)], + stack_unit_si_unit_tex:["\\mathrm{m}", "\\mathrm{l}", "\\mathrm{L}", "\\mathrm{g}", "\\mathrm{s}", "\\mathrm{h}", "\\mathrm{Hz}", "\\mathrm{Bq}", "\\mathrm{cd}", "\\mathrm{N}", "\\mathrm{Pa}", "\\mathrm{cal}", "\\mathrm{cal}", "\\mathrm{Btu}", "\\mathrm{eV}", "\\mathrm{J}", "\\mathrm{W}", "\\mathrm{A}", "\\Omega", "\\mathrm{C}", "\\mathrm{V}", "\\mathrm{F}", "\\mathrm{S}", "\\mathrm{Wb}", "\\mathrm{T}", "\\mathrm{H}", "\\mathrm{Gy}", "\\mathrm{rem}", "\\mathrm{Sv}", "\\mathrm{lx}", "\\mathrm{mol}", "\\mathrm{M}", "\\mathrm{kat}", "\\mathrm{rad}", "\\mathrm{K}", "\\mathrm{VA}"], + stack_unit_other_unit_code:[min, amu, u, mmHg, bar, cc, gal, mbar, atm, torr, rev, deg, rpm, day, year, in, ft, mi], + stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), 86400*s, 3.156e7*s, in, 12*in, 5280*12*in], + stack_unit_other_unit_tex:["\\mathrm{min}", "\\mathrm{amu}", "\\mathrm{u}", "\\mathrm{mmHg}", "\\mathrm{bar}", "\\mathrm{cc}", "\\mathrm{gal}", "\\mathrm{mbar}", "\\mathrm{atm}", "\\mathrm{torr}", "\\mathrm{rev}", "\\mathrm{{}^{o}}", "\\mathrm{rpm}", "\\mathrm{day}", "\\mathrm{year}", "\\mathrm{in}", "\\mathrm{ft}", "\\mathrm{mi}"], + true)$ +/* Load the main libraries. */ +/* load("stackmaxima.mac")$ */ + diff --git a/stack/2020052700/maximalocal.mac.template b/stack/2020052700/maximalocal.mac.template new file mode 100644 index 0000000..f49be37 --- /dev/null +++ b/stack/2020052700/maximalocal.mac.template @@ -0,0 +1,41 @@ +/* ***********************************************************************/ +/* This file is automatically generated at installation time. */ +/* The purpose is to transfer configuration settings to Maxima. */ +/* Hence, you should not edit this file. Edit your configuration. */ +/* This file is regularly overwritten, so your changes will be lost. */ +/* ***********************************************************************/ + +/* File generated on July 29, 2020, 3:31 pm */ + +/* Add the location to Maxima's search path */ +file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LIB}/###.{lisp}")] , file_search_lisp)$ +file_search_maxima:append( [sconcat("${LOG}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LOG}/###.{lisp}")] , file_search_lisp)$ + +STACK_SETUP(ex):=block( + MAXIMA_VERSION_NUM_EXPECTED:41, + MAXIMA_PLATFORM:"server", + maxima_tempdir:"${TMP}/", + IMAGE_DIR:"${PLOT}/", + PLOT_SIZE:[450,300], + PLOT_TERMINAL:"svg", + PLOT_TERM_OPT:"dynamic font \",11\" linewidth 1.2", + DEL_CMD:"rm", + GNUPLOT_CMD:"gnuplot", + MAXIMA_VERSION_EXPECTED:"5.41.0", + URL_BASE:"!ploturl!", + /* Define units available in STACK. */ + stack_unit_si_prefix_code:[y, z, a, f, p, n, u, m, c, d, da, h, k, M, G, T, P, E, Z, Y], + stack_unit_si_prefix_multiplier:[10^-24, 10^-21, 10^-18, 10^-15, 10^-12, 10^-9, 10^-6, 10^-3, 10^-2, 10^-1, 10, 10^2, 10^3, 10^6, 10^9, 10^12, 10^15, 10^18, 10^21, 10^24], + stack_unit_si_prefix_tex:["\\mathrm{y}", "\\mathrm{z}", "\\mathrm{a}", "\\mathrm{f}", "\\mathrm{p}", "\\mathrm{n}", "\\mu ", "\\mathrm{m}", "\\mathrm{c}", "\\mathrm{d}", "\\mathrm{da}", "\\mathrm{h}", "\\mathrm{k}", "\\mathrm{M}", "\\mathrm{G}", "\\mathrm{T}", "\\mathrm{P}", "\\mathrm{E}", "\\mathrm{Z}", "\\mathrm{Y}"], + stack_unit_si_unit_code:[m, l, L, g, s, h, Hz, Bq, cd, N, Pa, cal, Cal, Btu, eV, J, W, A, ohm, C, V, F, S, Wb, T, H, Gy, rem, Sv, lx, mol, M, kat, rad, K, VA], + stack_unit_si_unit_conversions:[m, m^3/1000, m^3/1000, kg/1000, s, s*3600, 1/s, 1/s, cd, (kg*m)/s^2, kg/(m*s^2), 4.2*J, 4200*J, 1055*J, 1.602177e-19*J, (kg*m^2)/s^2, (kg*m^2)/s^3, A, (kg*m^2)/(s^3*A^2), s*A, (kg*m^2)/(s^3*A), (s^4*A^2)/(kg*m^2), (s^3*A^2)/(kg*m^2), (kg*m^2)/(s^2*A), kg/(s^2*A), (kg*m^2)/(s^2*A^2), m^2/s^2, 0.01*Sv, m^2/s^2, cd/m^2, mol, mol/(m^3/1000), mol/s, rad, K, (kg*m^2)/(s^3)], + stack_unit_si_unit_tex:["\\mathrm{m}", "\\mathrm{l}", "\\mathrm{L}", "\\mathrm{g}", "\\mathrm{s}", "\\mathrm{h}", "\\mathrm{Hz}", "\\mathrm{Bq}", "\\mathrm{cd}", "\\mathrm{N}", "\\mathrm{Pa}", "\\mathrm{cal}", "\\mathrm{cal}", "\\mathrm{Btu}", "\\mathrm{eV}", "\\mathrm{J}", "\\mathrm{W}", "\\mathrm{A}", "\\Omega", "\\mathrm{C}", "\\mathrm{V}", "\\mathrm{F}", "\\mathrm{S}", "\\mathrm{Wb}", "\\mathrm{T}", "\\mathrm{H}", "\\mathrm{Gy}", "\\mathrm{rem}", "\\mathrm{Sv}", "\\mathrm{lx}", "\\mathrm{mol}", "\\mathrm{M}", "\\mathrm{kat}", "\\mathrm{rad}", "\\mathrm{K}", "\\mathrm{VA}"], + stack_unit_other_unit_code:[min, amu, u, mmHg, bar, cc, gal, mbar, atm, torr, rev, deg, rpm, day, year, in, ft, mi], + stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), 86400*s, 3.156e7*s, in, 12*in, 5280*12*in], + stack_unit_other_unit_tex:["\\mathrm{min}", "\\mathrm{amu}", "\\mathrm{u}", "\\mathrm{mmHg}", "\\mathrm{bar}", "\\mathrm{cc}", "\\mathrm{gal}", "\\mathrm{mbar}", "\\mathrm{atm}", "\\mathrm{torr}", "\\mathrm{rev}", "\\mathrm{{}^{o}}", "\\mathrm{rpm}", "\\mathrm{day}", "\\mathrm{year}", "\\mathrm{in}", "\\mathrm{ft}", "\\mathrm{mi}"], + true)$ +/* Load the main libraries. */ +/* load("stackmaxima.mac")$ */ + diff --git a/stack/2020061000/maximalocal.mac.template b/stack/2020061000/maximalocal.mac.template new file mode 100644 index 0000000..f64d864 --- /dev/null +++ b/stack/2020061000/maximalocal.mac.template @@ -0,0 +1,41 @@ +/* ***********************************************************************/ +/* This file is automatically generated at installation time. */ +/* The purpose is to transfer configuration settings to Maxima. */ +/* Hence, you should not edit this file. Edit your configuration. */ +/* This file is regularly overwritten, so your changes will be lost. */ +/* ***********************************************************************/ + +/* File generated on July 29, 2020, 3:36 pm */ + +/* Add the location to Maxima's search path */ +file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LIB}/###.{lisp}")] , file_search_lisp)$ +file_search_maxima:append( [sconcat("${LOG}/###.{mac,mc}")] , file_search_maxima)$ +file_search_lisp:append( [sconcat("${LOG}/###.{lisp}")] , file_search_lisp)$ + +STACK_SETUP(ex):=block( + MAXIMA_VERSION_NUM_EXPECTED:41, + MAXIMA_PLATFORM:"server", + maxima_tempdir:"${TMP}/", + IMAGE_DIR:"${PLOT}/", + PLOT_SIZE:[450,300], + PLOT_TERMINAL:"svg", + PLOT_TERM_OPT:"dynamic font \",11\" linewidth 1.2", + DEL_CMD:"rm", + GNUPLOT_CMD:"gnuplot", + MAXIMA_VERSION_EXPECTED:"5.41.0", + URL_BASE:"!ploturl!", + /* Define units available in STACK. */ + stack_unit_si_prefix_code:[y, z, a, f, p, n, u, m, c, d, da, h, k, M, G, T, P, E, Z, Y], + stack_unit_si_prefix_multiplier:[10^-24, 10^-21, 10^-18, 10^-15, 10^-12, 10^-9, 10^-6, 10^-3, 10^-2, 10^-1, 10, 10^2, 10^3, 10^6, 10^9, 10^12, 10^15, 10^18, 10^21, 10^24], + stack_unit_si_prefix_tex:["\\mathrm{y}", "\\mathrm{z}", "\\mathrm{a}", "\\mathrm{f}", "\\mathrm{p}", "\\mathrm{n}", "\\mu ", "\\mathrm{m}", "\\mathrm{c}", "\\mathrm{d}", "\\mathrm{da}", "\\mathrm{h}", "\\mathrm{k}", "\\mathrm{M}", "\\mathrm{G}", "\\mathrm{T}", "\\mathrm{P}", "\\mathrm{E}", "\\mathrm{Z}", "\\mathrm{Y}"], + stack_unit_si_unit_code:[m, l, L, g, s, h, Hz, Bq, cd, N, Pa, cal, Cal, Btu, eV, J, W, A, ohm, C, V, F, S, Wb, T, H, Gy, rem, Sv, lx, mol, M, kat, rad, K, VA], + stack_unit_si_unit_conversions:[m, m^3/1000, m^3/1000, kg/1000, s, s*3600, 1/s, 1/s, cd, (kg*m)/s^2, kg/(m*s^2), 4.2*J, 4200*J, 1055*J, 1.602177e-19*J, (kg*m^2)/s^2, (kg*m^2)/s^3, A, (kg*m^2)/(s^3*A^2), s*A, (kg*m^2)/(s^3*A), (s^4*A^2)/(kg*m^2), (s^3*A^2)/(kg*m^2), (kg*m^2)/(s^2*A), kg/(s^2*A), (kg*m^2)/(s^2*A^2), m^2/s^2, 0.01*Sv, m^2/s^2, cd/m^2, mol, mol/(m^3/1000), mol/s, rad, K, (kg*m^2)/(s^3)], + stack_unit_si_unit_tex:["\\mathrm{m}", "\\mathrm{l}", "\\mathrm{L}", "\\mathrm{g}", "\\mathrm{s}", "\\mathrm{h}", "\\mathrm{Hz}", "\\mathrm{Bq}", "\\mathrm{cd}", "\\mathrm{N}", "\\mathrm{Pa}", "\\mathrm{cal}", "\\mathrm{cal}", "\\mathrm{Btu}", "\\mathrm{eV}", "\\mathrm{J}", "\\mathrm{W}", "\\mathrm{A}", "\\Omega", "\\mathrm{C}", "\\mathrm{V}", "\\mathrm{F}", "\\mathrm{S}", "\\mathrm{Wb}", "\\mathrm{T}", "\\mathrm{H}", "\\mathrm{Gy}", "\\mathrm{rem}", "\\mathrm{Sv}", "\\mathrm{lx}", "\\mathrm{mol}", "\\mathrm{M}", "\\mathrm{kat}", "\\mathrm{rad}", "\\mathrm{K}", "\\mathrm{VA}"], + stack_unit_other_unit_code:[min, amu, u, mmHg, bar, cc, gal, mbar, atm, torr, rev, deg, rpm, day, year, in, ft, mi], + stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), 86400*s, 3.156e7*s, in, 12*in, 5280*12*in], + stack_unit_other_unit_tex:["\\mathrm{min}", "\\mathrm{amu}", "\\mathrm{u}", "\\mathrm{mmHg}", "\\mathrm{bar}", "\\mathrm{cc}", "\\mathrm{gal}", "\\mathrm{mbar}", "\\mathrm{atm}", "\\mathrm{torr}", "\\mathrm{rev}", "\\mathrm{{}^{o}}", "\\mathrm{rpm}", "\\mathrm{day}", "\\mathrm{year}", "\\mathrm{in}", "\\mathrm{ft}", "\\mathrm{mi}"], + true)$ +/* Load the main libraries. */ +/* load("stackmaxima.mac")$ */ + diff --git a/assets/maximalocal.mac.template b/stack/2020070100/maximalocal.mac.template similarity index 97% rename from assets/maximalocal.mac.template rename to stack/2020070100/maximalocal.mac.template index 02d176f..6ddeaf4 100644 --- a/assets/maximalocal.mac.template +++ b/stack/2020070100/maximalocal.mac.template @@ -5,7 +5,7 @@ /* This file is regularly overwritten, so your changes will be lost. */ /* ***********************************************************************/ -/* File generated on July 14, 2020, 10:04 am */ +/* File generated on July 29, 2020, 3:56 pm */ /* Add the location to Maxima's search path */ file_search_maxima:append( [sconcat("${LIB}/###.{mac,mc}")] , file_search_maxima)$ @@ -36,6 +36,6 @@ STACK_SETUP(ex):=block( stack_unit_other_unit_conversions:[s*60, amu, amu, 133.322387415*Pa, 10^5*Pa, 10^4*m^2, m^3*10^(-6), 3.785*l, 10^2*Pa, 101325*Pa, 101325/760*Pa, 2*pi*rad, pi*rad/180, pi*rad/(30*s), 149597870700*m, 1.660539040E-27*kg, Np, B, dB, 86400*s, 3.156e7*s, hp, in, 12*in, 36*in, 5280*12*in, lb], stack_unit_other_unit_tex:["\\mathrm{min}", "\\mathrm{amu}", "\\mathrm{u}", "\\mathrm{mmHg}", "\\mathrm{bar}", "\\mathrm{ha}", "\\mathrm{cc}", "\\mathrm{gal}", "\\mathrm{mbar}", "\\mathrm{atm}", "\\mathrm{torr}", "\\mathrm{rev}", "\\mathrm{{}^{o}}", "\\mathrm{rpm}", "\\mathrm{au}", "\\mathrm{Da}", "\\mathrm{Np}", "\\mathrm{B}", "\\mathrm{dB}", "\\mathrm{day}", "\\mathrm{year}", "\\mathrm{hp}", "\\mathrm{in}", "\\mathrm{ft}", "\\mathrm{yd}", "\\mathrm{mi}", "\\mathrm{lb}"], true)$ -/* Load the main libraries */ +/* Load the main libraries. */ /* load("stackmaxima.mac")$ */ -- GitLab