5.4. Questions and Question Database (question.rsl)
(* define the question database and its operations *)
module Question;
from Test import Test;
export QuestionDB, Question, TestQuestion, AnsweredQuestion, GradedQuestion, QuestionText, Type, Class,
LastUsed, Keywords, Author, Time, Difficulty, AutoGrade, CorrectAnswer, QuestionNumber, Response,
Points, PointsEarned, Feedback;
object QuestionDB is
components: Question*;
description: (*
A QuestionDB is the highest level structure containing any number of questions.
There are two kinds of databases, a local copy and a server copy. When the
user first creates their local copy, it will become a replica of the
server QuestionDB. After that, each QuestionDB remains separate, with operations
available to edit each individualy.
*);
end QuestionDB;
object Question is
components: type:Type and class:Class and time:Time and difficulty:Difficulty and lastused:LastUsed and
keywords:Keywords and graphiclist:Graphic* and
autograde:AutoGrade and questiontext:QuestionText and correctanswer:CorrectAnswer and author:Author;
description: (*
A Question is the generic definition for the types of questions stored
in a Test. Type determines what type of question (T/F, Multiple choice,
Fill-in-the-blank, Matching, Essay, Code). The Class component is used to describe
the general subject matter of the Question. The Time component is an approximate
time required to complete the Question. The Difficulty component is a
user defined approximation of the difficulty of the particular Question.
The LastUsed component holds the date of when the question was last used on
any exam. The Keywords component contains a list of words describing the
subject matter of the Question. The Graphic component holds any number of graphics
associated with the Question. The AutoGrade component is a boolean expression denoting
whether or not the Question can be graded automatically. CorrectAnswer contains the correct
answer to the question (for the autograder).
*(subject to change)*
*);
end Question;
object Type is string;
object Class is string;
object Time is integer;
object Difficulty is integer;
object LastUsed is string;
object Keywords is string;
object Graphic;
object AutoGrade is boolean;
object QuestionText is string;
object CorrectAnswer is string;
object Author is string;
object TestQuestion inherits from Question
components: questionnumber:QuestionNumber, points:Points;
description: (*
QuestionNumber describes the position of the question within a Test.
The Points component is used to hold the value of the Question.
be stored when the Question is saved into a Database, but will only be used
when the Question is saved into a Test.
*);
end TestQuestion;
object QuestionNumber is integer;
object Points is integer;
object AnsweredQuestion inherits from TestQuestion
components: response:Response;
description: (*
Response contains the student's choice of answer to the question.
*);
end AnsweredQuestion;
object Response is string;
object GradedQuestion inherits from AnsweredQuestion
components: pointsearned:PointsEarned, feedback:Feedback;
description: (*
PointsEarned is used to mark how many points the student has earned for this
question (set by autograder).
Feedback contains a professors input back to the student regarding their response.
*);
end GradedQuestion;
object PointsEarned is integer;
object Feedback is string;
object LocalDB is QuestionDB;
object SharedDB is QuestionDB;
(* begin operations *)
operation AddQuestionToLocalDB is
inputs: ldb:LocalDB, q:Question;
outputs: ldb':LocalDB;
description: (*
Add the given question to the LocalDB. The properties
of the question such as the questiontext, type, class
time, difficulty, keywords, and correct answer must not
all be the same as an existing question in the LocalDB.
*);
precondition:
(*
* There is no question in the local database with the same
* properties as the input question, q.
*)
(not (exists (q' in ldb) q'.questiontext = q.questiontext))
and
(not (exists (q' in ldb) q'.type = q.type))
and
(not (exists (q' in ldb) q'.class = q.class))
and
(not (exists (q' in ldb) q'.time = q.time))
and
(not (exists (q' in ldb) q'.difficulty = q.difficulty))
and
(not (exists (q' in ldb) q'.keywords = q.keywords))
and
(not (exists (q' in ldb) q'.correctanswer = q.correctanswer))
and
(not (exists (q' in ldb) q'.author = q.author));
postcondition:
(*
* A question is in the database if and only if it is the new
* question to be added or it is in the input database.
*)
forall (q':Question)
(q' in ldb') iff ((q' = q) or (q' in ldb));
end AddQuestionToLocalDB;
operation RemoveQuestionFromLocalDB is
inputs: ldb:LocalDB, q:Question;
outputs: ldb':LocalDB;
description:(*
Delete the given question from the given local database.
The given question must already be in the input local
database. The question to be deleted from the local
database must match the input question in all properties.
*);
precondition:
(*
* The given Question is in the given LocalDB
*)
q in ldb;
postcondition:
(*
* The question is in the output database if and only if it is not
* the existing record to be deleted and it is in the input db.
*)
(forall (q':Question)
(q' in ldb') iff ((q' != q) and (q' in ldb)));
end RemoveQuestionFromLocalDB;
operation ModifyQuestionInLocalDB is
inputs: ldb:LocalDB, old_q:Question, new_q:Question;
outputs: ldb':LocalDB;
description:(*
Change the given old question to the given new question.
The old and new questions must not be the same. The old question
must already be in the input database. The new question must meet
the same conditions as for the input to the AddQuestionToLocalDB
operation.
*);
precondition:
(*
* The old and new questions are not the same.
*)
(old_q != new_q)
and
(*
* The old question is in the given database.
*)
(old_q in ldb)
and
(*
* There is no question in the local database with the same
* properties as the input question, q.
*)
(not (exists (new_q' in ldb) new_q'.questiontext = new_q.questiontext))
and
(not (exists (new_q' in ldb) new_q'.type = new_q.type))
and
(not (exists (new_q' in ldb) new_q'.class = new_q.class))
and
(not (exists (new_q' in ldb) new_q'.time = new_q.time))
and
(not (exists (new_q' in ldb) new_q'.difficulty = new_q.difficulty))
and
(not (exists (new_q' in ldb) new_q'.keywords = new_q.keywords))
and
(not (exists (new_q' in ldb) new_q'.correctanswer = new_q.correctanswer))
and
(not (exists (new_q' in ldb) new_q'.author = new_q.author));
postcondition:
(*
* A question is in the output database if and only if it is the new
* question to be added or it is in the input database, an dit is not
* the old question.
*)
forall (q':Question)
(q' in ldb') iff (((q' = new_q) or (q' in ldb)) and (q' != old_q));
end ModifyQuestionInLocalDB;
operation TransferQuestionToSharedDB is
inputs: ldb:LocalDB, sdb:SharedDB, q:Question;
outputs: sdb':SharedDB;
description:(*
Transfer the given Question from the local database to the shared
database. The Login operation for the server must occur before
the transfer. Before the question is transfered, the question
should not already be in the shared database. After the transfer,
the shared database should contain all questions as the input
shared database plus the question that was added from the local
database.
*);
precondition:
(*
* The question to be transfered should not exist in the shared database.
*)
(not (exists (q' in sdb) q'.questiontext = q.questiontext))
and
(not (exists (q' in sdb) q'.type = q.type))
and
(not (exists (q' in sdb) q'.class = q.class))
and
(not (exists (q' in sdb) q'.time = q.time))
and
(not (exists (q' in sdb) q'.difficulty = q.difficulty))
and
(not (exists (q' in sdb) q'.keywords = q.keywords))
and
(not (exists (q' in sdb) q'.correctanswer = q.correctanswer))
and
(not (exists (q' in sdb) q'.author = q.author));
postcondition:
(*
* The output shared database should only contain the question from
* the input shared database and the question added from the local
* database.
*)
forall (q':Question)
(q' in sdb') iff (((q' = q) or (q' in sdb)));
end TransferQuestionToSharedDB;
operation TransferSingleQuestionToLocalDB is
inputs: ldb:LocalDB, sdb:SharedDB, q:Question;
outputs: ldb':LocalDB;
description:(*
Transfer the given Question from the shared database to the local
database. The Login operation for the server must occur before
the transfer. Before the question is transfered, the question
should not already be in the local database. After the transfer,
the local database should contain all questions as the input
local database plus the question that was added from the shared
database.
*);
precondition:
(*
* The question to be transfered should not exist in the local database.
*)
(not (exists (q' in ldb) q'.questiontext = q.questiontext))
and
(not (exists (q' in ldb) q'.type = q.type))
and
(not (exists (q' in ldb) q'.class = q.class))
and
(not (exists (q' in ldb) q'.time = q.time))
and
(not (exists (q' in ldb) q'.difficulty = q.difficulty))
and
(not (exists (q' in ldb) q'.keywords = q.keywords))
and
(not (exists (q' in ldb) q'.correctanswer = q.correctanswer))
and
(not (exists (q' in ldb) q'.author = q.author));
postcondition:
(*
* The output local database should only contain the question from
* the input local database and the question added from the shared
* database.
*)
forall (q':Question)
(q' in ldb') iff (((q' = q) or (q' in ldb)));
end TransferSingleQuestionToLocalDB;
operation TransferAllQuestionsToLocalDB is
inputs: ldb:LocalDB, sdb:SharedDB;
outputs: ldb':LocalDB;
description:(*
Transfer the all the given Questions from the shared database to the local
database. The Login operation for the server must occur before
the transfer. Before the questions are transfered, there should be
no questions in the local database. After the transfer,
the local database should contain all questions in the shared database.
*);
precondition:
(*
* Remove all questions in the local database.
*)
forall(q' in ldb)
(q' = nil);
postcondition:
(*
* The output local database should only contain the questions from
* the input shared database.
*)
forall (q':Question)
(q' in ldb') iff (q' in sdb);
end TransferAllQuestionsToLocalDB;
operation ModifyQuestionInSharedDB is
inputs: sdb:SharedDB, old_q:Question, new_q:Question;
outputs: sdb':SharedDB;
description:(*
Change the given old question to the given new question.
The old and new questions must not be the same. The old question
must already be in the input database. The new question must meet
the same conditions as for the input to the AddQuestionToLocalDB
operation.
*);
precondition:
(*
* The old and new questions are not the same.
*)
(old_q != new_q)
and
(*
* The old question is in the given database.
*)
(old_q in sdb)
and
(*
* There is no question in the shared database with the same
* properties as the input question, q.
*)
(not (exists (new_q' in sdb) new_q'.questiontext = new_q.questiontext))
and
(not (exists (new_q' in sdb) new_q'.type = new_q.type))
and
(not (exists (new_q' in sdb) new_q'.class = new_q.class))
and
(not (exists (new_q' in sdb) new_q'.time = new_q.time))
and
(not (exists (new_q' in sdb) new_q'.difficulty = new_q.difficulty))
and
(not (exists (new_q' in sdb) new_q'.keywords = new_q.keywords))
and
(not (exists (new_q' in sdb) new_q'.correctanswer = new_q.correctanswer))
and
(not (exists (new_q' in sdb) new_q'.author = new_q.author));
postcondition:
(*
* A question is in the output database if and only if it is the new
* question to be added or it is in the input database, and it is not
* the old question.
*)
forall (q':Question)
(q' in sdb') iff (((q' = new_q) or (q' in sdb)) and (q' != old_q));
end ModifyQuestionInSharedDB;
operation RemoveQuestionFromSharedDB is
inputs: sdb:SharedDB, q:Question;
outputs: sdb':SharedDB;
description:(*
Delete the given question from the given shared database.
The given question must already be in the input shared
database. The question to be deleted from the shared
database must match the input question in all properties.
*);
precondition:
(*
* The given Question is in the given SharedDB
*)
q in sdb;
postcondition:
(*
* The question is in the output database if and only if it is not
* the existing record to be deleted and it is in the input db.
*)
(forall (q':Question)
(q' in sdb') iff ((q' != q) and (q' in sdb)));
end RemoveQuestionFromSharedDB;
(* Start Nelson Bonilla's Section *)
operation SearchQuestionDatabase is
inputs: qdb:QuestionDB, c:Class;
outputs: ql:Question*;
description: (*
Find a question or questions by class. If more than one is found, output list is sorted
by keyword.
*);
precondition: (* None *);
postcondition:
(*
* The output list consists of all questions of the given class in the input db.
*)
(forall (q:Question)
(q in ql) iff (q in qdb) and (q.class = c))
and
(*
* The output list is sorted in alphabetical order
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].class < ql[i + 1].class);
end SearchQuestionDatabase;
operation SearchQuestionDatabase is
inputs: qdb:QuestionDB, tp:Type;
outputs: ql:Question*;
description: (*
Find a question or questions by type. If more than one is found, output list is sorted
by keyword.
*);
precondition: (* None*);
postcondition:
(*
* The output list consists of all questions of the given type in the input db.
*)
(forall (q:Question)
(q in ql) iff (q in qdb) and (q.type = tp))
and
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].keywords < ql[i + 1].keywords);
end SearchQuestionDatabase;
operation SearchQuestionDatabase is
inputs: qdb:QuestionDB, tm:Time;
outputs: ql:Question*;
description: (*
Find a question or questions by time. If more than one is found, output list is sorted
by keyword.
*);
precondition: (* None *);
postcondition:
(*
* The output list consists of all questions of the given time in the input db.
*)
(forall (q:Question)
(q in ql) iff (q in qdb) and (q.time = tm))
and
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].keywords < ql[i + 1].keywords);
end SearchQuestionDatabase;
operation SearchQuestionDatabase is
inputs: qdb:QuestionDB, d:Difficulty;
outputs: ql:Question*;
description: (*
Find a question or questions by difficulty. If more than one is found, output list is sorted
by keyword.
*);
precondition: (* None *);
postcondition:
(*
* The output list consists of all questions of the given difficulty in the input db.
*)
(forall (q:Question)
(q in ql) iff (q in qdb) and (q.difficulty = d))
and
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].keywords < ql[i + 1].keywords);
end SearchQuestionDatabase;
operation SearchQuestionDatabase is
inputs: qdb:QuestionDB, l:LastUsed;
outputs: ql:Question*;
description: (*
Find a question or questions by LastUse. If more than one is found, output list is sorted
by keyword.
*);
precondition: (* None *);
postcondition:
(*
* The output list consists of all questions of the given Last Use in the input db.
*)
(forall (q:Question)
(q in ql) iff (q in qdb) and (q.lastused = l))
and
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].keywords < ql[i + 1].keywords);
end SearchQuestionDatabase;
operation SearchQuestionDatabase is
inputs: qdb:QuestionDB, k:Keywords;
outputs: ql:Question*;
description: (*
Find a question or questions by keyword. If more than one is found, output list is sorted
by keyword.
*);
precondition: (* None *);
postcondition:
(*
* The output list consists of all questions of the given keyword in the input db.
*)
(forall (q:Question)
(q in ql) iff (q in qdb) and (q.keywords = k))
and
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].keywords < ql[i + 1].keywords);
end SearchQuestionDatabase;
operation SearchQuestionDatabase is
inputs: qdb:QuestionDB, a:Author;
outputs: ql:Question*;
description: (*
Find a question or questions by author. If more than one is found, output list is sorted
by keyword.
*);
precondition: (* None *);
postcondition:
(*
* The output list consists of all questions of the given author in the input db.
*)
(forall (q:Question)
(q in ql) iff (q in qdb) and (q.author = a))
and
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].keywords < ql[i + 1].keywords);
end SearchQuestionDatabase;
operation SortQuestionDatabase is
inputs: qdb:QuestionDB;
outputs: ql:Question*;
description: (*
Sorts the column labeled class in alphabetical order.
*);
precondition: (* None *);
postcondition:
(*
* The output list is sorted in alphabetical order by class.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].class < ql[i + 1].class);
end SortQuestionDatabase;
operation SortQuestionDatabase is
inputs: qdb:QuestionDB;
outputs: ql:Question*;
description: (*
Sorts the column labeled type in alphabetical order.
*);
precondition: (* None *);
postcondition:
(*
* The output list is sorted in alphabetical order by type.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].type < ql[i + 1].type);
end SortQuestionDatabase;
operation SortQuestionDatabase is
inputs: qdb:QuestionDB;
outputs: ql:Question*;
description: (*
Sort the column labeled time in descending numerical order.
*);
precondition: (* None *);
postcondition:
(*
* The output list is sorted in numerical order by time.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].time < ql[i + 1].time);
end SortQuestionDatabase;
operation SortQuestionDatabase is
inputs: qdb:QuestionDB;
outputs: ql:Question*;
description: (*
Sort the column labeled difficulty in descending numerical order.
*);
precondition: (* None *);
postcondition:
(*
* The output list is sorted in numerical order by difficulty.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].difficulty < ql[i + 1].difficulty);
end SortQuestionDatabase;
operation SortQuestionDatabase is
inputs: qdb:QuestionDB;
outputs: ql:Question*;
description: (*
Sort the column labeled Last Use by date with the most recent at the top.
*);
precondition: (* None *);
postcondition:
(*
* The output list is sorted in alphabetical order by last use.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].lastused < ql[i + 1].lastused);
end SortQuestionDatabase;
operation SortQuestionDatabase is
inputs: qdb:QuestionDB;
outputs: ql:Question*;
description: (*
Sort the column labeled keyword in alphabetical order.
*);
precondition: (* None *);
postcondition:
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].keywords < ql[i + 1].keywords);
end SortQuestionDatabase;
operation SortQuestionDatabase is
inputs: qdb:QuestionDB;
outputs: ql:Question*;
description: (*
Sort the column labeled author in alphabetical order.
*);
precondition: (* None *);
postcondition:
(*
* The output list is sorted in alphabetical order by keyword.
*)
(forall (i:integer | (i >= 1) and (i < #ql))
ql[i].author < ql[i + 1].author);
end SortQuestionDatabase;
(* End Nelson Bonilla's Section *)
end Question;
Prev: view.rsl
| Next: test.rsl
| Up: formal specification
| Top: index