public function test_strings_in_castext_escaped() { $vars = 'st:"This is a string with escaped \\" strings...."'; $at1 = new stack_cas_keyval($vars, null, 123, 't', true, 0); $this->assertTrue($at1->get_valid()); $at2 = new stack_cas_text('\\[@st@\\]', $at1->get_session(), 0, 't'); $this->assertTrue($at2->get_valid()); $at2->get_display_castext(); $this->assertEquals($at2->get_display_castext(), '\\[\\mbox{This is a string with escaped " strings....}\\]'); }
/** * Validate all the maxima code in the question. * * This is done last, and separate from the other validation for two reasons: * 1. The rest of the validation is organised to validate the form in order, * to match the way the form is defined. Here we need to validate in the * order that the CAS is evaluated at run-time. * 2. This is the slowest part of validation, so we only do it at the end if * everything else is OK. * * @param array $errors the errors array that validation is assembling. * @param array $fromform the submitted data to validate. * @return array updated $errors array. */ protected function validate_question_cas_code($errors, $fromform, $fixingdollars) { $keyval = new stack_cas_keyval($fromform['questionvariables'], $this->options, $this->seed, 't'); $keyval->instantiate(); $session = $keyval->get_session(); if ($session->get_errors()) { $errors['questionvariables'][] = $session->get_errors(); return $errors; } // Instantiate all text fields and look for errors. $castextfields = array('questiontext', 'specificfeedback', 'generalfeedback'); foreach ($castextfields as $field) { $errors = $this->validate_cas_text($errors, $fromform[$field]['text'], $field, $fixingdollars, clone $session); } $errors = $this->validate_cas_text($errors, $fromform['questionnote'], 'questionnote', $fixingdollars, clone $session); // Make a list of all inputs, instantiate it and then look for errors. $inputs = $this->get_input_names_from_question_text(); $inputvalues = array(); foreach ($inputs as $inputname => $notused) { $cs = new stack_cas_casstring($inputname . ':' . $fromform[$inputname . 'modelans']); $cs->get_valid('t'); $inputvalues[] = $cs; if ($fromform[$inputname . 'options']) { $cs = new stack_cas_casstring('optionsfor' . $inputname . ':' . $fromform[$inputname . 'options']); $cs->get_valid('t'); $inputvalues[] = $cs; } } $inputsession = clone $session; $inputsession->add_vars($inputvalues); $inputsession->instantiate(); foreach ($inputs as $inputname => $notused) { if ($inputsession->get_errors_key($inputname)) { $errors[$inputname . 'modelans'][] = $inputsession->get_errors_key($inputname); // TODO: Send the acutal value to to input, and ask it to validate it. // For example, the matrix input type could check that the model answer is a matrix. } if ($fromform[$inputname . 'options'] && $inputsession->get_errors_key('optionsfor' . $inputname)) { $errors[$inputname . 'options'][] = $inputsession->get_errors_key('optionsfor' . $inputname); } // else TODO: Send the acutal value to the input, and ask it to validate it. } // At this point if we have errors, especially with inputs, there is no point in executing any of the PRTs. if (!empty($errors)) { return $errors; } // TODO: loop over all the PRTs in a similar manner.... // Remember, to use // clone $inputsession // as the base session to have all the teacher's answers instantiated. // Otherwise we are likley to do illigitimate things to the various inputs. return $errors; }
/** * Once we know the random seed, we can initialise all the other parts of the question. */ public function initialise_question_from_seed() { // Build up the question session out of all the bits that need to go into it. // 1. question variables. $questionvars = new stack_cas_keyval($this->questionvariables, $this->options, $this->seed, 't'); $session = $questionvars->get_session(); // 2. correct answer for all inputs. $response = array(); foreach ($this->inputs as $name => $input) { $cs = new stack_cas_casstring($input->get_teacher_answer()); $cs->get_valid('t'); $cs->set_key($name); $response[$name] = $cs; } $session->add_vars($response); $sessionlength = count($session->get_session()); // 3. CAS bits inside the question text. $questiontext = $this->prepare_cas_text($this->questiontext, $session); // 4. CAS bits inside the specific feedback. $feedbacktext = $this->prepare_cas_text($this->specificfeedback, $session); // 5. CAS bits inside the question note. $notetext = $this->prepare_cas_text($this->questionnote, $session); // 6. The standard PRT feedback. $prtcorrect = $this->prepare_cas_text($this->prtcorrect, $session); $prtpartiallycorrect = $this->prepare_cas_text($this->prtpartiallycorrect, $session); $prtincorrect = $this->prepare_cas_text($this->prtincorrect, $session); // Now instantiate the session. $session->instantiate(); if ($session->get_errors()) { // We throw an exception here because any problems with the CAS code // up to this point should have been caught during validation when // the question was edited or deployed. throw new stack_exception('qtype_stack_question : CAS error when instantiating the session: ' . $session->get_errors($this->user_can_edit())); } // Finally, store only those values really needed for later. $this->questiontextinstantiated = $questiontext->get_display_castext(); $this->specificfeedbackinstantiated = $feedbacktext->get_display_castext(); $this->questionnoteinstantiated = $notetext->get_display_castext(); $this->prtcorrectinstantiated = $prtcorrect->get_display_castext(); $this->prtpartiallycorrectinstantiated = $prtpartiallycorrect->get_display_castext(); $this->prtincorrectinstantiated = $prtincorrect->get_display_castext(); $session->prune_session($sessionlength); $this->session = $session; // Allow inputs to update themselves based on the model answers. $this->adapt_inputs(); }
public function test_do_test_3() { // Nontrivial use of the feeback variables. // Error in authoring ends up in loop. STACK should bail. $options = new stack_options(); $seed = 12345; $questionvars = new stack_cas_keyval('n:3; p:(x+1)^n; ta:p;', $options, $seed, 't'); // Feeback variables. $cstrings = array('sa1:sans', 'sa2:expand(sans)'); foreach ($cstrings as $s) { $cs = new stack_cas_casstring($s); $cs->get_valid('t'); $s1[] = $cs; } $feedbackvars = new stack_cas_session($s1, $options, $seed); $feedbackvars->get_valid(); // Define the tree itself. $sans = new stack_cas_casstring('sa1'); $sans->get_valid('t'); $tans = new stack_cas_casstring('ta'); $tans->get_valid('t'); $node = new stack_potentialresponse_node($sans, $tans, 'AlgEquiv', '', true); $node->add_branch(0, '=', 0, '', -1, 'Test 1 false. Look: \\[@(sa1)^2@ \\neq @(sa2)^2@\\]', FORMAT_HTML, '1-0-0'); $node->add_branch(1, '=', 1, '', 1, 'Test 1 true. ', FORMAT_HTML, '1-0-1'); $potentialresponses[] = $node; $sans = new stack_cas_casstring('sa2'); $sans->get_valid('t'); $tans = new stack_cas_casstring('ta'); $tans->get_valid('t'); $node = new stack_potentialresponse_node($sans, $tans, 'FacForm', 'x', true); $node->add_branch(0, '-', 0.7, '', 0, 'Test 2 false.', FORMAT_HTML, '1-1-0'); $node->add_branch(1, '+', 1, '', 3, 'Test 2 true', FORMAT_HTML, '1-1-1'); $potentialresponses[] = $node; $tree = new stack_potentialresponse_tree('', '', true, 5, $feedbackvars, $potentialresponses, 0); // Some data from students. $answers = array('sans' => '(x+1)^3'); $result = $tree->evaluate_response($questionvars->get_session(), $options, $answers, $seed); $this->assertTrue($result->valid); $this->assertEquals('', $result->errors); $this->assertEquals(0.3, $result->score); $this->assertEquals(0, $result->penalty); $this->assertEquals(2, count($result->feedback)); $this->assertEquals('Test 1 true.', $result->feedback[0]->feedback); $this->assertEquals('Test 2 false.', $result->feedback[1]->feedback); $this->assertEquals(array('1-0-1', 'ATFacForm_notfactored.', '1-1-0', '[PRT-CIRCULARITY]=0'), $result->answernotes); $this->assertEquals(array('sa1', 'ta'), $tree->get_required_variables(array('sa1', 'sa3', 'ta', 'ssa1', 'a1', 't'))); }
$simp = true; } else { $simp = false; } // Initially simplification should be on. if (!$vars and !$string) { $simp = true; } if ($string) { $options = new stack_options(); $options->set_site_defaults(); $options->set_option('simplify', $simp); $session = new stack_cas_session(null, $options); if ($vars) { $keyvals = new stack_cas_keyval($vars, $options, 0, 't'); $session = $keyvals->get_session(); $varerrs = $keyvals->get_errors(); } if (!$varerrs) { $ct = new stack_cas_text($string, $session, 0, 't'); $displaytext = $ct->get_display_castext(); $errs = $ct->get_errors(); $debuginfo = $ct->get_debuginfo(); } } echo $OUTPUT->header(); echo $OUTPUT->heading($title); echo html_writer::tag('p', stack_string('chatintro')); // If we are editing the General Feedback from a question it is very helpful to see the question text. if ($questionid) { echo $OUTPUT->heading(stack_string('questiontext'), 3);
public static function make_stack_question_runtime_prt_err() { $q = self::make_a_stack_question(); $q->name = 'runtime_prt_err'; $q->questionvariables = ""; $q->questiontext = '<p>Give an example of a system of equations with a unique solution.</p>' . '<p>[[input:ans1]] [[validation:ans1]]</p>'; $q->specificfeedback = '[[feedback:Result]]'; $q->questionnote = ''; $q->inputs['ans1'] = stack_input_factory::make('algebraic', 'ans1', '[x+y=1,x-y=1]', array('boxWidth' => 25)); $feedbackvars = new stack_cas_keyval('', null, 0, 't'); $sans = new stack_cas_casstring('all_listp(equationp,ans1)'); $sans->get_valid('t'); $tans = new stack_cas_casstring('true'); $tans->get_valid('t'); $node0 = new stack_potentialresponse_node($sans, $tans, 'AlgEquiv', '', true); $node0->add_branch(0, '=', 0, '', -1, 'Your answer should be a list of equations!', FORMAT_HTML, 'Result-0-F'); $node0->add_branch(1, '=', 0, '', 1, 'Your answer is a list of equations.', FORMAT_HTML, 'Result-0-T'); $sans = new stack_cas_casstring('solve(ans1,listofvars(ans1))'); $sans->get_valid('t'); $tans = new stack_cas_casstring('[]'); $tans->get_valid('t'); $node1 = new stack_potentialresponse_node($sans, $tans, 'AlgEquiv', '', true); $node1->add_branch(0, '=', 0, $q->penalty, -1, 'Your equations have no solution!', FORMAT_HTML, 'Result-1-F'); $node1->add_branch(1, '=', 0, $q->penalty, 2, 'You have some solutions!', FORMAT_HTML, 'Result-1-T'); $sans = new stack_cas_casstring('length(solve(ans1,listofvars(ans1)))'); $sans->get_valid('t'); $tans = new stack_cas_casstring('1'); $tans->get_valid('t'); $node2 = new stack_potentialresponse_node($sans, $tans, 'AlgEquiv', '', true); $node2->add_branch(0, '=', 0, $q->penalty, -1, 'You should have only one solution.', FORMAT_HTML, 'Result-2-F'); $node2->add_branch(1, '=', 1, $q->penalty, -1, 'Good, you have one solution.', FORMAT_HTML, 'Result-2-T'); $q->prts['Result'] = new stack_potentialresponse_tree('Result', '', true, 1, $feedbackvars->get_session(), array($node0, $node1, $node2), 0); return $q; }
public function test_keyval_session_keyval_3() { // Inserting stars. $kvin = "a:2x; b:(x+1)(x-1); b:f(x);"; $kvins = "a:2*x; b:(x+1)*(x-1); b:f(x);"; $at1 = new stack_cas_keyval($kvin, null, 123, 's', false, 1); $session = $at1->get_session(); $kvout = $session->get_keyval_representation(); $this->assertEquals($kvins, $kvout); }