
\documentclass[11pt]{article}

\usepackage{indentfirst}
\usepackage{url}
\usepackage[utf8]{inputenc}

\RequirePackage{amsmath}

% \VignetteIndexEntry{grade Package Tutorial}

\begin{document}

\title{grade Package Tutorial}
\author{Leif Johnson}
\maketitle

\section{Purpose and Motivation}
\subsection{Motivation}
This package came about because of work I was doing with Moodle
\url{http://www.moodle.org}.  Specifically I made a Moodle question
type plugin that allows {\it R} to be integrated directly into Moodle
questions.  In brief, the Moodle server sends the question to a remote
server for processing.  This server does stuff to the question, and
can process chunks of it however it pleases.  I have a server doing
this with {\it R}.

Each Moodle question has a collection of answers with associated
feedback and grades.  When a student submits an answer to a Moodle
question, Moodle iterates through the answers to find a match.  The
student then gets the appropriate feedback and grade for that
question.  The Moodle question type can grade single value numerical
answers, but it can't do anything more complicated than that.

My solution was to build in a {\it remote grading} option into the
question type.  If {\it remote grading} is enabled, the Moodle server
sends the student's answer back to the remote server for grading.
This raises issues of text processing and 'answer' matching.  This is
what the {\it grade} package provides.
\subsection{The Problem}
We want to be able to grade questions from within the question type,
with minimal amount of work from the question writer.  A simple example of a 
question would be:\\

\noindent {\it Question:} Given that $<data>$ follows a normal
distribution with standard deviation $<sdev>$, find a $95\%$ confidence
interval for the mean.

\noindent {\it answer:} $grade.interval( x.bar + s.dev * qnorm(0.975)
* c(-1,1), studentans)$\\

So the remote server needs to evaluate each possible answer and return
a binary true/false decision back to Moodle.  This involves
calculating the correct answer, converting the student's answer from
{\it text} to the appropriate form, and deciding if they
match.  {\it grade} provides functions to do this.
\section{Usage}
Usage is intended to be very simple, and hopefully it is.  Each
grading function follows the same basic format:
\[grade.function(correctans, studentans)\] 
\noindent The grading function returns {\it TRUE} if {\it studentans} is correct,
and {\it FALSE} otherwise.

\noindent {\it correctans} is the 'correct' answer.  {\it studentans} is the
student answer.  Although you are not required to use them in that
order, it is a good idea.  Functions typically enforce stricter
requirements on {\it correctans}.  E.g. {\it grade.interval}
requires that {\it correctans} have length 2 and errors if it does
not.  {\it grade.interval} does not error if {\it studentans} does
not have length 2, though the answer will be incorrect.

There are 5 options in common as well:
\begin{itemize}
\item {\it tolerance} Either a numeric or a string representing a
  numeric (NOT INF or NA).  Usage varies by grading function, but is
  typically a component wise tolerance.
\item {\it useeval} {\it TRUE/FALSE}.  Defaults to {\it TRUE}.  If
  {\it TRUE} text elements are evaluated using {\it eval}.  If
  {\it FALSE} text elements are coerced with {\it as.numeric}.  
\item {\it usena} {\it TRUE/FALSE}.  Defaults to {\it FALSE}.  If
  {\it TRUE}, {\it NA} is an accepted value, if {\it FALSE}
  {\it NA} is not considered to be valid.
\item {\it useinf} {\it TRUE/FALSE}.  Defaults to {\it FALSE}.  If
  {\it TRUE}, {\it Inf} and {\it -Inf} are accepted values.  If
  {\it FALSE}, {\it Inf} and {\it -Inf} are not considered to be
  valid.
\item {\it quiet} {\it TRUE/FALSE}.  Defaults to {\it TRUE}.  If
  {\it TRUE}, functions output as little extra information as
  possible.  If {\it FALSE} there are more warning messages.  Can be
  use full for debugging or tracing failures.
\end{itemize}
\subsection{Simple Examples}
First some intervals.  Note the usage of 'usena', and 'useinf'.
<<intervals.ex1>>=
library(grade)
x <- c(1,2)
grade.interval(x, "[1,2]")
grade.interval(x, "[1,2.02]")
grade.interval(x, "[1,2.02]", tolerance=.03)

grade.interval("[NA, 1]", c(NA, 1), usena=T) # usena=T not allowed in grade.interval
grade.interval(c(1,Inf), c(1,Inf))
grade.interval(c(1,Inf), c(1,Inf), useinf=T)
@ 
To grade sets there are {\it grade.set} and {\it grade.orderedset}, the 
only difference is that {\it grade.orderedset} requires the sets to be in the 
same order.
<<<sets.ex1>>=
set1 <- "[1,2,3,5]"
set2 <- "[5,3,2,1]"
grade.orderedset(set1, set2)
grade.set(set1, set2)
set3 <- c(NA, Inf, pi)
grade.orderedset(set3, set3)
grade.orderedset(set3, set3, usena=T, useinf=T)
@ There is a function for discrete probability distributions as well.
It can be used to verify that a student's answer could be a discrete
probability dist.
<<<discrete.ex1>>=
grade.discreteprobability(NULL, c(0, 1/2, 1/2, 0), checkcorrect=FALSE)
grade.discreteprobability(NULL, c(-1, 1/2, 1/2, 1), checkcorrect=FALSE)
@ 
And to check against a target distribution, order is enforced if
{\it ordered=TRUE}, and not enforced if {\it ordered=FALSE}:
<<<discrete.ex2>>=
correct <- c(0, 1/2, 1/4, 1/4)
sans <- "[0, 1/4, 1/4, 1/2]"
grade.discreteprobability(correct, sans)
grade.discreteprobability(correct, sans, ordered=T)
@ 
Lastly, we have a function to check if a number is negative, and one to 
compare a single value.
<<<neg.num.ex1>>=
grade.negative(NULL, -1)
grade.negative(NULL, -Inf)
grade.negative(NULL, -Inf, useinf=T)

grade.number(1, 1)
grade.number(3.141, "pi", tolerance=.002)
@ 
\subsection{ Parsing Input}
There are 4 functions involved in parsing input, {\it grade.isscalar},
{\it grade.parse}, {\it grade.parsechunk} and {\it grade.parseset}.
Generally, you will just want to use {\it grade.parse}.  These
functions return a vector of values if all checks are passed, {\it NULL} 
otherwise.
<<<parse.ex1>>=
grade.parse("[1, 2, 3]")
grade.parse("NA")
grade.parse("NA", usena=T)
grade.parse("[-Inf, Inf]")
grade.parse("[-Inf, Inf]", useinf=T)
@
Note that you can pass R objects in as well.  These need to conform
to whatever requirements you pass to the parse function:
<<<parse.ex2>>=
grade.parse(c(1,2,3))
grade.parse(NA)
grade.parse(c(-Inf, Inf), useinf=T)
@ 
Checks are made with the {\it grade.isscalar} function:
<<<isscalar.ex1>>=
grade.isscalar(c(1,2))
grade.isscalar(Inf, useinf=T)
@ 
\subsection{eval vs as.numeric}
Using {\it eval} to parse input that is coming from random sources can be a 
problem, but the grade.parse functions {\bf will not eval text containing 
 parenthesis or assignment operators}.  It is unlikely that anything 
malicious can slip through.
<<evalrm.ex1>>=
x <- NULL
grade.parse("x <- 1")
x
grade.parse("rm(list=ls())")
ls()
eval(parse(text="rm(list=ls())"))
ls()
@ 
Using {\it eval} should generally be safe.  It does have a significant 
advantage over {\it as.numeric}:
<<<evalvsnum.ex1>>=
grade.parse("1")
grade.parse("1", useeval=F)
grade.parse("pi")
grade.parse("pi", useeval=F)
grade.parse("1/2")
grade.parse("1/2", useeval=F)
@ 
I recommend that you use {\it eval}, which is why it's the default.
\end{document}
