Advertisement
Guest User

Untitled

a guest
Apr 20th, 2014
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 11.20 KB | None | 0 0
  1. <?php
  2.  
  3. require_once(IA_ROOT_DIR."common/task.php");
  4.  
  5. abstract class BaseGrader {
  6.     protected $task, $job;
  7.     protected $result, $testResults;
  8.  
  9.     public function __construct($task, $tparams, $job) {
  10.         $this->task = array_merge($task, $tparams);
  11.         $this->job = $job;
  12.     }
  13.  
  14.     /**
  15.      * Compiles custom evaluator and interactive program if needed.
  16.      * The evaluator is used when multiple correct solutions can be outputted,
  17.      * in which case simply comparing files is not enough.
  18.      * The interactive program is used in 'interactive' tasks. This program is
  19.      * run in parallel with the user's program and comunication between them
  20.      * is implemented through pipes.
  21.      */
  22.     protected function compileEvaluators() {
  23.         $evals = array(
  24.             'evaluator' => 'evaluatorul problemei',
  25.             'interact' => 'programul interactiv',
  26.         );
  27.         foreach ($evals as $eval_type => $eval_desc) {
  28.             if (!getattr($this->task, $eval_type)) {
  29.                 continue;
  30.             }
  31.  
  32.             $source_file = IA_ROOT_DIR . 'eval/temp/' . $this->task[$eval_type];
  33.             if (!copy_grader_file($this->task, $this->task[$eval_type],
  34.                                   $source_file)) {
  35.                 log_print("Task $eval_type not found");
  36.                 throw new EvalTaskOwnerError(
  37.                     "Lipşeşte {$eval_desc}.\nPagina cu enunţul problemei " .
  38.                     "trebuie să conţină un ataşament 'grader_" .
  39.                     $this->task[$eval_type] . "'");
  40.             }
  41.  
  42.             $compiler_messages = '';
  43.             if (!compile_file($source_file, $eval_type, $compiler_messages)) {
  44.                 log_print("Task $eval_type compile error");
  45.                 throw new EvalTaskOwnerError('Eroare de compilare în ' .
  46.                                              $eval_desc . ":\n" .
  47.                                              $compiler_messages);
  48.             }
  49.         }
  50.     }
  51.  
  52.     /**
  53.      * Processes the user submission. For classic and interactive tasks, this
  54.      * means compiling the user's source file.
  55.      */
  56.     protected function processUserSubmission() {
  57.         $source_file = 'user.' . $this->job['compiler_id'];
  58.         $res = @file_put_contents($source_file,
  59.                                   $this->job['file_contents']);
  60.         eval_assert($res !== false,
  61.                     'User program could not be written to disk');
  62.  
  63.         $compiler_messages = '';
  64.         if (!compile_file($source_file, 'user', $compiler_messages)) {
  65.             log_print('User program compile error');
  66.             log_print($compiler_messages);
  67.             throw new EvalUserCompileError($compiler_messages);
  68.         }
  69.         $this->result['log'] = "Compilare:\n" . $compiler_messages . "\n";
  70.     }
  71.  
  72.     /**
  73.      * Perform any necessary actions before running test cases.
  74.      * These include compiling evaluators or interactive programs and
  75.      * compiling user source files.
  76.      */
  77.     protected function preTestCases() {
  78.         $this->result = array(
  79.             'score' => 0,
  80.             'message' => 'Evaluare incompleta',
  81.             'log' => '',
  82.         );
  83.  
  84.         // Clean temporary directory and chdir to it
  85.         eval_assert(clean_dir(IA_ROOT_DIR . 'eval/temp/'),
  86.                     "Can't clean temp dir.");
  87.         eval_assert(@chdir(IA_ROOT_DIR . 'eval/temp/'),
  88.                     "Can't chdir to temp dir.");
  89.  
  90.         // Compile all source files
  91.         $this->compileEvaluators();
  92.         $this->processUserSubmission();
  93.     }
  94.  
  95.     /**
  96.      * Perform any necessary actions after running all test cases.
  97.      */
  98.     protected function postTestCases() {
  99.         $this->result['message'] = 'Evaluare completa';
  100.         if ($this->result['score'] < 0 ||
  101.             $this->result['score'] > IA_JUDGE_MAX_SCORE) {
  102.             throw new EvalTaskOwnerError(
  103.                 'Evaluatorul a returnat un scor invalid.');
  104.         }
  105.     }
  106.  
  107.     protected function getInFile($jaildir) {
  108.         return $jaildir . $this->task['id'] . '.in';
  109.     }
  110.  
  111.     protected function getOutFile($jaildir) {
  112.         return $jaildir . $this->task['id'] . '.out';
  113.     }
  114.  
  115.     protected function getOkFile($jaildir) {
  116.         return $jaildir . $this->task['id'] . '.ok';
  117.     }
  118.  
  119.     /**
  120.      * Evaluates the contestant's output on a particular test case.
  121.      *
  122.      * @param  int     $testno
  123.      * @param  string  $jaildir
  124.      */
  125.     protected function testCaseJudgeOutputs($testno, $jaildir) {
  126.         $test_result = &$this->testResults[$testno];
  127.         $outfile = $this->getOutFile($jaildir);
  128.         $okfile = $this->getOkFile($jaildir);
  129.  
  130.         // Copy ok file, if used.
  131.         if ($this->task['use_ok_files']) {
  132.             if (!copy_grader_file($this->task, 'test' . $testno . '.ok',
  133.                                   $okfile)) {
  134.                 log_print("Test $testno: .ok file not found");
  135.                 throw new EvalTaskOwnerError(
  136.                     "Lipşeşte fişierul .ok al testului $testno.\nPagina cu " .
  137.                     "enunţul problemei trebuie să conţină un ataşament " .
  138.                     "'grader_test{$testno}.ok'");
  139.             }
  140.         }
  141.  
  142.         if (!$this->task['evaluator']) {
  143.             // Diff grading, trivial.
  144.             $test_result['grader_time'] = null;
  145.             $test_result['grader_mem'] = null;
  146.             if (is_readable($outfile)) {
  147.                 $diff_output = shell_exec("diff -qBbEa $outfile $okfile");
  148.                 if ($diff_output == '') {
  149.                     log_print("Test $testno: Diff eval: Files identical");
  150.                     $test_result['message'] = 'OK';
  151.                     $test_result['score'] = 100 / $this->task['test_count'];
  152.                 } else {
  153.                     log_print("Test $testno: Diff eval: Files differ");
  154.                     $test_result['message'] = 'Incorect';
  155.                     $test_result['score'] = 0;
  156.                 }
  157.             } else {
  158.                 log_print("Test $testno: Diff eval: output missing");
  159.                 $test_result['message'] = 'Fisier de iesire lipsa';
  160.                 $test_result['score'] = 0;
  161.             }
  162.             return;
  163.         }
  164.  
  165.         // Custom grader.
  166.         $ret = @copy(IA_ROOT_DIR . 'eval/temp/evaluator',
  167.                      $jaildir . 'evaluator');
  168.         eval_assert($ret, 'Failed to copy custom grader');
  169.         eval_assert(chmod('evaluator', 0555),
  170.                     'Failed to chmod a+x user program');
  171.  
  172.         // Run task eval, and check result
  173.         $jrunres = jail_run('evaluator', $jaildir,
  174.                             IA_JUDGE_TASK_EVAL_TIMELIMIT,
  175.                             IA_JUDGE_TASK_EVAL_MEMLIMIT,
  176.                             true);
  177.         eval_assert($jrunres['result'] != 'ERROR', "Error in jrun");
  178.  
  179.         // Task eval is not allowed to fail.
  180.         if ($jrunres['result'] == 'FAIL') {
  181.             log_print("Test $testno: Task eval failed");
  182.             throw new EvalTaskOwnerError(
  183.                 "A apărut o eroare în rularea evaluatorului pe testul " .
  184.                 "$testno: {$jrunres['message']}: timp {$jrunres['time']}ms: " .
  185.                 "mem {$jrunres['memory']}kb");
  186.         }
  187.  
  188.         // Get score.
  189.         $jrunres['stdout'] = trim($jrunres['stdout']);
  190.         if ($jrunres['stdout'] === '' ||
  191.             !is_whole_number($jrunres['stdout'])) {
  192.             log_print("Test $testno: Task eval score broken or empty");
  193.             throw new EvalTaskOwnerError(
  194.                 "Evaluatorul nu a returnat un număr la stdout " .
  195.                 "pe testul $testno (se ignoră spaţii, newline, etc)");
  196.         }
  197.  
  198.         $test_result['grader_time'] = $jrunres['time'];
  199.         $test_result['grader_mem'] = $jrunres['memory'];
  200.         $test_result['score'] = (int)$jrunres['stdout'];
  201.         if ($test_result['score'] < 0 ||
  202.             $test_result['score'] > IA_JUDGE_MAX_SCORE) {
  203.             log_print("Test $testno: Invalid score returned by evaluator");
  204.             throw new EvalTaskOwnerError(
  205.                 'Evaluatorul a returnat un scor invalid.');
  206.         }
  207.  
  208.         // Get message.
  209.         $message = $jrunres['stderr'];
  210.         $message = strtok($message, "\n");
  211.         if (strlen($message) == 0 ||
  212.             strlen($message) > IA_JUDGE_MAX_EVAL_MESSAGE) {
  213.             log_print("Test $testno: Task eval message broken");
  214.             throw new EvalTaskOwnerError(
  215.                 'Evaluatorul a returnat un mesaj gol sau mai lung de ' .
  216.                 IA_JUDGE_MAX_EVAL_MESSAGE . 'de caractere la stdout');
  217.         }
  218.         $test_result['message'] = $message;
  219.  
  220.         // Log.
  221.         log_print("Test $testno: Eval gave {$test_result['score']} points " .
  222.                   "and said {$test_result['message']}");
  223.     }
  224.  
  225.     /**
  226.      * Judges the user's submission on one test case. Depinding on task type,
  227.      * it should copy the necessary input and user files, compile and run any
  228.      * source files and call testCaseJudgeOutputs() afterwards
  229.      *
  230.      * @param  int     $testno
  231.      * @param  string  $jaildir
  232.      */
  233.     abstract protected function testCaseJudge($testno, $jaildir);
  234.  
  235.     /**
  236.      * Grade the submission and return the result
  237.      *
  238.      * @return array            Array containing 'score', 'message' and 'log'
  239.      *                          fields
  240.      */
  241.     public function grade() {
  242.         $this->preTestCases();
  243.  
  244.         // Running tests.
  245.         $this->testResults = array();
  246.         $test_score = array();
  247.  
  248.         $test_groups = task_get_testgroups($this->task);
  249.         $group_idx = 0;
  250.         foreach ($test_groups as $group) {
  251.             $group_idx++;
  252.             foreach ($group as $testno) {
  253.                 if (IA_JUDGE_KEEP_JAILS) {
  254.                     $jaildir = (IA_ROOT_DIR . 'eval/jail/' .
  255.                                 $this->job['id'] . '-' . $testno . '/');
  256.                 } else {
  257.                     $jaildir = IA_ROOT_DIR . "eval/jail/";
  258.                 }
  259.  
  260.                 // Clean and chdir to jail dir.
  261.                 eval_assert(clean_dir($jaildir), "Can't clean jail dir.");
  262.                 eval_assert(@chdir($jaildir), "Can't chdir to jail dir.");
  263.  
  264.                 $this->testCaseJudge($testno, $jaildir);
  265.                 $test_result = &$this->testResults[$testno];
  266.                 job_test_update($this->job['id'], $testno, $group_idx,
  267.                                 $test_result['test_time'],
  268.                                 $test_result['test_mem'],
  269.                                 $test_result['grader_time'],
  270.                                 $test_result['grader_mem'],
  271.                                 $test_result['score'], $test_result['message']);
  272.                 $test_score[$testno] = $test_result['score'];
  273.             }
  274.  
  275.             $solved_group = true;
  276.             $group_score = 0;
  277.             foreach ($group as $testno) {
  278.                 if ($test_score[$testno] == 0) {
  279.                     $solved_group = false;
  280.                 }
  281.                 $group_score += $test_score[$testno];
  282.             }
  283.             if ($solved_group) {
  284.                 $this->result['score'] += $group_score;
  285.             }
  286.         }
  287.  
  288.         $this->postTestCases();
  289.         return $this->result;
  290.     }
  291. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement