5.7. Grading (grading.rsl)

(*--- Describe the objects and operations related to grading ---*)

(* Filename - grading.rsl
   Author   - Sujit Polpaya 
              (With a lot of help from Chris Noe.)
   Date     - 05/24/2004
   CPE 205, Dr.Fisher, Cal Poly, San Luis Obispo.
 *)


(*--- Begin module Grader ---*)
module TestToolGrader;

    (*--- Imports ---*)
    from Test import Test, TakenTest, GradedTest, TotalPoints, File;
    from Question import Question, AnsweredQuestion, GradedQuestion, AutoGrade, CorrectAnswer, 
                         Response, Points, PointsEarned, Feedback, QuestionNumber;
    from File import FileType, TakenTestType, GradedTestType;

    (* There are no exports or objects in this module because this module uses the objects defined in
       the other sections of the Test Tool. 
     *)


    (* Automatically grade all the auto-gradable questions in all the available tests. *)
    operation AutoGradeTests
        inputs       : ttests:TakenTest*;
        outputs      : agtests:GradedTest*;
        precondition : (* All the tests in the list should be of the type: TakenTest *)
        
                       (forall (k:integer | (k >= 1) and (k < #(ttests)))
                            (ttests[k].file.file_type?taken_test_type));

        postcondition: (* All the auto-gradable questions in all the available tests are graded.
                          If the response matches with the correct answer, full points are awarded,
                          else a zero is awarded. *)

                       (forall (i:integer | (i >= 1) and (i < #(ttests)))
                            (forall (j:integer | (j >= 1) and (j < #(ttests[i].answeredquestionlist)))
                                (if (ttests[i].answeredquestionlist[j].autograde = true)
                                 then
                                    (if(ttests[i].answeredquestionlist[j].response =
                                        ttests[i].answeredquestionlist[j].correctanswer)
                                     then
                                        agtests[i].gradedquestionlist[j].pointsearned = 
                                        ttests[i].answeredquestionlist[j].points
                                     else agtests[i].gradedquestionlist[j].pointsearned = 0))));

    description      : (* Automatic grading tests attempts to grade all the tests in the grading folder.
                          But, it grades only the auto-gradable questions in each test, namely the multiple-choice,
                          true or false, fill-in-the-blanks and matching. Functionality to grade a matching question
                          is not implemented yet. Responses are compared with the correct answer only if the question
                          is auto-gradable. Points are assigned if the response matches with the correct answer, which
                          is stored either as a character or a string. If the response does not match with the correct
                          answer, a zero is awarded. *);
    end AutoGradeTests;


    (* Display autograding summary. *)
    operation DisplayAutoGradingSummary
        inputs       : ttests:TakenTest*;
        outputs      : agtests:GradedTest*, total_tests_available:integer, total_tests_graded:integer,
                       total_questions_in_each_test:integer;
        precondition : (* None. Preconditions are already satisfied in operation AutoGradeTests *);
        postcondition: (* Total tests available        = # of tests in a Taken Test.
                          Total tests graded           = # of tests in a Graded Test.
                          Total questions in each test = # of questions in any test.
                          There is no way to implement a counter to count the number of tests graded
                          automatically. *)
                        
                        ((total_tests_available = #(ttests))
        
                        and
                        
                        (total_tests_graded = #(agtests))
                        
                        and
                        
                        (total_questions_in_each_test = #(ttests[1].answeredquestionlist)));
                        
    description      : (* Output the numeric values used to display in the summary dialog box. *);
                        
    end DisplayAutoGradingSummary;
    

    (* Manually grade an individual test by assigning points and feedback to each student response.
       Feedback can be empty. *)
    operation ManualGradeTest
        inputs       : ttest:TakenTest, pts:Points*, fdbk:Feedback*;
        outputs      : mgtest:GradedTest;
        precondition : (* The test should be of the type: TakenTest, and the points awarded cannot
                          be more than the possible points for each question. *)
        
                       ((ttest.file.file_type?taken_test_type)
                       
                         and 
                       
                        (forall (k:integer | (k >= 1) and (k < #(ttest.answeredquestionlist)))
                            (pts[k] <= ttest.answeredquestionlist[k].points)));
                       
        postcondition: (* Assign the respective points earned and the feedback to the respective
                          question in the test. *)
                          
                       (forall (i:integer | (i >= 1) and (i < #(ttest.answeredquestionlist)))
                            (mgtest.gradedquestionlist[i].pointsearned = pts[i])
                            
                            and
                            
                            (mgtest.gradedquestionlist[i].feedback = fdbk[i]));
                            
        description  : (* Points assigned for all the short-answer and program source code type questions,
                          and feedback by the grader are added to produce the graded test. The grader has
                          to grade each question in the test manually. *);
    end ManualGradeTest;


    (* Manually grade an individual question in an individual test. *)
    operation ManualGradeQuestion
        inputs       : que:AnsweredQuestion, pts:Points, fdbk:Feedback;
        outputs      : que':GradedQuestion;
        precondition : (* Points awarded cannot be more than the possible points. *)
        
                       (pts <= que.points);
                       
        postcondition: (* The grader assigns a point to the response manually.
                          So, just assign the points and feedback. Feedback can be empty. *)
                       
                       (que'.pointsearned = pts and que'.feedback = fdbk);
                       
    end ManualGradeQuestion;
    
    
    (* Manually grade an individual questions in all the tests. *)
    operation ManualGradeQuestionsInTests
        inputs       : ttests:TakenTest*, question_number:integer, pts:Points*, fdbk:Feedback*;
        outputs      : agtests:GradedTest*;
        precondition : (* All the tests in the list should be of the type: TakenTest, and
                          Points awarded cannot be more than the possible points for the specific
                          question. *)
                          
                       (forall (k:integer | (k >= 1) and (k < #(ttests)))
                            (ttests[k].file.file_type?taken_test_type))
                           
                       and

                       (forall (k:integer | (k >= 1) and (k < #(ttests)))
                            (pts[k] <= ttests[k].answeredquestionlist[question_number].points));
                            
        postcondition: (* The grader assigns a point to the response manually.
                          So, just assign the points and feedback. Feedback can be empty. *)

                       (forall (i:integer | (i >= 1) and (i < #(ttests)))
                            (agtests[i].gradedquestionlist[question_number].pointsearned = pts[i])
                            
                            and
                            
                            (agtests[i].gradedquestionlist[question_number].feedback = fdbk[i]));
         
        description  : (* Grades a specific question number in all the available tests. The grader
                          has to input the question number, points and feedback for each question. *);
                            
    end ManualGradeQuestionsInTests;    


    (* EditPointsEarned can be used to add, or edit points to a question. *)
    operation EditPointsEarned
        inputs       : que:AnsweredQuestion, pts:Points;
        outputs      : que':GradedQuestion;
        precondition : (* Points earned cannot be more than the possible points. *)
        
                       (que'.pointsearned <= que.points);
                       
        postcondition: (* The grader assigns a point to the response manually.
                          Just assign the points to the points earned. *)
        
                       (que'.pointsearned = pts);
                       
    end EditPointsEarned;


    (* EditFeedback can be used to add, or edit feedback to a question. *)
    operation EditFeedback
        inputs       : que:AnsweredQuestion, fdbk:Feedback;
        outputs      : que':GradedQuestion;
        precondition : (* The question should not be automatically gradable. *)
        
                       (que.autograde = false);
                       
        postcondition: (* The grader assigns a feedback to the response manually. *)
        
                       (que'.feedback = fdbk);
    end EditFeedback;


    (* Adds the points earned by each response in a test to calculate the final test score. *)
    operation CalculateTotalEarnedPoints
        inputs       : gtest:GradedTest;
        outputs      : gtest':GradedTest;
        precondition : (* Test has to be of the type: GradedTest *)
        
                       (gtest.file.file_type?graded_test_type);

        postcondition: (* Adds up points earned for each graded question. *)

                         (forall (i:integer | (i >= 1) and (i < #(gtest.gradedquestionlist)))
                            (gtest.totalpoints = gtest.totalpoints + gtest.gradedquestionlist[i].pointsearned));

        description  : (* Just adds up points earned for each question. There is no way to check if the
                          question is already graded by the grader. This is applicable for manually graded
                          questions. Auto-gradable questions are already graded and points are awarded. *);

    end CalculateTotalEarnedPoints;
    
    
    (* Display a student test view: GUI output operation. *)
    operation DisplayStudentTestView
        inputs       : ttest:TakenTest;
        outputs      : gtest:GradedTest;
        precondition : (* None *);
        postcondition: (* Initialize the points earned and feedback for each test question. *)
        
                       (forall (i:integer | (i >= 1) and (i < #(ttest.answeredquestionlist)))

                            (gtest.gradedquestionlist[i].pointsearned = 0)

                            and

                            (gtest.gradedquestionlist[i].feedback = nil));

        description  : (* A student test view displays all the test questions and student responses,
                          with the points earned for each question initialized to 0, and the feedback
                          initialized to nil. *);
    end DisplayStudentTestView;
    
    
    (* Display a question view: GUI output operation. *)
    operation DisplayQuestionView
        inputs       : ttests:TakenTest*, question_number:integer;
        outputs      : gtests:GradedTest*, gque:GradedQuestion*;
        precondition : (* None *);
        postcondition: (* A graded question is visible only if the question index matches with the question
                          number input by the user. *)
                          
                       (forall (i:integer | (i >= 1) and (i < #(ttests)))
                            (forall (j:integer | (j >= 1) and (j < #(ttests[i].answeredquestionlist)))
                                (gtests[i].gradedquestionlist[j] in gque) iff (question_number = 
                                                                               gtests[i].gradedquestionlist[j].questionnumber)

                                 and

                                (gtests[i].gradedquestionlist[j].pointsearned = 0)

                                 and

                                 (gtests[i].gradedquestionlist[j].feedback = nil)));

        description  : (* A student test view displays all the test questions and student responses,
                          with the points earned for each question initialized to 0, and the feedback
                          initialized to nil. *);
    end DisplayQuestionView;    
  

end TestToolGrader;

(*--- End module Grader ---*)


Prev: generate.rsl | Next: student.rsl | Up: formal specification | Top: index