7
$\begingroup$

Edit I have made some progress on this problem, which is given below the question.

I use the Moodle course management system for much of my teaching, and the CMS comes with a tool for creating on-line quizzes. A quiz question can take the form of a "calculated question type" which allows for variables to be used in the question and the answer will be calculated based on a formula involving those variables.

The problem is, the calculated question type has a very limited set of functions that can be used to create formulas . An example question might be?

Calculate the mean of {a}, {b}, and {c}.

Where the variables are indicated by alphanumeric symboles within curly braces. Since there is no mean() or average() function, I am forced to enter the following in the answer block:

({a}+{b}+{c})/3

For a trivial problem such as this one, I can manage the answer block; however, if I were to ask for something like the StandardDeviation, the equation quickly becomes burdensome.

I'd like to use Mathematica to create the appropriate form of the function to be put into the answer block.

Ideally, I'd like a MoodleForm[expr] that will take a valid Mathematica expression and convert it into a valid Moodle answer expression (or state that it doesn't know how to make the conversion:

MoodleForm[a+b+c] -> {a} + {b} + {c}
MoodleForm[Mean[{a,b,c}] -> ({a} + {b} + {c})/3
MoodleForm[ListPlot[{a,b,c}] -> "I can't do that, BoB"

Sadly, I'm stuck at the very beginning. If I make the assumption that a, b and c are all undefined in the current Mathematica context, I thought I could do something like this to separate out Symbols that are in the "System`" context.

expr1 = a + b + c;
expr1 /. x_Symbol /; Context[x] == "Global`" :> {x}

Clearly, I need to be thinking about this problem in a different way, and I welcome any suggestions on how to proceed.


Progress

My 'inspiration' for this approach is based on the results of TreeForm[Mean[{a,b,c}]]

enter image description here

I thought that if I could create lists with a function as the first element and the arguments as the remaining elements, I might be able to get the desired formatting. Prepare for some ugly code:

Clear[mdSimplifier];
mdSimplifier[expr_] := Module[{out},
  (* Assume we always deal with Reals, sorry Mathematicians*)
  out = expr /. {Conjugate[x_] :> x};
  N@out
  ]
Clear[mdLeveler];
mdLeveler[expr_] := Module[{},
  If[Depth[#] == 1, #, Level[#, {1}, Heads -> True]] &@expr
  ]
Clear[mdOperate];
mdOperate[expr_List] := Module[{out, hd, rst},
  out = N /@ expr;
  (* If the first element of expr is a Symbol and none of the rest \
are lists *)
  If[And @@ Flatten[{
      Head@First@expr == Symbol,
      (List =!= #) & /@ (Rest@expr)}],
   hd = First@expr;
   rst = Rest@expr;
   Switch[hd,
    Times, ToString[hd @@ rst],
    Power, 
    "pow(" <> ToString[rst[[1]]] <> "," <> ToString[N@rst[[2]]] <> 
     ")"],
   expr]
  ]
Clear[mdPrettyPrint];
mdPrettyPrint[expr_String] := Module[{out},
  out = StringReplace[expr,
    "md" ~~ x : DigitCharacter :> "{md" ~~ x ~~ "}"
    ]
  ]

I've created several functions to help compartmentalize the problem. Here is how I implement the solution for expr = StandardDeviation[{md1,md2,md3}]

mdSimplifier[expr] (* Gets rid of fractions and makes an assumption of Real values *)
mdLeveler[%] (* Returns a Function/arguments list if possible *)
out = mdLeveler /@ % (* See Point 1 below *)
out[[3]] = mdOperate[out[[3]]] (* See Point 2 below *)
mdPrettyPrint@mdOperate[out]

"0.408248 pow({md1} (2. {md1} - 1. {md2} - 1. {md3}) + {md2} (-1. \ {md1} + 2. {md2} - 1. {md3}) + {md3} (-1. {md1} - 1. {md2} + 2. \ {md3}),0.5)"

With a little more tweaking, this string generates the desired output when I use it in the Moodle CMS, which for reference is:

0.408248 * pow({md1} * (2. * {md1} - {md2} - {md3}) + {md2} * (- {md1} + 2. * {md2} - {md3}) + {md3} * (- {md1} - {md2} + 2. * {md3}),0.5)

The issues now are:

  • Point 1 - How do I apply mdLeveler so that it will dig into the expression so that I don't have to apply it multiple times manually?
  • Point 2 - mdOperate suffers from the same problem as does mdLeveler.
  • Point 3 - The Moodle CMS wants explicit multiplication symbols, and I don't know if it is possible to add them automatically.
$\endgroup$
  • $\begingroup$ One quick thought: the output should be a String so you can copy it into a text field of the CMS. Also: maybe it's easier if you choose your variable names according to some pattern, e.g., moodle[a], moodle[b], etc. $\endgroup$ – Jens Jan 10 '15 at 1:42
  • $\begingroup$ @Jens, the pattern-containing variable name is an excellent idea that I hadn't thought of. Thanks. $\endgroup$ – bobthechemist Jan 10 '15 at 1:48
  • $\begingroup$ @bobthechemist is it possible to have CDFs in moodle and get info passed back and forth? $\endgroup$ – Mike Honeychurch Feb 1 '15 at 23:49
  • $\begingroup$ @MikeHoneychurch I've been able to embed CDFs in Moodle without too much difficulty (HTML scrubbing sometimes gets in the way), but I've not been able to get more sophisticated integration. I started looking in to whether or not Enterprise CDF might allow for it, but our school decided to stop paying for the Mathematica license. sigh. $\endgroup$ – bobthechemist Feb 2 '15 at 0:34
  • $\begingroup$ @bobthechemist thanks. At the very least you would need enterprise CDFs I would think ...although you can import from HTML addresses in free CDF I think (would would allow REST based communication). $\endgroup$ – Mike Honeychurch Feb 2 '15 at 0:42
3
$\begingroup$

Maybe the simplest method is CForm with small string postprocessing

moodleForm[expr_] := StringReplace[#, {"power" -> "pow", 
       "md(" ~~ Shortest@x__ ~~ ")" :> "{" ~~ x ~~ "}"}] &@
    ToLowerCase@ToString[#, CForm] &@Simplify[expr, Assumptions -> _md ∈ Reals]

StandardDeviation[{md[a], md[b], md[c]}] // moodleForm

(*sqrt(pow({a},2) + pow({b},2) - {b}*{c} + pow({c},2) - {a}*({b} + {c}))/sqrt(3)*)
$\endgroup$
  • $\begingroup$ It never occurred to me that Moodle was using a c-type format. This solution works brilliantly. $\endgroup$ – bobthechemist Jan 13 '15 at 21:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.