Parent Directory
|
Revision Log
Many changes to this file. I've fixed multi_cmp which will check a comma separated string of answers. I have commented out many other routines which do not appear to be in use.
1 # This file is PGcomplexmacros.pl 2 # This includes the subroutines for the ANS macros, that 3 # is, macros allowing a more flexible answer checking 4 #################################################################### 5 # Copyright @ 1995-2002 The WeBWorK Team 6 # All Rights Reserved 7 #################################################################### 8 #$Id$ 9 10 11 =head1 NAME 12 13 Macros for complex numbers for the PG language 14 15 =head1 SYNPOSIS 16 17 18 19 =head1 DESCRIPTION 20 21 =cut 22 23 24 BEGIN{ 25 be_strict(); 26 27 } 28 29 30 31 sub _PGcomplexmacros_init { 32 } 33 # export functions from Complex1. 34 35 foreach my $f (@Complex1::EXPORT) { 36 # #PG_restricted_eval("\*$f = \*Complex1::$f"); # this is too clever -- 37 # the original subroutines are destroyed 38 next if $f eq 'sqrt'; #exporting the square root caused conflicts with the standard version 39 # You can still use Complex1::sqrt to take square root of complex numbers 40 next if $f eq 'log'; #exporting loq caused conflicts with the standard version 41 # You can still use Complex1::log to take square root of complex numbers 42 43 my $string = qq{ 44 sub main::$f { 45 &Complex1::$f; 46 } 47 }; 48 PG_restricted_eval($string); 49 } 50 51 52 # You need to add 53 # sub i(); # to your problem or else to dangerousMacros.pl 54 # in order to use expressions such as 1 +3*i; 55 # Without this prototype you would have to write 1+3*i(); 56 # The prototype has to be defined at compile time, but dangerousMacros.pl is complied first. 57 #Complex1::display_format('cartesian'); 58 59 # number format used frequently in strict prefilters 60 my $number = '([+-]?)(?=\d|\.\d)\d*(\.\d*)?(E([+-]?\d+))?'; 61 62 63 64 65 =head4 cplx_cmp 66 67 This subroutine compares complex numbers. 68 Available prefilters include: 69 each of these are called by cplx_cmp( answer, mode => '(prefilter name)' ) 70 'std' The standard comparison method for complex numbers. This option it the default 71 and works with any combination of cartesian numbers, polar numbers, and 72 functions. The default display method is cartesian, for all methods, but if 73 the student answer is polar, even in part, then their answer will be displayed 74 that way. 75 'strict_polar' This is still under developement. The idea is to check to make sure that there 76 only a single term in front of the e and after it... but the method does not 77 check to make sure that the i is in the exponent, nor does it handle cases 78 where the polar has e** coefficients. 79 'strict_num_cartesian' This prefilter allows only complex numbers of the form "a+bi" where a and b 80 are strictly numbers. 81 'strict_num_polar' This prefilter allows only complex numbers of the form "ae^(bi)" where a and b 82 are strictly numbers. 83 'strict' This is a combination of strict_num_cartesian and strict_num_polar, so it 84 allows complex numbers of either the form "a+bi" or "ae^(bi)" where a and b 85 are strictly numbers. 86 87 88 =cut 89 90 sub cplx_cmp { 91 my $correctAnswer = shift; 92 my %cplx_params = @_; 93 94 assign_option_aliases( \%cplx_params, 95 'reltol' => 'relTol', 96 ); 97 set_default_options(\%cplx_params, 98 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative', 99 # default mode should be relative, to obtain this tol must not be defined 100 'tolerance' => $main::numAbsTolDefault, 101 'relTol' => $main::numRelPercentTolDefault, 102 'zeroLevel' => $main::numZeroLevelDefault, 103 'zeroLevelTol' => $main::numZeroLevelTolDefault, 104 'format' => $main::numFormatDefault, 105 'debug' => 0, 106 'mode' => 'std', 107 'strings' => undef, 108 ); 109 my $format = $cplx_params{'format'}; 110 my $mode = $cplx_params{'mode'}; 111 112 if( $cplx_params{tolType} eq 'relative' ) { 113 $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'}; 114 } 115 116 my $formattedCorrectAnswer; 117 my $correct_num_answer; 118 my $corrAnswerIsString = 0; 119 120 121 if (defined($cplx_params{strings}) && $cplx_params{strings}) { 122 my $legalString = ''; 123 my @legalStrings = @{$cplx_params{strings}}; 124 $correct_num_answer = $correctAnswer; 125 $formattedCorrectAnswer = $correctAnswer; 126 foreach $legalString (@legalStrings) { 127 if ( uc($correctAnswer) eq uc($legalString) ) { 128 $corrAnswerIsString = 1; 129 130 last; 131 } 132 } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric 133 } else { 134 $correct_num_answer = $correctAnswer; 135 $formattedCorrectAnswer = prfmt( $correctAnswer, $cplx_params{'format'} ); 136 } 137 $correct_num_answer = math_constants($correct_num_answer); 138 139 my $PGanswerMessage = ''; 140 141 my ($inVal,$correctVal,$PG_eval_errors,$PG_full_error_report); 142 143 if (defined($correct_num_answer) && $correct_num_answer =~ /\S/ && $corrAnswerIsString == 0 ) { 144 ($correctVal, $PG_eval_errors,$PG_full_error_report) = PG_answer_eval($correct_num_answer); 145 } else { # case of a string answer 146 $PG_eval_errors = ' '; 147 $correctVal = $correctAnswer; 148 } 149 150 ######################################################################## 151 $correctVal = $correct_num_answer; 152 $correctVal = cplx( $correctVal, 0 ) unless ref($correctVal) =~/^Complex?/ || $corrAnswerIsString == 1; 153 154 #construct the answer evaluator 155 my $answer_evaluator = new AnswerEvaluator; 156 $answer_evaluator->{debug} = $cplx_params{debug}; 157 $answer_evaluator->ans_hash( 158 correct_ans => $correctVal, 159 type => "cplx_cmp", 160 tolerance => $cplx_params{tolerance}, 161 tolType => 'absolute', # $cplx_params{tolType}, 162 original_correct_ans => $formattedCorrectAnswer, 163 answerIsString => $corrAnswerIsString, 164 answer_form => 'cartesian', 165 ); 166 my ($in, $formattedSubmittedAnswer); 167 $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift; 168 $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;} 169 ); 170 if (defined($cplx_params{strings}) && $cplx_params{strings}) { 171 $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params); 172 } 173 174 $answer_evaluator->install_pre_filter(\&check_syntax); 175 $answer_evaluator->install_pre_filter(\&math_constants); 176 $answer_evaluator->install_pre_filter(\&cplx_constants); 177 $answer_evaluator->install_pre_filter(\&check_for_polar); 178 if ($mode eq 'std') { 179 # do nothing 180 } elsif ($mode eq 'strict_polar') { 181 $answer_evaluator->install_pre_filter(\&is_a_polar); 182 } elsif ($mode eq 'strict_num_cartesian') { 183 $answer_evaluator->install_pre_filter(\&is_a_numeric_cartesian); 184 } elsif ($mode eq 'strict_num_polar') { 185 $answer_evaluator->install_pre_filter(\&is_a_numeric_polar); 186 } elsif ($mode eq 'strict') { 187 $answer_evaluator->install_pre_filter(\&is_a_numeric_complex); 188 } else { 189 $PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.'; 190 $formattedSubmittedAnswer = $in; 191 } 192 193 if ($corrAnswerIsString == 0 ){ # avoiding running compare_cplx when correct answer is a string. 194 $answer_evaluator->install_evaluator(\&compare_cplx, %cplx_params); 195 } 196 197 198 ############################################################################### 199 # We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's 200 # can be displayed in the answer message. This may still cause a few anomolies when strings are used 201 # 202 ############################################################################### 203 204 $answer_evaluator->install_post_filter(\&fix_answers_for_display); 205 $answer_evaluator->install_post_filter(\&fix_for_polar_display); 206 207 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; 208 return $rh_ans unless $rh_ans->catch_error('EVAL'); 209 $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message}; 210 $rh_ans->clear_error('EVAL'); } ); 211 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } ); 212 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } ); 213 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } ); 214 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } ); 215 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('STRING'); } ); 216 $answer_evaluator; 217 } 218 219 220 221 # compares two complex numbers by comparing their real and imaginary parts 222 sub compare_cplx { 223 my ($rh_ans, %options) = @_; 224 my ($inVal,$PG_eval_errors,$PG_full_error_report) = PG_answer_eval($rh_ans->{student_ans}); 225 226 if ($PG_eval_errors) { 227 $rh_ans->throw_error('EVAL','There is a syntax error in your answer'); 228 $rh_ans->{ans_message} = clean_up_error_msg($PG_eval_errors); 229 return $rh_ans; 230 } else { 231 $rh_ans->{student_ans} = prfmt($inVal,$options{format}); 232 } 233 234 $inVal = cplx($inVal,0) unless ref($inVal) =~/Complex/; 235 my $permitted_error_Re; 236 my $permitted_error_Im; 237 if ($rh_ans->{tolType} eq 'absolute') { 238 $permitted_error_Re = $rh_ans->{tolerance}; 239 $permitted_error_Im = $rh_ans->{tolerance}; 240 } 241 elsif ( abs($rh_ans->{correct_ans}) <= $options{zeroLevel}) { 242 $permitted_error_Re = $options{zeroLevelTol}; ## want $tol to be non zero 243 $permitted_error_Im = $options{zeroLevelTol}; ## want $tol to be non zero 244 } 245 else { 246 $permitted_error_Re = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Re); 247 $permitted_error_Im = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Im); 248 249 } 250 251 $rh_ans->{score} = 1 if ( abs( $rh_ans->{correct_ans}->Complex::Re - $inVal->Complex::Re) <= 252 $permitted_error_Re && abs($rh_ans->{correct_ans}->Complex::Im - $inVal->Complex::Im )<= $permitted_error_Im ); 253 254 $rh_ans; 255 } 256 257 =head4 multi_cmp 258 259 260 Checks a comma separated string of items against an array of evaluators. 261 For example this is useful for checking all of the complex roots of an equation. 262 Each student answer must be evaluated as correct by a DISTINCT answer evalutor. 263 264 This answer checker will only work reliably if each answer checker corresponds 265 to a distinct correct answer. For example if one answer checker requires 266 any positive number, and the second requires the answer 1, then 1,2 might 267 be judged incorrect since 1, satisifes the first answer checker, but 2 doesn't 268 satisfy the second. 2,1 would work however. Avoid this type of use!! 269 270 Including backtracking to fit the answers as best possible to each answer evaluator 271 in the best possible way, is beyond the ambitions of this evaluator. 272 273 274 =cut 275 276 sub multi_cmp { 277 my $ra_answer_evaluators = shift; # array of evaluators 278 my %options = @_; 279 my @answer_evaluators = @{$ra_answer_evaluators}; 280 my $backup_ans_eval = $answer_evaluators[0]; 281 my $multi_ans_evaluator = new AnswerEvaluator; 282 $multi_ans_evaluator->install_evaluator( sub { 283 my $rh_ans = shift; 284 my @student_answers = split/\s*,\s*/,$rh_ans->{student_ans}; 285 my @evaluated_ans_hashes = (); 286 for ( my $j=0; $j<@student_answers; $j++ ) { 287 # find an answer evaluator which marks this answer correct. 288 my $student_ans = $student_answers[$j]; 289 my $temp_hash; 290 for ( my $i=0; $i<@answer_evaluators; $i++ ) { 291 my $evaluator = $answer_evaluators[$i]; 292 $temp_hash = new AnswerHash; # make a copy of the answer hash resulting from the evaluation 293 %$temp_hash = %{$evaluator->evaluate($student_ans)}; 294 if (($temp_hash->{score} == 1)) { 295 # save evaluated answer 296 push @evaluated_ans_hashes, $temp_hash; 297 # remove answer evaluator and check the next answer 298 splice(@answer_evaluators,$i,1); 299 last; 300 } 301 } 302 # if we exit the loop without finding a correct evaluation: 303 # make sure every answer is evaluated, even extra answers for which 304 # there will be no answer evaluators left. 305 if (not defined($temp_hash) ) { # make sure every answer is evaluated, even extra answers. 306 my $evaluator = $backup_ans_eval; 307 $temp_hash = new AnswerHash; # make a copy of the answer hash resulting from the evaluation 308 %$temp_hash = %{$evaluator->evaluate($student_ans)}; 309 $temp_hash->{score} =0; # this was an extra answer -- clearly incorrect 310 $temp_hash->{correct_ans} = "too many answers"; 311 } 312 # now make sure that even answers which 313 # don't never evaluate correctly are still recorded in the list 314 if ( $temp_hash->{score} <1) { 315 push @evaluated_ans_hashes, $temp_hash; 316 } 317 318 319 } 320 # construct the final answer hash 321 my $rh_ans_out = shift @evaluated_ans_hashes; 322 while (@evaluated_ans_hashes) { 323 my $temp_hash = shift @evaluated_ans_hashes; 324 $rh_ans_out =$rh_ans_out->AND($temp_hash); 325 } 326 $rh_ans_out->{student_ans} = $rh_ans->{student_ans}; 327 $rh_ans_out->{score}=0 unless @{$ra_answer_evaluators} == @student_answers; # require the correct number of answers 328 $rh_ans_out; 329 }); 330 $multi_ans_evaluator; 331 } 332 # sub multi_cmp_old{ 333 # my $pointer = shift; # array of evaluators 334 # my %options = @_; 335 # my @evals = @{$pointer}; 336 # my $answer_evaluator = new AnswerEvaluator; 337 # $answer_evaluator->install_evaluator( sub { 338 # my $rh_ans = shift; 339 # $rh_ans->{score} = 1;#in order to use AND below, score must be 1 340 # $rh_ans->{preview_text_string} = "";#needs to be initialized to prevent warnings 341 # my @student_answers = split/,/,$rh_ans->{student_ans}; 342 # foreach my $eval ( @evals ){ 343 # my $temp_eval = new AnswerEvaluator; 344 # my $temp_hash = $temp_eval->ans_hash; 345 # $temp_hash->{preview_text_string} = "";#needs to be initialized to prevent warnings 346 # #FIXME I believe there is a logic problem here. 347 # # If each answer entered is judged correct by ONE answer evaluator 348 # # then the answer is correct, but for example if you enter a correct 349 # # root to an equation twice each answer will be judged correct and 350 # # and the whole question correct, even though the answer omits 351 # # the second root. 352 # foreach my $temp ( @student_answers ){ 353 # $eval->evaluate($temp); 354 # $temp = $eval->ans_hash->{student_ans} unless $eval->ans_hash->{student_ans}=~ /you/i; 355 # $temp_hash = $temp_hash->OR( $eval->ans_hash ); 356 # if( $eval->ans_hash->{score} == 1){ last; } 357 # } 358 # $rh_ans = $rh_ans->AND( $temp_hash ); 359 # } 360 # #$rh_ans->{correct_ans} =~ s/No correct answer specified (OR|AND) //g; 361 # $rh_ans->{student_ans} = ""; 362 # foreach( @student_answers ){ $rh_ans->{student_ans} .= "$_, "; } 363 # $rh_ans->{student_ans} =~ s/, \Z//; 364 # if( scalar(@evals) != scalar(@student_answers) ){ $rh_ans->{score} = 0; }#wrong number of answers makes answer wrong 365 # $rh_ans; }); 366 # $answer_evaluator; 367 # } 368 # this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05 369 # sub mult_cmp{ 370 # my $answer = shift; 371 # my @answers = @{$answer} if ref($answer) eq 'ARRAY'; 372 # my %mult_params = @_; 373 # my @keys = qw ( tolerance tolType format mode zeroLevel zeroLevelTol debug ); 374 # my @correctVal; 375 # my $formattedCorrectAnswer; 376 # my @correct_num_answer; 377 # my ($PG_eval_errors,$PG_full_error_report); 378 # assign_option_aliases( \%mult_params, 379 # 'reltol' => 'relTol', 380 # ); 381 # set_default_options(\%mult_params, 382 # 'tolType' => (defined($mult_params{tol}) ) ? 'absolute' : 'relative', 383 # # default mode should be relative, to obtain this tol must not be defined 384 # 'tolerance' => $main::numAbsTolDefault, 385 # 'relTol' => $main::numRelPercentTolDefault, 386 # 'zeroLevel' => $main::numZeroLevelDefault, 387 # 'zeroLevelTol' => $main::numZeroLevelTolDefault, 388 # 'format' => $main::numFormatDefault, 389 # 'debug' => 0, 390 # 'mode' => 'std', 391 # 'compare' => 'num', 392 # ); 393 # my $format = $mult_params{'format'}; 394 # my $mode = $mult_params{'mode'}; 395 # 396 # 397 # if( $mult_params{tolType} eq 'relative' ) { 398 # $mult_params{'tolerance'} = .01*$mult_params{'relTol'}; 399 # } 400 # 401 # if( $mult_params{ 'compare' } eq 'cplx' ){ 402 # foreach( @answers ) 403 # { 404 # $_ = cplx( $_, 0 ) unless ref($_) =~/Complex/; 405 # } 406 # } 407 # 408 # my $corrAnswerIsString = 0; 409 # 410 # for( my $k = 0; $k < @answers; $k++ ){ 411 # if (defined($mult_params{strings}) && $mult_params{strings}) { 412 # my $legalString = ''; 413 # my @legalStrings = @{$mult_params{strings}}; 414 # $correct_num_answer[$k] = $answers[$k]; 415 # $formattedCorrectAnswer .= $answers[$k] . ","; 416 # foreach $legalString (@legalStrings) { 417 # if ( uc($answers[$k]) eq uc($legalString) ) { 418 # $corrAnswerIsString = 1; 419 # 420 # last; 421 # } 422 # } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric 423 # } else { 424 # $correct_num_answer[$k] = $answers[$k]; 425 # $formattedCorrectAnswer .= prfmt( $answers[$k], $mult_params{'format'} ) . ", "; 426 # } 427 # $correct_num_answer[$k] = math_constants($correct_num_answer[$k]); 428 # my $PGanswerMessage = ''; 429 # 430 # 431 # if (defined($correct_num_answer[$k]) && $correct_num_answer[$k] =~ /\S/ && $corrAnswerIsString == 0 ) { 432 # ($correctVal[$k], $PG_eval_errors,$PG_full_error_report) = 433 # PG_answer_eval($correct_num_answer[$k]); 434 # } else { # case of a string answer 435 # $PG_eval_errors = ' '; 436 # $correctVal[$k] = $answers[$k]; 437 # } 438 # 439 # #if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal[$k])) && $corrAnswerIsString == 0)) { 440 # ##error message from eval or above 441 # #warn "Error in 'correct' answer: $PG_eval_errors<br> 442 # #The answer $answers[$k] evaluates to $correctVal[$k], 443 # #which cannot be interpreted as a number. "; 444 # 445 # #} 446 # ######################################################################## 447 # $correctVal[$k] = $correct_num_answer[$k]; 448 # } 449 # $formattedCorrectAnswer =~ s/, \Z//; 450 # 451 # #construct the answer evaluator 452 # 453 # my $answer_evaluator = new AnswerEvaluator; 454 # 455 # 456 # $answer_evaluator->{debug} = $mult_params{debug}; 457 # $answer_evaluator->ans_hash( 458 # correct_ans => [@correctVal], 459 # type => "${mode}_number", 460 # tolerance => $mult_params{tolerance}, 461 # tolType => 'absolute', # $mult_params{tolType}, 462 # original_correct_ans => $formattedCorrectAnswer, 463 # answerIsString => $corrAnswerIsString, 464 # answer_form => 'cartesian', 465 # ); 466 # my ($in, $formattedSubmittedAnswer); 467 # $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift; 468 # $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;} 469 # ); 470 # if (defined($mult_params{strings}) && $mult_params{strings}) { 471 # $answer_evaluator->install_pre_filter(\&check_strings, %mult_params); 472 # } 473 # 474 # $answer_evaluator -> install_pre_filter( \&mult_prefilters, %mult_params ); 475 # $answer_evaluator->install_pre_filter( sub{my $rh_ans = shift; $rh_ans->{original_student_ans} = $rh_ans->{student_ans};$rh_ans;}); 476 # 477 # if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string. 478 # $answer_evaluator->install_evaluator(\&compare_mult, %mult_params); 479 # } 480 # 481 # 482 # ############################################################################### 483 # # We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's 484 # # can be displayed in the answer message. This may still cause a few anomolies when strings are used 485 # # 486 # ############################################################################### 487 # $answer_evaluator->install_post_filter( sub{my $rh_ans = shift; $rh_ans->{student_ans} = $rh_ans->{original_student_ans};$rh_ans;}); 488 # $answer_evaluator->install_post_filter(\&fix_answers_for_display); 489 # $answer_evaluator->install_post_filter(\&fix_for_polar_display); 490 # 491 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; 492 # return $rh_ans unless $rh_ans->catch_error('EVAL'); 493 # $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message}; 494 # $rh_ans->clear_error('EVAL'); } ); 495 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } ); 496 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } ); 497 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } ); 498 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } ); 499 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('STRING'); } ); 500 # $answer_evaluator; 501 # } 502 503 # sub mult_prefilters{ 504 # my ($rh_ans, %options) = @_; 505 # my @student_answers = split/,/,$rh_ans->{student_ans}; 506 # foreach( @student_answers ){ 507 # $rh_ans->{student_ans} = $_; 508 # $rh_ans = &check_syntax( $rh_ans ); 509 # $rh_ans = &math_constants( $rh_ans ); 510 # if( $options{compare} eq 'cplx' ){ 511 # $rh_ans = &cplx_constants( $rh_ans ); 512 # #$rh_ans = &check_for_polar( $rh_ans ); 513 # } 514 # if ( $options{mode} eq 'std') { 515 # # do nothing 516 # } elsif ($options{mode} eq 'strict_polar') { 517 # $rh_ans = &is_a_polar( $rh_ans ); 518 # } elsif ($options{mode} eq 'strict_num_cartesian') { 519 # $rh_ans = &is_a_numeric_cartesian( $rh_ans ); 520 # } elsif ($options{mode} eq 'strict_num_polar') { 521 # $rh_ans = &is_a_numeric_polar( $rh_ans ); 522 # } elsif ($options{mode} eq 'strict') { 523 # $rh_ans = &is_a_numeric_complex( $rh_ans ); 524 # } elsif ($options{mode} eq 'arith') { 525 # $rh_ans = &is_an_arithmetic_expression( $rh_ans ); 526 # } elsif ($options{mode} eq 'frac') { 527 # $rh_ans = &is_a_fraction( $rh_ans ); 528 # 529 # } else { 530 # #$PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.'; 531 # #$formattedSubmittedAnswer = $in; 532 # } 533 # $_ = $rh_ans->{student_ans}; 534 # } 535 # my $ans_string; 536 # foreach( @student_answers ) 537 # { 538 # $ans_string .= ", $_"; 539 # } 540 # $ans_string =~ s/\A,//; 541 # $rh_ans->{student_ans} = $ans_string; 542 # $rh_ans; 543 # } 544 545 # sub polar{ 546 # my $z = shift; 547 # my %options = @_; 548 # my $r = rho($z); 549 # my $theta = $z->theta; 550 # my $r_format = ':%0.3f'; 551 # my $theta_format = ':%0.3f'; 552 # $r_format=":" . $options{r_format} if defined($options{r_format}); 553 # $theta_format = ":" . $options{theta_format} if defined($options{theta_format}); 554 # "{$r$r_format} e^{i {$theta$theta_format}}"; 555 # 556 # } 557 558 # compares two complex numbers by comparing their real and imaginary parts 559 # sub compare_mult { 560 # my ($rh_ans, %options) = @_; 561 # my @student_answers = split/,/,$rh_ans->{student_ans}; 562 # my @correct_answers = @{$rh_ans->{correct_ans}}; 563 # my $one_correct = 1/@correct_answers; 564 # my $temp_score = 0; 565 # foreach( @correct_answers ){ 566 # $rh_ans->{correct_ans} = $_; 567 # foreach( @student_answers ){ 568 # $rh_ans->{student_ans} = $_; 569 # if( $options{compare} eq 'cplx' ){ 570 # $rh_ans = &compare_cplx( $rh_ans, %options); 571 # }else{ 572 # $rh_ans = &compare_numbers( $rh_ans, %options); 573 # } 574 # if( $rh_ans->{score} == 1 ) 575 # { 576 # $temp_score += $one_correct; 577 # $rh_ans->{score} = 0; 578 # last; 579 # } 580 # } 581 # } 582 # $rh_ans->{score} = $temp_score; 583 # $rh_ans; 584 # 585 # } 586 587 588 589 # Output is text displaying the complex numver in "e to the i theta" form. The 590 # formats for the argument theta is determined by the option C<theta_format> and the 591 # format for the modulus is determined by the C<r_format> option. 592 593 #this basically just checks for "e^" which unfortunately will show something like (e^4)*i as a polar, this should be changed 594 sub check_for_polar{ 595 596 my($in,%options) = @_; 597 my $rh_ans; 598 my $process_ans_hash = ( ref( $in ) eq 'AnswerHash' ) ? 1 : 0 ; 599 if ($process_ans_hash) { 600 $rh_ans = $in; 601 $in = $rh_ans->{student_ans}; 602 } 603 # The code fragment above allows this filter to be used when the input is simply a string 604 # as well as when the input is an AnswerHash, and options. 605 if( $in =~ /2.71828182845905\*\*/ ){ 606 $rh_ans->{answer_form} = 'polar'; 607 } 608 $rh_ans; 609 } 610 611 612 613 sub cplx_constants { 614 my($in,%options) = @_; 615 my $rh_ans; 616 my $process_ans_hash = ( ref( $in ) eq 'AnswerHash' ) ? 1 : 0 ; 617 if ($process_ans_hash) { 618 $rh_ans = $in; 619 $in = $rh_ans->{student_ans}; 620 } 621 # The code fragment above allows this filter to be used when the input is simply a string 622 # as well as when the input is an AnswerHash, and options. 623 $in =~ s/\bi\b/(i)/g; #try to keep -i being recognized as a file reference 624 # and recognized as a function whose output is an imaginary number 625 626 if ($process_ans_hash) { 627 $rh_ans->{student_ans}=$in; 628 return $rh_ans; 629 } else { 630 return $in; 631 } 632 } 633 634 ## allows only for numbers of the form a+bi and ae^(bi), where a and b are strict numbers 635 sub is_a_numeric_complex { 636 my ($num,%options) = @_; 637 my $process_ans_hash = ( ref( $num ) eq 'AnswerHash' ) ? 1 : 0 ; 638 my ($rh_ans); 639 if ($process_ans_hash) { 640 $rh_ans = $num; 641 $num = $rh_ans->{student_ans}; 642 } 643 644 my $is_a_number = 0; 645 return $is_a_number unless defined($num); 646 $num =~ s/^\s*//; ## remove initial spaces 647 $num =~ s/\s*$//; ## remove trailing spaces 648 649 if ($num =~ 650 651 /^($number[+,-]?($number\*\(i\)|\(i\)|\(i\)\*$number)|($number\*\(i\)|-?\(i\)|-?\(i\)\*$number)([+,-]$number)?|($number\*)?2.71828182845905\*\*\(($number\*\(i\)|\(i\)\*$number|i|-\(i\))\)|$number)$/){ 652 $is_a_number = 1; 653 } 654 655 if ($process_ans_hash) { 656 if ($is_a_number == 1 ) { 657 $rh_ans->{student_ans}=$num; 658 return $rh_ans; 659 } else { 660 $rh_ans->{student_ans} = "Incorrect number format: You must enter a numeric complex, e.g. a+bi 661 or a*e^(bi)"; 662 $rh_ans->throw_error('COMPLEX', 'You must enter a number, e.g. -6, 5.3, or 6.12E-3'); 663 return $rh_ans; 664 } 665 } else { 666 return $is_a_number; 667 } 668 } 669 670 ## allows only for the form a + bi, where a and b are strict numbers 671 sub is_a_numeric_cartesian { 672 my ($num,%options) = @_; 673 my $process_ans_hash = ( ref( $num ) eq 'AnswerHash' ) ? 1 : 0 ; 674 my ($rh_ans); 675 if ($process_ans_hash) { 676 $rh_ans = $num; 677 $num = $rh_ans->{student_ans}; 678 } 679 680 my $is_a_number = 0; 681 return $is_a_number unless defined($num); 682 $num =~ s/^\s*//; ## remove initial spaces 683 $num =~ s/\s*$//; ## remove trailing spaces 684 685 if ($num =~ 686 687 /^($number[+,-]?($number\*\(i\)|\(i\)|\(i\)\*$number)|($number\*\(i\)|-?\(i\)|-?\(i\)\*$number)([+,-]$number)?|$number)$/){ 688 $is_a_number = 1; 689 } 690 691 if ($process_ans_hash) { 692 if ($is_a_number == 1 ) { 693 $rh_ans->{student_ans}=$num; 694 return $rh_ans; 695 } else { 696 $rh_ans->{student_ans} = "Incorrect number format: You must enter a numeric cartesian, e.g. a+bi"; 697 $rh_ans->throw_error('CARTESIAN', 'You must enter a number, e.g. -6, 5.3, or 6.12E-3'); 698 return $rh_ans; 699 } 700 } else { 701 return $is_a_number; 702 } 703 } 704 705 ## allows only for the form ae^(bi), where a and b are strict numbers 706 sub is_a_numeric_polar { 707 my ($num,%options) = @_; 708 my $process_ans_hash = ( ref( $num ) eq 'AnswerHash' ) ? 1 : 0 ; 709 my ($rh_ans); 710 if ($process_ans_hash) { 711 $rh_ans = $num; 712 $num = $rh_ans->{student_ans}; 713 } 714 715 my $is_a_number = 0; 716 return $is_a_number unless defined($num); 717 $num =~ s/^\s*//; ## remove initial spaces 718 $num =~ s/\s*$//; ## remove trailing spaces 719 if ($num =~ 720 /^($number|($number\*)?2.71828182845905\*\*\(($number\*\(i\)|\(i\)\*$number|i|-\(i\))\))$/){ 721 $is_a_number = 1; 722 } 723 724 if ($process_ans_hash) { 725 if ($is_a_number == 1 ) { 726 $rh_ans->{student_ans}=$num; 727 return $rh_ans; 728 } else { 729 $rh_ans->{student_ans} = "Incorrect number format: You must enter a numeric polar, e.g. a*e^(bi)"; 730 $rh_ans->throw_error('POLAR', 'You must enter a number, e.g. -6, 5.3, or 6.12E-3'); 731 return $rh_ans; 732 } 733 } else { 734 return $is_a_number; 735 } 736 } 737 738 #this subroutine mearly captures what is before and after the "e**" it does not verify that the "i" is there, or in the 739 #exponent this must eventually be addresed 740 sub is_a_polar { 741 my ($num,%options) = @_; 742 my $process_ans_hash = ( ref( $num ) eq 'AnswerHash' ) ? 1 : 0 ; 743 my ($rh_ans); 744 if ($process_ans_hash) { 745 $rh_ans = $num; 746 $num = $rh_ans->{student_ans}; 747 } 748 749 my $is_a_number = 0; 750 return $is_a_number unless defined($num); 751 $num =~ s/^\s*//; ## remove initial spaces 752 $num =~ s/\s*$//; ## remove trailing spaces 753 $num =~ /^(.*)\*2.71828182845905\*\*(.*)/; 754 #warn "rho: ", $1; 755 #warn "theta: ", $2; 756 if( defined( $1 ) ){ 757 if( &single_term( $1 ) && &single_term( $2 ) ) 758 { 759 $is_a_number = 1; 760 } 761 } 762 if ($process_ans_hash) { 763 if ($is_a_number == 1 ) { 764 $rh_ans->{student_ans}=$num; 765 return $rh_ans; 766 } else { 767 $rh_ans->{student_ans} = "Incorrect number format: You must enter a polar, e.g. a*e^(bi)"; 768 $rh_ans->throw_error('POLAR', 'You must enter a number, e.g. -6, 5.3, or 6.12E-3'); 769 return $rh_ans; 770 } 771 } else { 772 return $is_a_number; 773 } 774 } 775 776 =head4 single_term() 777 This subroutine takes in a string, which is a mathematical expresion, and determines whether or not 778 it is a single term. This is accoplished using a stack. Open parenthesis pluses and minuses are all 779 added onto the stack, and when a closed parenthesis is reached, the stack is popped untill the open 780 parenthesis is found. If the original was a single term, the stack should be empty after 781 evaluation. If there is anything left ( + or - ) then false is returned. 782 Of course, the unary operator "-" must be handled... if it is a unary operator, and not a regular - 783 the only place it could occur unambiguously without being surrounded by parenthesis, is the very 784 first position. So that case is checked before the loop begins. 785 =cut 786 787 sub single_term{ 788 my $term = shift; 789 my @stack; 790 $term = reverse $term; 791 if( length $term >= 1 ) 792 { 793 my $temp = chop $term; 794 if( $temp ne "-" ){ $term .= $temp; } 795 } 796 while( length $term >= 1 ){ 797 my $character = chop $term; 798 if( $character eq "+" || $character eq "-" || $character eq "(" ){ 799 push @stack, $character; 800 }elsif( $character eq ")" ){ 801 while( pop @stack ne "(" ){} 802 } 803 804 } 805 if( scalar @stack == 0 ){ return 1;}else{ return 0;} 806 } 807 808 # changes default to display as a polar 809 sub fix_for_polar_display{ 810 my ($rh_ans, %options) = @_; 811 if( ref( $rh_ans->{student_ans} ) =~ /Complex/ && $rh_ans->{answer_form} eq 'polar' ){ 812 $rh_ans->{student_ans}->display_format( 'polar'); 813 ## these lines of code have the polar displayed as re^(theta) instead of [rho,theta] 814 $rh_ans->{student_ans} =~ s/,/*e^\(/; 815 $rh_ans->{student_ans} =~ s/\[//; 816 $rh_ans->{student_ans} =~ s/\]/i\)/; 817 } 818 $rh_ans; 819 } 820 821 # this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05 822 # sub cplx_cmp2 { 823 # my $correctAnswer = shift; 824 # my %cplx_params = @_; 825 # my @keys = qw ( correctAnswer tolerance tolType format mode zeroLevel zeroLevelTol debug ); 826 # assign_option_aliases( \%cplx_params, 827 # 'reltol' => 'relTol', 828 # ); 829 # set_default_options(\%cplx_params, 830 # 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative', 831 # # default mode should be relative, to obtain this tol must not be defined 832 # 'tolerance' => $main::numAbsTolDefault, 833 # 'relTol' => $main::numRelPercentTolDefault, 834 # 'zeroLevel' => $main::numZeroLevelDefault, 835 # 'zeroLevelTol' => $main::numZeroLevelTolDefault, 836 # 'format' => $main::numFormatDefault, 837 # 'debug' => 0, 838 # 'mode' => 'std', 839 # 840 # ); 841 # $correctAnswer = cplx($correctAnswer,0) unless ref($correctAnswer) =~/Complex/; 842 # my $format = $cplx_params{'format'}; 843 # my $mode = $cplx_params{'mode'}; 844 # 845 # if( $cplx_params{tolType} eq 'relative' ) { 846 # $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'}; 847 # } 848 # 849 # my $formattedCorrectAnswer; 850 # my $correct_num_answer; 851 # my $corrAnswerIsString = 0; 852 # 853 # 854 # if (defined($cplx_params{strings}) && $cplx_params{strings}) { 855 # my $legalString = ''; 856 # my @legalStrings = @{$cplx_params{strings}}; 857 # $correct_num_answer = $correctAnswer; 858 # $formattedCorrectAnswer = $correctAnswer; 859 # foreach $legalString (@legalStrings) { 860 # if ( uc($correctAnswer) eq uc($legalString) ) { 861 # $corrAnswerIsString = 1; 862 # 863 # last; 864 # } 865 # } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric 866 # } else { 867 # $correct_num_answer = $correctAnswer; 868 # $formattedCorrectAnswer = prfmt( $correctAnswer, $cplx_params{'format'} ); 869 # } 870 # $correct_num_answer = math_constants($correct_num_answer); 871 # my $PGanswerMessage = ''; 872 # 873 # my ($inVal,$correctVal,$PG_eval_errors,$PG_full_error_report); 874 # 875 # if (defined($correct_num_answer) && $correct_num_answer =~ /\S/ && $corrAnswerIsString == 0 ) { 876 # ($correctVal, $PG_eval_errors,$PG_full_error_report) = PG_answer_eval($correct_num_answer); 877 # } else { # case of a string answer 878 # $PG_eval_errors = ' '; 879 # $correctVal = $correctAnswer; 880 # } 881 # 882 # if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal)) && $corrAnswerIsString == 0)) { 883 # ##error message from eval or above 884 # warn "Error in 'correct' answer: $PG_eval_errors<br> 885 # The answer $correctAnswer evaluates to $correctVal, 886 # which cannot be interpreted as a number. "; 887 # 888 # } 889 # ######################################################################## 890 # $correctVal = $correct_num_answer;#it took me two and a half hours to figure out that correctVal wasn't 891 # #getting the number properly 892 # #construct the answer evaluator 893 # my $answer_evaluator = new AnswerEvaluator; 894 # 895 # 896 # $answer_evaluator->{debug} = $cplx_params{debug}; 897 # $answer_evaluator->ans_hash( 898 # correct_ans => $correctVal, 899 # type => "${mode}_number", 900 # tolerance => $cplx_params{tolerance}, 901 # tolType => 'absolute', # $cplx_params{tolType}, 902 # original_correct_ans => $formattedCorrectAnswer, 903 # answerIsString => $corrAnswerIsString, 904 # answer_form => 'cartesian', 905 # ); 906 # my ($in, $formattedSubmittedAnswer); 907 # $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift; 908 # $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;} 909 # ); 910 # if (defined($cplx_params{strings}) && $cplx_params{strings}) { 911 # $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params); 912 # } 913 # #$answer_evaluator->install_pre_filter(\&check_syntax); 914 # 915 # $answer_evaluator->install_pre_filter(\&math_constants); 916 # $answer_evaluator->install_pre_filter(\&cplx_constants); 917 # $answer_evaluator->install_pre_filter(\&check_for_polar); 918 # if ($mode eq 'std') { 919 # # do nothing 920 # } elsif ($mode eq 'strict_polar') { 921 # $answer_evaluator->install_pre_filter(\&is_a_polar); 922 # } elsif ($mode eq 'strict_num_cartesian') { 923 # $answer_evaluator->install_pre_filter(\&is_a_numeric_cartesian); 924 # } elsif ($mode eq 'strict_num_polar') { 925 # $answer_evaluator->install_pre_filter(\&is_a_numeric_polar); 926 # } elsif ($mode eq 'strict') { 927 # $answer_evaluator->install_pre_filter(\&is_a_numeric_complex); 928 # } elsif ($mode eq 'arith') { 929 # $answer_evaluator->install_pre_filter(\&is_an_arithmetic_expression); 930 # } elsif ($mode eq 'frac') { 931 # $answer_evaluator->install_pre_filter(\&is_a_fraction); 932 # 933 # } else { 934 # $PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.'; 935 # $formattedSubmittedAnswer = $in; 936 # } 937 # if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string. 938 # $answer_evaluator->install_evaluator(\&compare_cplx2, %cplx_params); 939 # } 940 # 941 # 942 # ############################################################################### 943 # # We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's 944 # # can be displayed in the answer message. This may still cause a few anomolies when strings are used 945 # # 946 # ############################################################################### 947 # 948 # $answer_evaluator->install_post_filter(\&fix_answers_for_display); 949 # $answer_evaluator->install_post_filter(\&fix_for_polar_display); 950 # 951 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; 952 # return $rh_ans unless $rh_ans->catch_error('EVAL'); 953 # $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message}; 954 # $rh_ans->clear_error('EVAL'); } ); 955 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } ); 956 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } ); 957 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } ); 958 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } ); 959 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('STRING'); } ); 960 # $answer_evaluator; 961 # } 962 963 964 # compares two complex numbers by comparing their real and imaginary parts 965 # this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05 966 # sub compare_cplx2 { 967 # my ($rh_ans, %options) = @_; 968 # my @answers = split/,/,$rh_ans->{student_ans}; 969 # foreach( @answers ) 970 # { 971 # $rh_ans->{student_ans} = $_; 972 # $rh_ans = &check_syntax( $rh_ans ); 973 # my ($inVal,$PG_eval_errors,$PG_full_error_report) = PG_answer_eval($rh_ans->{student_ans}); 974 # 975 # if ($PG_eval_errors) { 976 # $rh_ans->throw_error('EVAL','There is a syntax error in your answer'); 977 # $rh_ans->{ans_message} = clean_up_error_msg($PG_eval_errors); 978 # # return $rh_ans; 979 # } else { 980 # $rh_ans->{student_ans} = prfmt($inVal,$options{format}); 981 # } 982 # 983 # $inVal = cplx($inVal,0) unless ref($inVal) =~/Complex/; 984 # my $permitted_error_Re; 985 # my $permitted_error_Im; 986 # if ($rh_ans->{tolType} eq 'absolute') { 987 # $permitted_error_Re = $rh_ans->{tolerance}; 988 # $permitted_error_Im = $rh_ans->{tolerance}; 989 # } 990 # elsif ( abs($rh_ans->{correct_ans}) <= $options{zeroLevel}) { 991 # $permitted_error_Re = $options{zeroLevelTol}; ## want $tol to be non zero 992 # $permitted_error_Im = $options{zeroLevelTol}; ## want $tol to be non zero 993 # } 994 # else { 995 # $permitted_error_Re = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Re); 996 # $permitted_error_Im = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Im); 997 # 998 # } 999 # 1000 # $rh_ans->{score} = 1 if ( abs( $rh_ans->{correct_ans}->Complex::Re - $inVal->Complex::Re) <= 1001 # $permitted_error_Re && abs($rh_ans->{correct_ans}->Complex::Im - $inVal->Complex::Im )<= $permitted_error_Im ); 1002 # if( $rh_ans->{score} == 1 ){ return $rh_ans; } 1003 # 1004 # 1005 # } 1006 # $rh_ans; 1007 # 1008 # } 1009 1010 # this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05 1011 # sub cplx_cmp_mult { 1012 # my $correctAnswer = shift; 1013 # my %cplx_params = @_; 1014 # my @keys = qw ( correctAnswer tolerance tolType format mode zeroLevel zeroLevelTol debug ); 1015 # assign_option_aliases( \%cplx_params, 1016 # 'reltol' => 'relTol', 1017 # ); 1018 # set_default_options(\%cplx_params, 1019 # 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative', 1020 # # default mode should be relative, to obtain this tol must not be defined 1021 # 'tolerance' => $main::numAbsTolDefault, 1022 # 'relTol' => $main::numRelPercentTolDefault, 1023 # 'zeroLevel' => $main::numZeroLevelDefault, 1024 # 'zeroLevelTol' => $main::numZeroLevelTolDefault, 1025 # 'format' => $main::numFormatDefault, 1026 # 'debug' => 0, 1027 # 'mode' => 'std', 1028 # 1029 # ); 1030 # $correctAnswer = cplx($correctAnswer,0) unless ref($correctAnswer) =~/Complex/; 1031 # my $format = $cplx_params{'format'}; 1032 # my $mode = $cplx_params{'mode'}; 1033 # 1034 # if( $cplx_params{tolType} eq 'relative' ) { 1035 # $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'}; 1036 # } 1037 # 1038 # my $formattedCorrectAnswer; 1039 # my $correct_num_answer; 1040 # my $corrAnswerIsString = 0; 1041 # 1042 # 1043 # if (defined($cplx_params{strings}) && $cplx_params{strings}) { 1044 # my $legalString = ''; 1045 # my @legalStrings = @{$cplx_params{strings}}; 1046 # $correct_num_answer = $correctAnswer; 1047 # $formattedCorrectAnswer = $correctAnswer; 1048 # foreach $legalString (@legalStrings) { 1049 # if ( uc($correctAnswer) eq uc($legalString) ) { 1050 # $corrAnswerIsString = 1; 1051 # 1052 # last; 1053 # } 1054 # } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric 1055 # } else { 1056 # $correct_num_answer = $correctAnswer; 1057 # $formattedCorrectAnswer = prfmt( $correctAnswer, $cplx_params{'format'} ); 1058 # } 1059 # $correct_num_answer = math_constants($correct_num_answer); 1060 # my $PGanswerMessage = ''; 1061 # 1062 # my ($inVal,$correctVal,$PG_eval_errors,$PG_full_error_report); 1063 # 1064 # if (defined($correct_num_answer) && $correct_num_answer =~ /\S/ && $corrAnswerIsString == 0 ) { 1065 # ($correctVal, $PG_eval_errors,$PG_full_error_report) = PG_answer_eval($correct_num_answer); 1066 # } else { # case of a string answer 1067 # $PG_eval_errors = ' '; 1068 # $correctVal = $correctAnswer; 1069 # } 1070 # 1071 # if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal)) && $corrAnswerIsString == 0)) { 1072 # ##error message from eval or above 1073 # warn "Error in 'correct' answer: $PG_eval_errors<br> 1074 # The answer $correctAnswer evaluates to $correctVal, 1075 # which cannot be interpreted as a number. "; 1076 # 1077 # } 1078 # ######################################################################## 1079 # $correctVal = $correct_num_answer;#it took me two and a half hours to figure out that correctVal wasn't 1080 # #getting the number properly 1081 # #construct the answer evaluator 1082 # my $counter = 0; 1083 # my $answer_evaluator = new AnswerEvaluator; 1084 # 1085 # my $number; 1086 # $answer_evaluator->install_pre_filter( sub{ my $rh_ans = shift; my @temp = 1087 # split/,/,$rh_ans->{student_ans}; $number = @temp; warn "this number ", $number; $rh_ans;}); 1088 # warn "number ", $number; 1089 # while( $counter < 4 ) 1090 # { 1091 # $answer_evaluator = &answer_mult( $correctVal, $mode, $formattedCorrectAnswer, 1092 # $corrAnswerIsString, $counter, %cplx_params ); 1093 # warn "answer_evaluator ", $answer_evaluator; 1094 # $answer_evaluator->install_evaluator( sub { my $rh_ans = shift; warn "score ", $rh_ans->{score}; 1095 # $rh_ans;}); 1096 # $counter += 1; 1097 # } 1098 # 1099 # $answer_evaluator; 1100 # 1101 # } 1102 1103 # this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05 1104 # sub answer_mult{ 1105 # my $correctVal = shift; 1106 # my $mode = shift; 1107 # my $formattedCorrectAnswer = shift; 1108 # my $corrAnswerIsString = shift; 1109 # my $counter = shift; 1110 # warn "counter ", $counter; 1111 # 1112 # my %cplx_params = @_; 1113 # my $answer_evaluator = new AnswerEvaluator; 1114 # 1115 # 1116 # $answer_evaluator->{debug} = $cplx_params{debug}; 1117 # $answer_evaluator->ans_hash( 1118 # correct_ans => $correctVal, 1119 # type => "${mode}_number", 1120 # tolerance => $cplx_params{tolerance}, 1121 # tolType => 'absolute', # $cplx_params{tolType}, 1122 # original_correct_ans => $formattedCorrectAnswer, 1123 # answerIsString => $corrAnswerIsString, 1124 # answer_form => 'cartesian', 1125 # ); 1126 # $answer_evaluator->install_pre_filter(sub { 1127 # my $rh_ans = shift; 1128 # $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; 1129 # my @answers = split/,/,$rh_ans->{student_ans}; 1130 # $rh_ans -> {student_ans} = $answers[$counter]; 1131 # $rh_ans; 1132 # } 1133 # ); 1134 # if (defined($cplx_params{strings}) && $cplx_params{strings}) { 1135 # $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params); 1136 # } 1137 # $answer_evaluator->install_pre_filter(\&check_syntax); 1138 # $answer_evaluator->install_pre_filter(\&math_constants); 1139 # $answer_evaluator->install_pre_filter(\&cplx_constants); 1140 # $answer_evaluator->install_pre_filter(\&check_for_polar); 1141 # if ($mode eq 'std') { 1142 # # do nothing 1143 # } elsif ($mode eq 'strict_polar') { 1144 # $answer_evaluator->install_pre_filter(\&is_a_polar); 1145 # } elsif ($mode eq 'strict_num_cartesian') { 1146 # $answer_evaluator->install_pre_filter(\&is_a_numeric_cartesian); 1147 # } elsif ($mode eq 'strict_num_polar') { 1148 # $answer_evaluator->install_pre_filter(\&is_a_numeric_polar); 1149 # } elsif ($mode eq 'strict') { 1150 # $answer_evaluator->install_pre_filter(\&is_a_numeric_complex); 1151 # } elsif ($mode eq 'arith') { 1152 # $answer_evaluator->install_pre_filter(\&is_an_arithmetic_expression); 1153 # } elsif ($mode eq 'frac') { 1154 # $answer_evaluator->install_pre_filter(\&is_a_fraction); 1155 # 1156 # } else { 1157 # #$PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.'; 1158 # } 1159 # if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string. 1160 # $answer_evaluator->install_evaluator(\&compare_cplx, %cplx_params); 1161 # } 1162 # 1163 # 1164 # ############################################################################### 1165 # # We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's 1166 # # can be displayed in the answer message. This may still cause a few anomolies when strings are used 1167 # # 1168 # ############################################################################### 1169 # 1170 # $answer_evaluator->install_post_filter(\&fix_answers_for_display); 1171 # $answer_evaluator->install_post_filter(\&fix_for_polar_display); 1172 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; 1173 # return $rh_ans unless $rh_ans->catch_error('EVAL'); 1174 # $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message}; 1175 # $rh_ans->clear_error('EVAL'); } ); 1176 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } ); 1177 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } ); 1178 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } ); 1179 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } ); 1180 # $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; warn "ans hash", $rh_ans->clear_error('STRING'); } ); 1181 # $answer_evaluator; 1182 # } 1183 # 1184 1185 1186 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |