public function instantiate() { if (null === $this->valid) { $this->validate(); } if (!$this->valid) { return false; } $this->session->instantiate(); $this->instantiated = true; }
public function adapt_to_model_answer($teacheranswer) { // Work out how big the matrix should be from the INSTANTIATED VALUE of the teacher's answer. $cs = new stack_cas_casstring('ta:matrix_size(' . $teacheranswer . ')'); $cs->get_valid('t'); $at1 = new stack_cas_session(array($cs), null, 0); $at1->instantiate(); if ('' != $at1->get_errors()) { $this->errors = $at1->get_errors(); return; } $size = $at1->get_value_key('ta'); $dimensions = explode(',', $size); $this->height = trim($dimensions[0], '[]'); $this->width = trim($dimensions[1], '[]'); }
public function test_ordergreat() { $cs = array('ordergreat(i,j,k)', 'p:matrix([-7],[2],[-3])', 'q:matrix([i],[j],[k])', 'v:dotproduct(p,q)'); foreach ($cs as $s) { $cs = new stack_cas_casstring($s); $cs->get_valid('t'); $s1[] = $cs; } $at1 = new stack_cas_session($s1, null, 0); $at1->instantiate(); $this->assertEquals('-7*i+2*j-3*k', $at1->get_value_key('v')); }
/** * * * @return bool * @access public */ public function do_test() { if ('' == trim($this->sanskey)) { $this->aterror = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptySA"))); $this->atfeedback = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptySA"))); $this->atansnote = $this->casfunction . 'TEST_FAILED:Empty SA.'; $this->atmark = 0; $this->atvalid = false; return null; } if ('' == trim($this->tanskey)) { $this->aterror = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptyTA"))); $this->atfeedback = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptyTA"))); $this->atansnote = $this->casfunction . 'TEST_FAILED:Empty TA.'; $this->atmark = 0; $this->atvalid = false; return null; } if ($this->processcasoptions) { if (null == $this->atoption or '' == $this->atoption) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => stack_string("AT_MissingOptions"))); $this->atansnote = 'STACKERROR_OPTION.'; $this->atmark = 0; $this->atvalid = false; return null; } else { // Validate with teacher privileges, strict syntax & no automatically adding stars. $ct = new stack_cas_casstring($this->atoption); if (!$ct->get_valid('t', true, 1)) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => '')); $this->atfeedback .= stack_string('AT_InvalidOptions', array('errors' => $ct->get_errors())); $this->atansnote = 'STACKERROR_OPTION.'; $this->atmark = 0; $this->atvalid = false; return null; } } $atopt = $this->atoption; $ta = "[{$this->tanskey},{$atopt}]"; } else { $ta = $this->tanskey; } // Sort out options. if (null === $this->options) { $this->options = new stack_options(); } if (!(null === $this->simp)) { $this->options->set_option('simplify', $this->simp); } $cascommands = array(); $cascommands[] = "STACKSA:{$this->sanskey}"; $cascommands[] = "STACKTA:{$ta}"; $cascommands[] = "result:StackReturn({$this->casfunction}(STACKSA,STACKTA))"; $cts = array(); foreach ($cascommands as $com) { $cs = new stack_cas_casstring($com); $cs->get_valid('t', true, 0); $cts[] = $cs; } $session = new stack_cas_session($cts, $this->options, 0); $session->instantiate(); $this->debuginfo = $session->get_debuginfo(); if ('' != $session->get_errors_key('STACKSA')) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('STACKSA'))); $this->atansnote = $this->casfunction . '_STACKERROR_SAns.'; $this->atmark = 0; $this->atvalid = false; return null; } if ('' != $session->get_errors_key('STACKTA')) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('STACKTA'))); $this->atansnote = $this->casfunction . '_STACKERROR_TAns.'; $this->atmark = 0; $this->atvalid = false; return null; } $sessionvars = $session->get_session(); $result = $sessionvars[2]; if ('' != $result->get_errors()) { $this->aterror = 'TEST_FAILED'; if ('' != trim($result->get_feedback())) { $this->atfeedback = $result->get_feedback(); } else { $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $result->get_errors())); } $this->atansnote = trim($result->get_answernote()); $this->atmark = 0; $this->atvalid = false; return null; } $this->atansnote = trim($result->get_answernote()); // Convert the Maxima string 'true' to PHP true. if ('true' == $result->get_value()) { $this->atmark = 1; } else { $this->atmark = 0; } $this->atfeedback = $result->get_feedback(); $this->atvalid = $result->get_valid(); if ($this->atmark) { return true; } else { return false; } }
public function do_test() { $this->atmark = 1; $anotes = array(); // Note that in casting to an integer we are lucky here. // Non-integer strings get cast to zero, which is invalid anyway.... $atestops = (int) $this->atoption; if (!is_int($atestops) or $atestops <= 0) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => '')); $this->atfeedback .= stack_string('ATNumDecPlaces_OptNotInt', array('opt' => $this->atoption)); $this->atansnote = 'ATNumDecPlaces_STACKERROR_Option.'; $this->atmark = 0; $this->atvalid = false; return null; } $commands = array($this->sanskey, $this->tanskey, (string) $this->atoption); foreach ($commands as $com) { $cs = new stack_cas_casstring($com); if (!$cs->get_valid('t', true, 0)) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => '')); $this->atfeedback .= stack_string('AT_InvalidOptions', array('errors' => $cs->get_errors())); $this->atansnote = 'ATNumDecPlaces_STACKERROR_Option.'; $this->atmark = 0; $this->atvalid = false; return null; } } // Check that the first expression is a floating point number, // with the right number of decimal places. $sans = explode('.', $this->sanskey); if (2 === count($sans)) { if ($atestops != strlen($sans[1])) { $this->atfeedback .= stack_string('ATNumDecPlaces_Wrong_DPs'); $anotes[] = 'ATNumDecPlaces_Wrong_DPs (' . strlen($sans[1]) . ' <> ' . $atestops . ')'; $this->atmark = 0; } else { $anotes[] = 'ATNumDecPlaces_Correct'; } } else { // No '.' found. $this->atfeedback .= stack_string('ATNumDecPlaces_NoDP'); $anotes[] = 'ATNumDecPlaces_NoDP'; $this->atmark = 0; } // Check that the two numbers evaluate to the same value. $cascommands = array(); $cascommands[] = "caschat2:ev({$this->atoption},simp)"; $cascommands[] = "caschat0:ev(float(round(10^caschat2*{$this->sanskey})/10^caschat2),simp)"; $cascommands[] = "caschat1:ev(float(round(10^caschat2*{$this->tanskey})/10^caschat2),simp)"; $cascommands[] = "caschat3:ev(second(ATAlgEquiv(caschat0,caschat1)),simp)"; $cts = array(); foreach ($cascommands as $com) { $cs = new stack_cas_casstring($com); $cs->get_valid('t', true, 0); $cts[] = $cs; } $session = new stack_cas_session($cts, null, 0); $session->instantiate(); if ('' != $session->get_errors_key('caschat0')) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('caschat0'))); $anotes[] = 'ATNumDecPlaces_STACKERROR_SAns'; $this->atansnote = implode('. ', $anotes) . '.'; $this->atmark = 0; $this->atvalid = false; return null; } if ('' != $session->get_errors_key('caschat1')) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('caschat1'))); $anotes[] = 'ATNumDecPlaces_STACKERROR_TAns'; $this->atansnote = implode('. ', $anotes) . '.'; $this->atmark = 0; $this->atvalid = false; return null; } if ('' != $session->get_errors_key('caschat2')) { $this->aterror = 'TEST_FAILED'; $this->atfeedback = stack_string('TEST_FAILED', array('errors' => '')); $this->atfeedback .= stack_string('AT_InvalidOptions', array('errors' => $session->get_errors_key('caschat2'))); $anotes[] = 'ATNumDecPlaces_STACKERROR_Options.'; $this->atansnote = implode('. ', $anotes) . '.'; $this->atmark = 0; $this->atvalid = false; return null; } if ($session->get_value_key('caschat3') == 'true') { // Note, we only want the mark to *stay* at 1. $this->atmark *= 1; $anotes[] = 'ATNumDecPlaces_Equiv'; } else { $this->atmark = 0; $anotes[] = 'ATNumDecPlaces_Not_equiv'; } $this->atansnote = implode('. ', $anotes) . '.'; if ($this->atmark) { return true; } return false; }
/** * Validate any attempts at this question. * * @param array $response the student response to the question. * @param stack_options $options CAS options to use when validating. * @param string $teacheranswer the teachers answer as a string representation of the evaluated expression. * @return stack_input_state represents the current state of the input. */ public function validate_student_response($response, $options, $teacheranswer, $forbiddenkeys) { if (!is_a($options, 'stack_options')) { throw new stack_exception('stack_input: validate_student_response: options not of class stack_options'); } $localoptions = clone $options; // The validation field should always come back through as a single RAW Maxima expression for each input. if (array_key_exists($this->name . '_val', $response)) { $validator = $response[$this->name . '_val']; } else { $validator = ''; } $contents = $this->response_to_contents($response); if (array() == $contents or $this->is_blank_response($contents)) { return new stack_input_state(self::BLANK, array(), '', '', '', '', ''); } // This method actually validates any CAS strings etc. list($valid, $errors, $modifiedcontents) = $this->validate_contents($contents, $forbiddenkeys); // If we can't get a "displayed value" back from the CAS, show the student their original expression. $display = stack_maxima_format_casstring($this->contents_to_maxima($contents)); $interpretedanswer = $this->contents_to_maxima($modifiedcontents); $answer = new stack_cas_casstring($interpretedanswer); $lvarsdisp = ''; // Send the string to the CAS. if ($valid) { if (!$this->get_parameter('sameType')) { $teacheranswer = null; } $singlevarchars = false; if (2 == $this->get_parameter('insertStars', 0)) { $singlevarchars = true; } // Generate an expression from which we extract the list of variables in the student's answer. $lvars = new stack_cas_casstring('ev(listofvars(' . $interpretedanswer . '),simp)'); $lvars->get_valid('t', $this->get_parameter('strictSyntax', true), $this->get_parameter('insertStars', 0), $this->get_parameter('allowWords', '')); $answer->set_cas_validation_casstring($this->name, $this->get_parameter('forbidFloats', false), $this->get_parameter('lowestTerms', false), $singlevarchars, $teacheranswer, $this->get_parameter('allowWords', '')); $localoptions->set_option('simplify', false); $session = new stack_cas_session(array($answer, $lvars), $localoptions, 0); $session->instantiate(); $session = $session->get_session(); $answer = $session[0]; $lvars = $session[1]; $errors = stack_maxima_translate($answer->get_errors()); if ('' != $errors) { $valid = false; } if ('' == $answer->get_value()) { $valid = false; } else { $display = '\\[ ' . $answer->get_display() . ' \\]'; $interpretedanswer = $answer->get_value(); if (!($lvars->get_value() == '[]')) { $lvarsdisp = '\\( ' . $lvars->get_display() . '\\) '; } } } $note = $answer->get_answernote(); // Answers may not contain the ? character. CAS-strings may, but answers may not. // It is very useful for teachers to be able to add in syntax hints. if (!(strpos($interpretedanswer, '?') === false)) { $valid = false; $errors .= stack_string('qm_error'); } if (!$valid) { $status = self::INVALID; } else { if ($this->get_parameter('mustVerify', true) && $validator != $this->contents_to_maxima($contents)) { $status = self::VALID; } else { $status = self::SCORE; } } return new stack_input_state($status, $contents, $interpretedanswer, $display, $errors, $note, $lvarsdisp); }
public function test_ordergreat() { $cs = array('ordergreat(i,j,k)', 'p:matrix([-7],[2],[-3])', 'q:matrix([i],[j],[k])', 'v:dotproduct(p,q)'); foreach ($cs as $s) { $cs = new stack_cas_casstring($s); $cs->get_valid('t'); $s1[] = $cs; } $at1 = new stack_cas_session($s1, null, 0); $at1->instantiate(); // There has been a subtle change to associativity in Maxima 5.37.0. $this->assertEquals('-7\\cdot i+2\\cdot j-3\\cdot k', $at1->get_display_key('v')); }
public static function run_test($test) { // Note: What we would really like to do is the following. // $el = stack_input_factory::make('algebraic', 'sans1', 'x'); // $el->set_parameter('insertStars', 1); // $el->set_parameter('strictSyntax', false); // $el->set_parameter('sameType', false); // $cs = $el->validate_student_response($test->rawstring); // However, we want to pull apart the bits to expose where the various errors occur. $cs = new stack_cas_casstring($test->rawstring); $cs->get_valid('s', false, 1); $cs->set_cas_validation_casstring('sans1', true, true, false, null); $phpvalid = $cs->get_valid(); if ($phpvalid) { // Trim off stack_validate_typeless([..], true, true). $phpcasstring = $cs->get_casstring(); $phpcasstring = substr($phpcasstring, 25); $phpcasstring = substr($phpcasstring, 0, strlen($phpcasstring) - 12); $outputphpcasstring = $phpcasstring; } else { $phpcasstring = ''; $outputphpcasstring = 'N/A...'; } $errors = $cs->get_errors(); $passed = true; if ('php_true' === $test->phpvalid) { $expected = true; } else { $expected = false; } if ($phpvalid != $expected) { $passed = false; $errors .= ' ' . stack_string('phpvalidatemismatch'); } if ($phpvalid && $phpcasstring != $test->phpcasstring) { $passed = false; $errors .= ' ' . stack_maxima_format_casstring($phpcasstring) . ' \\(\\neq \\) ' . stack_maxima_format_casstring($test->phpcasstring); } $casvalid = ''; $caserrors = ''; $casvalue = ''; $casdisplay = ''; if ($cs->get_valid()) { $options = new stack_options(); $options->set_option('simplify', false); $session = new stack_cas_session(array($cs), $options, 0); $session->instantiate(); $session = $session->get_session(); $cs = $session[0]; $caserrors = stack_maxima_translate($cs->get_errors()); $casvalue = stack_maxima_format_casstring($cs->get_value()); if ('cas_true' == $test->casvalid) { $casexpected = true; } else { $casexpected = false; } if ('' == $cs->get_value()) { $casvalid = false; } else { $casvalid = true; } if ($casexpected != $casvalid) { $passed = false; $caserrors .= ' ' . stack_string('casvalidatemismatch'); } $casdisplay = $cs->get_display(); } $answernote = $cs->get_answernote(); if ($answernote != $test->ansnotes) { $passed = false; $errors .= ' ' . stack_string('ansnotemismatch'); } return array($passed, $phpvalid, $phpcasstring, $errors, $casvalid, $caserrors, $casdisplay, $casvalue, $answernote); }
public function test_plot_fail() { $cs = array('a:0', 'p:plot(a*x/0,[x,-2,2],[y,-2,2])'); foreach ($cs as $s) { $cs = new stack_cas_casstring($s); $cs->get_valid('t'); $s1[] = $cs; } $at1 = new stack_cas_session($s1, null, 0); $at1->instantiate(); $this->assertEquals('0', $at1->get_value_key('a')); $this->assertEquals('Division by zero.', trim($at1->get_errors_key('p'))); $this->assertFalse(strpos($at1->get_value_key('p'), 'STACK auto-generated plot of 0 with parameters')); }
public function test_remove_comment_fail() { $at1 = new stack_cas_keyval("a:1\n /* This is a comment \n b:2\n */\n c:3", null, 123, 's', true, 0); $this->assertTrue($at1->get_valid()); $a3 = array('a:1', 'c:4'); $s3 = array(); foreach ($a3 as $s) { $s3[] = new stack_cas_casstring($s); } $cs3 = new stack_cas_session($s3, null, 123); $cs3->instantiate(); $at1->instantiate(); // This looks strange, but the cache layer gives inconsistent results if the first // of these populates the cache, and the second one uses it. $this->assertNotEquals($cs3->get_session(), $at1->get_session()->get_session()); }