Update of /cvsroot/aimmath/AIM/WEB-INF/maple/aim
In directory sc8-pr-cvs1:/tmp/cvs-serv28505
Modified Files:
Tag: develop_2_1
Int.mpl Util1.mpl
Log Message:
Util1.mpl: added
- NiceFrac ... for fine-tuning of fractions
- simplifyabs ... simplifies the result of diff(ln(abs(u)), u) to 1/u
Int.mpl: some improvements (using the above) + added some new features
for checking for integration constants with indefinite integrals. - GG
Index: Int.mpl
===================================================================
RCS file: /cvsroot/aimmath/AIM/WEB-INF/maple/aim/Int.mpl,v
retrieving revision 1.2.2.1
retrieving revision 1.2.2.2
diff -C2 -d -r1.2.2.1 -r1.2.2.2
*** Int.mpl 10 Jul 2003 20:10:03 -0000 1.2.2.1
--- Int.mpl 19 Jul 2003 17:37:34 -0000 1.2.2.2
***************
*** 119,131 ****
@a['AnswerNote']@. The function returns a list of the form
@[mark,feedback,note]@.
",
proc(a,
Q::`aim/Int/Problem/Indefinite`,
#optional
! val_::numeric
)
! local q,argtype,ans,diffans,rightans,integrand,var,
! feedback,note,mark,t,val,u,base,expt,newvar,ns;
if type(a,`aim/Question/Attempt`) then
--- 119,140 ----
@a['AnswerNote']@. The function returns a list of the form
@[mark,feedback,note]@.
+ By default, the student's answer need not have an integration constant,
+ but to insist that one be included pass as 4th argument
+ the optional argument @intconst_@ with value @\"insist\"@, and in this case
+ the student is penalised (by multiplying by a factor of 0.9).
+ To suggest there should be an integration constant but not penalise
+ pass the optional argument @intconst_@ with value @\"alert\"@.
+ In order for there to be a 4th argument one is obliged, in this case,
+ to pass the 3rd argument @val_@.
",
proc(a,
Q::`aim/Int/Problem/Indefinite`,
#optional
! val_::numeric,
! intconst_::string
)
! local q,argtype,ans,diffans,rightans,integrand,var,subsvars,varstr,
! feedback,note,mark,t,val,intconst,u,base,expt,newvar,ns;
if type(a,`aim/Question/Attempt`) then
***************
*** 140,144 ****
fi;
! val := `if`(nargs > 2, val_,1);
q := `aim/Int/Problem/Split`(Q);
--- 149,159 ----
fi;
! if nargs >= 4 then
! val, intconst := val_, intconst_;
! elif nargs = 3 then
! val, intconst := val_, "ignore";
! else
! val, intconst := 1, "ignore";
! fi;
q := `aim/Int/Problem/Split`(Q);
***************
*** 150,155 ****
note := "";
! diffans :=
! traperror(simplify(diff(ans,var),assume = positive));
if diffans = lasterror then
--- 165,170 ----
note := "";
! diffans := traperror(simplify(simplifyabs(diff(ans,var))));
! t := `aim/CheckVars`(ans, integrand);
if diffans = lasterror then
***************
*** 159,163 ****
mark := 0;
! elif traperror(simplify(diffans - integrand)) = 0 then
feedback := "";
note := "";
--- 174,188 ----
mark := 0;
! # Sometimes it's best to compare the integrals and sometimes it's best to
! # differentiate and see that it gives back the integrand
! # ... if a student transforms the integrand in some way and then
! # integrates, as is typical of some trig. integrals, differentiation and
! # comparing with the integrand can sometimes fail no matter how much help
! # you give Maple. simplifyabs here takes care of examples like int(1/u, u)
! # where the student gives the answer: ln(abs(u)) + C
! elif traperror(simplify(simplifyabs(diff(simplify(ans - rightans))))) = 0 or
! traperror(expand(simplify(diffans - integrand))) = 0 or
! traperror(expand(simplify(diffans - integrand), assume = positive)) = 0
! then
feedback := "";
note := "";
***************
*** 171,176 ****
__("In fact, the derivative of your answer is:"),
"\n",
! sprintf("<latex>\\[\\frac{d}{d%a}\\left[%s\\right] = %s\\]</latex>",
! var,LaTeX(ans),LaTeX(diff(ans,var))),
"\n",
__("so you must have done something wrong."),
--- 196,201 ----
__("In fact, the derivative of your answer is:"),
"\n",
! sprintf("<latex>\\[\\frac{d}{d%a}\\bigl(%s\\bigr) = %s\\]</latex>",
! var,LaTeX(ans),LaTeX(simplifyabs(diff(ans,var)))),
"\n",
__("so you must have done something wrong."),
***************
*** 180,198 ****
mark := 0;
! t := `aim/CheckVars`(ans,Q);
!
! if t['Extra'] <> [] then
feedback :=
feedback,
! __("Your answer involves the following variable(s) that do not occur in the question or the right answer:"),
! " <font color='red'><tt>",
! `Util/CommaJoin`(op(t['Extra'])),
! "</tt></font>\n<br/>\n",
! __("Note that variable names are case-sensitive; you should not enter <font color='green'><tt>A</tt></font> for <font color='green'><tt>a</tt></font> or vice-versa."),
! "<br/><br/>\n";
! note := __("extra vars");
! if ({op(t['Extra'])} intersect {"u","v","w","U","V","W"}) <> {} then
feedback :=
! feedback,__("#Explain integration backsubstitution"),"\n<br/>\n";
fi;
elif type([integrand],[`^`]) then
--- 205,240 ----
mark := 0;
! if t['Missing'] = [] and nops(t['Extra']) > 1 then
feedback :=
feedback,
! __("Your answer seems to include at least one superfluous integration constant, one is enough!");
! fi;
!
! if t['Missing'] <> [] then
! if t['Extra'] <> [] then
feedback :=
! feedback,
! __("Your answer involves the following variable(s) that do not occur in the integrand:"),
! " <font color='red'><tt>",
! `Util/CommaJoin`(op(t['Extra'])),
! "</tt></font>\n<br/>\n",
! __("Note that variable names are case-sensitive; you should not enter <font color='green'><tt>A</tt></font> for <font color='green'><tt>a</tt></font> or vice-versa. One of the extra variables could be intended as the integration constant but where is the original variable of integration?"),
! "<br/><br/>\n";
! note := __("extra vars");
! if ({op(t['Extra'])} intersect {"u","v","w","U","V","W"}) <> {} then
! feedback :=
! feedback,__("#Explain integration backsubstitution"),"\n<br/>\n";
! fi;
! #The following is a possible alternative for the preceding if ... fi
! #subsvars := {op(t['Extra'])} intersect {"u","v","w","U","V","W"};
! #if subsvars <> {} then
! # varstr := convert(var, string);
! #feedback :=
! # feedback, "It looks as if you made a substitution ", subsvars[1],
! # " = f(", varstr, ") for some function f. ",
! # "Your final answer should be expressed in terms of the original ",
! # "integration variable by substituting f(", varstr, ") for ",
! # subsvars[1], "\n<br/>\n";
! #fi;
fi;
elif type([integrand],[`^`]) then
***************
*** 219,222 ****
--- 261,283 ----
fi;
+ if intconst <> "ignore" and nops(t['Extra']) < 1 then
+ if member("C", t['Correct']) then
+ # strange choice of integration variable!!
+ feedback := feedback,
+ __("You neglected to include an integration constant.");
+ else
+ feedback := feedback,
+ __("You neglected to include an integration constant, i.e. you should have included, e.g.: + C.");
+ fi;
+ if intconst = "insist" then
+ mark := mark * 0.9;
+ else
+ feedback := feedback,
+ __("There was no penalty for omitting it.");
+ fi;
+ feedback := feedback, "\n<br>\n";
+ note := note, __("no integration constant");
+ fi;
+
feedback := cat(feedback);
note := cat(note);
***************
*** 268,271 ****
--- 329,336 ----
feedback := "";
note := "";
+ elif `aim/TestSymbolic`(ans,-q['RightAnswer']) then
+ mark := 0;
+ feedback := __("Possibly you evaluated the limits in the wrong order.");
+ note := __("Reversed limits");
else
mark := 0;
***************
*** 310,326 ****
`Package/Assign`(
`aim/DefInt/ShowSubs`,
! "It is assumed that @Q@ is an indefinite integration problem, and
that @F@ is a solution of the corresponding indefinite problem.
The output is a LaTeX string enclosed in a <latex> tag,
! expressing something like this:
<pre><font color='green'>
4
! / | 3 | 4 | 3 | | 3 |
! | 2 | x | | 4 | | 2 | 64 8 56
! | x dx = | ---- | = | -- | - | -- | = -- - - = --
! | | 3 | | 3 | | 3 | 3 3 3
! / | | x=2 | | | |
2
--- 375,410 ----
`Package/Assign`(
+ `aim/DefInt/NiceInt`,
+ "Given @Q@, a definite integration problem, returns
+ a LaTeX string for the integration problem that has its
+ limits set more nicely and with a little whitespace before
+ the d@x@, where @x@ is the integration variable
+ ",
+ proc(Q::`aim/Int/Problem/Definite`,F)
+ local q, a, b;
+ q := `aim/Int/Problem/Split`(Q);
+ a, b := op( q['Limits'] );
+ cat( "\\int_{", NiceFrac(a, 1, "textstyle"), "}",
+ "^{", NiceFrac(b, 1, "textstyle"), "} ",
+ LaTeX( op(1, q['Integral']) ), " d", LaTeX( q['Variable'] ) );
+ end
+ ):
+
+ ######################################################################
+
+ `Package/Assign`(
`aim/DefInt/ShowSubs`,
! "It is assumed that @Q@ is a definite integration problem, and
that @F@ is a solution of the corresponding indefinite problem.
The output is a LaTeX string enclosed in a <latex> tag,
! expressing something like this, except on multiple lines:
<pre><font color='green'>
4
! / | 3 | 4 / 3 \\ / 3 \\
! | 2 | x | | 4 | | 2 | 64 8 56
! | x dx = | ---- | = | -- | - | -- | = -- - - = --
! | | 3 | | 3 | | 3 | 3 3 3
! / | | x=2 \\ / \\ /
2
***************
*** 328,353 ****
",
proc(Q::`aim/Int/Problem/Definite`,F)
! local q,limits,a,b,x,Fa,Fb,L0,L1,L2,L3,s;
q := `aim/Int/Problem/Split`(Q);
! limits := q['Limits'];
! a := op(1,limits);
! b := op(2,limits);
x := q['Variable'];
Fa := limit(F,x=a);
Fb := limit(F,x=b);
! L0 := LaTeX(q['Integral']);
! L1 :=
! cat("\\left[ ", LaTeX(F), "\\right]_{",LaTeX(a),"}^{",LaTeX(b),"}");
! L2 :=
! cat("\\left( ", LaTeX(Fb), "\\right) - \\left(", LaTeX(Fa), "\\right)");
L3 := LaTeX(Fb - Fa);
! s := cat(L0," = ",L1," = ",L2," = ",L3);
# The next line tests whether Fb - Fa is visibly equal to
--- 412,441 ----
",
proc(Q::`aim/Int/Problem/Definite`,F)
! local q,limits,a,b,x,Fa,Fb,L0,L1,L2,L3,LaTeXF,s;
q := `aim/Int/Problem/Split`(Q);
! a, b := op( q['Limits'] );
x := q['Variable'];
Fa := limit(F,x=a);
Fb := limit(F,x=b);
! limits := cat("_{", NiceFrac(a, 1, "textstyle"), "}",
! "^{", NiceFrac(b, 1, "textstyle"), "}");
! L0 := cat( "\\int", limits, " ",
! LaTeX( op(1, q['Integral']) ), " d", LaTeX(x) );
! LaTeXF := LaTeX(F);
! L1 := `if`( evalb( SearchText("frac", LaTeXF) > 0 ),
! cat("\\left[ ", LaTeXF, " \\right]", limits),
! cat("\\bigl[ ", LaTeXF, " \\bigr]", limits) );
!
! L2 := cat( "\\left(", LaTeX(Fb), "\\right) - ",
! "\\left(", LaTeX(Fa), "\\right)");
L3 := LaTeX(Fb - Fa);
! s := cat(L0, " &= ", L1, "\\\\ &= ", L2, "\\\\ &= ", L3);
# The next line tests whether Fb - Fa is visibly equal to
***************
*** 355,362 ****
# simplification, provided that the question is correct.
if (Fb - Fa <> q['RightAnswer']) then
! s := cat(s," = ",LaTeX(q['RightAnswer']));
fi;
! RETURN(cat("<latex>\\[ ",s," \\]</latex>\n"));
end
):
--- 443,450 ----
# simplification, provided that the question is correct.
if (Fb - Fa <> q['RightAnswer']) then
! s := cat(s,"\\\\ &= ", LaTeX(q['RightAnswer']));
fi;
! RETURN(cat("<latex>\\begin{eqnarray*} ",s," \\end{eqnarray*}</latex>\n"));
end
):
Index: Util1.mpl
===================================================================
RCS file: /cvsroot/aimmath/AIM/WEB-INF/maple/aim/Attic/Util1.mpl,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -C2 -d -r1.1.2.1 -r1.1.2.2
*** Util1.mpl 9 Jul 2003 09:59:48 -0000 1.1.2.1
--- Util1.mpl 19 Jul 2003 17:37:34 -0000 1.1.2.2
***************
*** 8,12 ****
Package("aim/Util1","
This package provides some extra utility functions initially created
! as they were needed by or were useful with the #`aim/Trig`# package.
"
):
--- 8,13 ----
Package("aim/Util1","
This package provides some extra utility functions initially created
! as they were needed by or were useful with packages such as the
! #`aim/Trig`# package.
"
):
***************
*** 148,151 ****
--- 149,248 ----
s_ := cat(s_[1 .. pos - 1], s_[posn .. posb - 1], "/", s_[posb .. -1]);
od;
+ end
+ ):
+
+ `Package/Assign`(
+ NiceFrac::string,
+ "Return a nicely formatted rendition of the fraction @n@/@d@ as a
+ LaTeX string. It accepts the following optional arguments
+ <dl>
+ <dt>@\"term\"@</dt>
+ <dd>if present, @n@/@d@ is treated as a term in a larger expression,
+ i.e. if @n@/@d@ = 0 then an empty string is returned or otherwise
+ the operational sign (+ or -) is prepended;</dd>
+ <dt>@\"coef\"@ (or @\"coeff\"@)</dt>
+ <dd>if present, @n@/@d@ is treated as the coefficient of a term,
+ i.e. if @n@/@d@ = 1 or -1 then only an operational sign is returned
+ (+, in the former case, or - otherwise); in any case, as with
+ @\"term\"@ an operational sign is prepended;</dd>
+ <dt>@\"lcoef\"@ (or @\"lcoeff\"@)</dt>
+ <dd>if present, @n@/@d@ is treated as the coefficient of a leading term,
+ i.e. if @n@/@d@ = -1 then only the operational sign - is returned,
+ and if @n@/@d@ = 1 a null string is returned; in any case, an
+ operational sign is prepended only if @n@/@d@ is negative;</dd>
+ <dt>@\"nocancel\"@</dt>
+ <dd>if present, @n@/@d@ is not cancelled to lowest terms;</dd>
+ <dt>@\"textstyle\"@</dt>
+ <dd>if present, @n@/@d@ is formatted in textstyle, i.e. using / between
+ numerator and denominator
+ (by default, @n@/@d@ is formatted in displaystyle, i.e. in
+ @\\frac{..}{..}@ form).
+ </dl>",
+ proc(n, d)
+ local x, n_, d_, sign_, term, coef, lcoef, nocancel, textstyle;
+ if nargs = 1 or type(args[2], string) then
+ d_ := 1;
+ else
+ d_ := d;
+ fi;
+ term := member("term", [args]);
+ coef := member("coef", [args]) or member("coeff", [args]);
+ lcoef := member("lcoef", [args]) or member("lcoeff", [args]);
+ nocancel := member("nocancel", [args]);
+ textstyle := member("textstyle", [args]);
+
+ x := n/d_;
+ sign_ := `if`(evalb( convert(signum(x), string)[1] = "-" ),
+ "-", `if`(evalb(term or coef), "+", ""));
+ if sign_ = "-" then
+ x := -x;
+ fi;
+ if term or coef then
+ sign_ := cat(sign_, " ");
+ fi;
+
+ if not nocancel and term and x = 0 then
+ return "";
+ elif not nocancel and (coef or lcoef) and x = 1 then
+ return sign_;
+ elif not nocancel and denom(x) = 1 then
+ return cat(sign_, LaTeX(x));
+ else
+ if nocancel then
+ n_ := `if`(evalb( signum(n) = -1 ), -n, n);
+ d_ := `if`(evalb( signum(d_) = -1 ), -d_, d_);
+ else
+ n_, d_ := numer(x), denom(x);
+ fi;
+ if textstyle then
+ return cat(sign_, LaTeX(n_), "/",
+ `if`(evalb(nops(d_) = 1), "", "("),
+ LaTeX(d_),
+ `if`(evalb(nops(d_) = 1), "", ")"));
+ else
+ return cat(sign_, "\\frac{", LaTeX(n_), "}{", LaTeX(d_), "}");
+ fi;
+ fi;
+ end
+ ):
+
+ `Package/Assign`(
+ `simplifyabs`::algebraic,
+ "Returns @e@ with any subexpression pairs of form @abs(1, u)@, @abs(u)@
+ replaced by @u@. These typically turn up when differentiating expressions
+ that contain absolute values, e.g. @diff(ln(abs(u)),u)@ gives
+ @abs(1,u)/abs(u)@ which #`simplifyabs`# simplifies to @1/u@. It is used
+ in #`aim/Int/Test`#.",
+ proc(e::algebraic)
+ local e_, absfns, x, u;
+ e_ := e;
+ absfns := selectfun(e_, abs);
+ for x in select(x -> evalb(nops(x) = 2), absfns) do
+ u := op(2, x);
+ if member(abs(x), absfns) then
+ e_ := subs( abs(1, u) = 1, abs(u) = u, e_ );
+ fi;
+ od;
+ return e_;
end
):
|