[system] / trunk / pg / macros / PGcomplexmacros.pl Repository:
ViewVC logotype

Diff of /trunk/pg/macros/PGcomplexmacros.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 2986 Revision 3319
58 58
59# number format used frequently in strict prefilters 59# number format used frequently in strict prefilters
60my $number = '([+-]?)(?=\d|\.\d)\d*(\.\d*)?(E([+-]?\d+))?'; 60my $number = '([+-]?)(?=\d|\.\d)\d*(\.\d*)?(E([+-]?\d+))?';
61 61
62 62
63sub polar{
64 my $z = shift;
65 my %options = @_;
66 my $r = rho($z);
67 my $theta = $z->theta;
68 my $r_format = ':%0.3f';
69 my $theta_format = ':%0.3f';
70 $r_format=":" . $options{r_format} if defined($options{r_format});
71 $theta_format = ":" . $options{theta_format} if defined($options{theta_format});
72 "{$r$r_format} e^{i {$theta$theta_format}}";
73 63
74}
75 64
76=head4 cplx_cmp 65=head4 cplx_cmp
77 66
78 This subroutine compares complex numbers. 67 This subroutine compares complex numbers.
79 Available prefilters include: 68 Available prefilters include:
101sub cplx_cmp { 90sub cplx_cmp {
102 my $correctAnswer = shift; 91 my $correctAnswer = shift;
103 my %cplx_params = @_; 92 my %cplx_params = @_;
104 93
105 assign_option_aliases( \%cplx_params, 94 assign_option_aliases( \%cplx_params,
106 'reltol' => 'relTol', 95 'reltol' => 'relTol',
107 ); 96 );
108 set_default_options(\%cplx_params, 97 set_default_options(\%cplx_params,
109 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative', 98 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative',
110 # default mode should be relative, to obtain this tol must not be defined 99 # default mode should be relative, to obtain this tol must not be defined
111 'tolerance' => $main::numAbsTolDefault, 100 'tolerance' => $main::numAbsTolDefault,
112 'relTol' => $main::numRelPercentTolDefault, 101 'relTol' => $main::numRelPercentTolDefault,
113 'zeroLevel' => $main::numZeroLevelDefault, 102 'zeroLevel' => $main::numZeroLevelDefault,
114 'zeroLevelTol' => $main::numZeroLevelTolDefault, 103 'zeroLevelTol' => $main::numZeroLevelTolDefault,
115 'format' => $main::numFormatDefault, 104 'format' => $main::numFormatDefault,
116 'debug' => 0, 105 'debug' => 0,
117 'mode' => 'std', 106 'mode' => 'std',
118 'strings' => undef, 107 'strings' => undef,
119 108 );
120 );
121 my $format = $cplx_params{'format'}; 109 my $format = $cplx_params{'format'};
122 my $mode = $cplx_params{'mode'}; 110 my $mode = $cplx_params{'mode'};
123 111
124 if( $cplx_params{tolType} eq 'relative' ) { 112 if( $cplx_params{tolType} eq 'relative' ) {
125 $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'}; 113 $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'};
126 } 114 }
127 115
157 } else { # case of a string answer 145 } else { # case of a string answer
158 $PG_eval_errors = ' '; 146 $PG_eval_errors = ' ';
159 $correctVal = $correctAnswer; 147 $correctVal = $correctAnswer;
160 } 148 }
161 149
162 #if ( ($PG_eval_errors && $corrAnswerIsString == 0) or (not (( ref($correctAnswer) =~ /^Complex?/) || is_a_number($correctVal)) && $corrAnswerIsString == 0)) {
163 ##error message from eval or above
164 #warn "Error in 'correct' answer: $PG_eval_errors<br>
165 # The answer $correctAnswer evaluates to $correctVal,
166 # which cannot be interpreted as a number. ";
167
168 #}
169 ######################################################################## 150 ########################################################################
170 $correctVal = $correct_num_answer; 151 $correctVal = $correct_num_answer;
171 $correctVal = cplx( $correctVal, 0 ) unless ref($correctVal) =~/^Complex?/ || $corrAnswerIsString == 1; 152 $correctVal = cplx( $correctVal, 0 ) unless ref($correctVal) =~/^Complex?/ || $corrAnswerIsString == 1;
172 153
173 #construct the answer evaluator 154 #construct the answer evaluator
174 my $answer_evaluator = new AnswerEvaluator; 155 my $answer_evaluator = new AnswerEvaluator;
175 $answer_evaluator->{debug} = $cplx_params{debug}; 156 $answer_evaluator->{debug} = $cplx_params{debug};
176 $answer_evaluator->ans_hash( 157 $answer_evaluator->ans_hash(
177 correct_ans => $correctVal, 158 correct_ans => $correctVal,
178 type => "${mode}_number", 159 type => "cplx_cmp",
179 tolerance => $cplx_params{tolerance}, 160 tolerance => $cplx_params{tolerance},
180 tolType => 'absolute', # $cplx_params{tolType}, 161 tolType => 'absolute', # $cplx_params{tolType},
181 original_correct_ans => $formattedCorrectAnswer, 162 original_correct_ans => $formattedCorrectAnswer,
182 answerIsString => $corrAnswerIsString, 163 answerIsString => $corrAnswerIsString,
183 answer_form => 'cartesian', 164 answer_form => 'cartesian',
184 ); 165 );
185 my ($in, $formattedSubmittedAnswer); 166 my ($in, $formattedSubmittedAnswer);
186 $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift; 167 $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift;
187 $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;} 168 $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;}
188 ); 169 );
189 if (defined($cplx_params{strings}) && $cplx_params{strings}) { 170 if (defined($cplx_params{strings}) && $cplx_params{strings}) {
190 $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params); 171 $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params);
191 } 172 }
192 173
193 $answer_evaluator->install_pre_filter(\&check_syntax); 174 $answer_evaluator->install_pre_filter(\&check_syntax);
194
195 $answer_evaluator->install_pre_filter(\&math_constants); 175 $answer_evaluator->install_pre_filter(\&math_constants);
196 $answer_evaluator->install_pre_filter(\&cplx_constants); 176 $answer_evaluator->install_pre_filter(\&cplx_constants);
197 $answer_evaluator->install_pre_filter(\&check_for_polar); 177 $answer_evaluator->install_pre_filter(\&check_for_polar);
198 if ($mode eq 'std') { 178 if ($mode eq 'std') {
199 # do nothing 179 # do nothing
272 $permitted_error_Re && abs($rh_ans->{correct_ans}->Complex::Im - $inVal->Complex::Im )<= $permitted_error_Im ); 252 $permitted_error_Re && abs($rh_ans->{correct_ans}->Complex::Im - $inVal->Complex::Im )<= $permitted_error_Im );
273 253
274 $rh_ans; 254 $rh_ans;
275} 255}
276 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
277sub mult_cmp{ 276sub 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 {
278 my $answer = shift; 283 my $rh_ans = shift;
279 my @answers = @{$answer} if ref($answer) eq 'ARRAY'; 284 my @student_answers = split/\s*,\s*/,$rh_ans->{student_ans};
280 my %mult_params = @_; 285 my @evaluated_ans_hashes = ();
281 my @keys = qw ( tolerance tolType format mode zeroLevel zeroLevelTol debug ); 286 for ( my $j=0; $j<@student_answers; $j++ ) {
282 my @correctVal; 287 # find an answer evaluator which marks this answer correct.
283 my $formattedCorrectAnswer; 288 my $student_ans = $student_answers[$j];
284 my @correct_num_answer; 289 my $temp_hash;
285 my ($PG_eval_errors,$PG_full_error_report); 290 for ( my $i=0; $i<@answer_evaluators; $i++ ) {
286 assign_option_aliases( \%mult_params, 291 my $evaluator = $answer_evaluators[$i];
287 'reltol' => 'relTol', 292 $temp_hash = new AnswerHash; # make a copy of the answer hash resulting from the evaluation
288 ); 293 %$temp_hash = %{$evaluator->evaluate($student_ans)};
289 set_default_options(\%mult_params, 294 if (($temp_hash->{score} == 1)) {
290 'tolType' => (defined($mult_params{tol}) ) ? 'absolute' : 'relative', 295 # save evaluated answer
291 # default mode should be relative, to obtain this tol must not be defined 296 push @evaluated_ans_hashes, $temp_hash;
292 'tolerance' => $main::numAbsTolDefault, 297 # remove answer evaluator and check the next answer
293 'relTol' => $main::numRelPercentTolDefault, 298 splice(@answer_evaluators,$i,1);
294 'zeroLevel' => $main::numZeroLevelDefault, 299 last;
295 'zeroLevelTol' => $main::numZeroLevelTolDefault, 300 }
296 'format' => $main::numFormatDefault, 301 }
297 'debug' => 0, 302 # if we exit the loop without finding a correct evaluation:
298 'mode' => 'std', 303 # make sure every answer is evaluated, even extra answers for which
299 'compare' => 'num', 304 # there will be no answer evaluators left.
300 ); 305 if (not defined($temp_hash) ) { # make sure every answer is evaluated, even extra answers.
301 my $format = $mult_params{'format'}; 306 my $evaluator = $backup_ans_eval;
302 my $mode = $mult_params{'mode'}; 307 $temp_hash = new AnswerHash; # make a copy of the answer hash resulting from the evaluation
303 308 %$temp_hash = %{$evaluator->evaluate($student_ans)};
304 309 $temp_hash->{score} =0; # this was an extra answer -- clearly incorrect
305 if( $mult_params{tolType} eq 'relative' ) { 310 $temp_hash->{correct_ans} = "too many answers";
306 $mult_params{'tolerance'} = .01*$mult_params{'relTol'}; 311 }
307 } 312 # now make sure that even answers which
308 313 # don't never evaluate correctly are still recorded in the list
309 if( $mult_params{ 'compare' } eq 'cplx' ){ 314 if ( $temp_hash->{score} <1) {
310 foreach( @answers ) 315 push @evaluated_ans_hashes, $temp_hash;
311 { 316 }
312 $_ = cplx( $_, 0 ) unless ref($_) =~/Complex/; 317
318
313 } 319 }
314 } 320 # construct the final answer hash
315 321 my $rh_ans_out = shift @evaluated_ans_hashes;
316 my $corrAnswerIsString = 0; 322 while (@evaluated_ans_hashes) {
317 323 my $temp_hash = shift @evaluated_ans_hashes;
318 for( my $k = 0; $k < @answers; $k++ ){ 324 $rh_ans_out =$rh_ans_out->AND($temp_hash);
319 if (defined($mult_params{strings}) && $mult_params{strings}) {
320 my $legalString = '';
321 my @legalStrings = @{$mult_params{strings}};
322 $correct_num_answer[$k] = $answers[$k];
323 $formattedCorrectAnswer .= $answers[$k] . ",";
324 foreach $legalString (@legalStrings) {
325 if ( uc($answers[$k]) eq uc($legalString) ) {
326 $corrAnswerIsString = 1;
327
328 last;
329 }
330 } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric
331 } else {
332 $correct_num_answer[$k] = $answers[$k];
333 $formattedCorrectAnswer .= prfmt( $answers[$k], $mult_params{'format'} ) . ", ";
334 }
335 $correct_num_answer[$k] = math_constants($correct_num_answer[$k]);
336 my $PGanswerMessage = '';
337
338
339 if (defined($correct_num_answer[$k]) && $correct_num_answer[$k] =~ /\S/ && $corrAnswerIsString == 0 ) {
340 ($correctVal[$k], $PG_eval_errors,$PG_full_error_report) =
341 PG_answer_eval($correct_num_answer[$k]);
342 } else { # case of a string answer
343 $PG_eval_errors = ' ';
344 $correctVal[$k] = $answers[$k];
345 }
346
347 #if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal[$k])) && $corrAnswerIsString == 0)) {
348 ##error message from eval or above
349 #warn "Error in 'correct' answer: $PG_eval_errors<br>
350 #The answer $answers[$k] evaluates to $correctVal[$k],
351 #which cannot be interpreted as a number. ";
352
353 #}
354 ########################################################################
355 $correctVal[$k] = $correct_num_answer[$k];
356 }
357 $formattedCorrectAnswer =~ s/, \Z//;
358
359 #construct the answer evaluator
360
361 my $answer_evaluator = new AnswerEvaluator;
362
363
364 $answer_evaluator->{debug} = $mult_params{debug};
365 $answer_evaluator->ans_hash(
366 correct_ans => [@correctVal],
367 type => "${mode}_number",
368 tolerance => $mult_params{tolerance},
369 tolType => 'absolute', # $mult_params{tolType},
370 original_correct_ans => $formattedCorrectAnswer,
371 answerIsString => $corrAnswerIsString,
372 answer_form => 'cartesian',
373 );
374 my ($in, $formattedSubmittedAnswer);
375 $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift;
376 $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;}
377 );
378 if (defined($mult_params{strings}) && $mult_params{strings}) {
379 $answer_evaluator->install_pre_filter(\&check_strings, %mult_params);
380 }
381
382 $answer_evaluator -> install_pre_filter( \&mult_prefilters, %mult_params );
383 $answer_evaluator->install_pre_filter( sub{my $rh_ans = shift; $rh_ans->{original_student_ans} = $rh_ans->{student_ans};$rh_ans;});
384
385 if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string.
386 $answer_evaluator->install_evaluator(\&compare_mult, %mult_params);
387 }
388
389
390###############################################################################
391# We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's
392# can be displayed in the answer message. This may still cause a few anomolies when strings are used
393#
394###############################################################################
395 $answer_evaluator->install_post_filter( sub{my $rh_ans = shift; $rh_ans->{student_ans} = $rh_ans->{original_student_ans};$rh_ans;});
396 $answer_evaluator->install_post_filter(\&fix_answers_for_display);
397 $answer_evaluator->install_post_filter(\&fix_for_polar_display);
398
399 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift;
400 return $rh_ans unless $rh_ans->catch_error('EVAL');
401 $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message};
402 $rh_ans->clear_error('EVAL'); } );
403 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } );
404 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } );
405 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } );
406 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } );
407 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('STRING'); } );
408 $answer_evaluator;
409}
410
411sub mult_prefilters{
412 my ($rh_ans, %options) = @_;
413 my @student_answers = split/,/,$rh_ans->{student_ans};
414 foreach( @student_answers ){
415 $rh_ans->{student_ans} = $_;
416 $rh_ans = &check_syntax( $rh_ans );
417 $rh_ans = &math_constants( $rh_ans );
418 if( $options{compare} eq 'cplx' ){
419 $rh_ans = &cplx_constants( $rh_ans );
420 #$rh_ans = &check_for_polar( $rh_ans );
421 } 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# }
422 if ( $options{mode} eq 'std') { 514# if ( $options{mode} eq 'std') {
423 # do nothing 515# # do nothing
424 } elsif ($options{mode} eq 'strict_polar') { 516# } elsif ($options{mode} eq 'strict_polar') {
425 $rh_ans = &is_a_polar( $rh_ans ); 517# $rh_ans = &is_a_polar( $rh_ans );
426 } elsif ($options{mode} eq 'strict_num_cartesian') { 518# } elsif ($options{mode} eq 'strict_num_cartesian') {
427 $rh_ans = &is_a_numeric_cartesian( $rh_ans ); 519# $rh_ans = &is_a_numeric_cartesian( $rh_ans );
428 } elsif ($options{mode} eq 'strict_num_polar') { 520# } elsif ($options{mode} eq 'strict_num_polar') {
429 $rh_ans = &is_a_numeric_polar( $rh_ans ); 521# $rh_ans = &is_a_numeric_polar( $rh_ans );
430 } elsif ($options{mode} eq 'strict') { 522# } elsif ($options{mode} eq 'strict') {
431 $rh_ans = &is_a_numeric_complex( $rh_ans ); 523# $rh_ans = &is_a_numeric_complex( $rh_ans );
432 } elsif ($options{mode} eq 'arith') { 524# } elsif ($options{mode} eq 'arith') {
433 $rh_ans = &is_an_arithmetic_expression( $rh_ans ); 525# $rh_ans = &is_an_arithmetic_expression( $rh_ans );
434 } elsif ($options{mode} eq 'frac') { 526# } elsif ($options{mode} eq 'frac') {
435 $rh_ans = &is_a_fraction( $rh_ans ); 527# $rh_ans = &is_a_fraction( $rh_ans );
436 528#
437 } else { 529# } else {
438 #$PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.'; 530# #$PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.';
439 #$formattedSubmittedAnswer = $in; 531# #$formattedSubmittedAnswer = $in;
440 } 532# }
441 $_ = $rh_ans->{student_ans}; 533# $_ = $rh_ans->{student_ans};
442 } 534# }
443 my $ans_string; 535# my $ans_string;
444 foreach( @student_answers ) 536# foreach( @student_answers )
445 { 537# {
446 $ans_string .= ", $_"; 538# $ans_string .= ", $_";
447 } 539# }
448 $ans_string =~ s/\A,//; 540# $ans_string =~ s/\A,//;
449 $rh_ans->{student_ans} = $ans_string; 541# $rh_ans->{student_ans} = $ans_string;
450 $rh_ans; 542# $rh_ans;
451} 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# }
452 557
453# compares two complex numbers by comparing their real and imaginary parts 558# compares two complex numbers by comparing their real and imaginary parts
454sub compare_mult { 559# sub compare_mult {
455 my ($rh_ans, %options) = @_; 560# my ($rh_ans, %options) = @_;
456 my @student_answers = split/,/,$rh_ans->{student_ans}; 561# my @student_answers = split/,/,$rh_ans->{student_ans};
457 my @correct_answers = @{$rh_ans->{correct_ans}}; 562# my @correct_answers = @{$rh_ans->{correct_ans}};
458 my $one_correct = 1/@correct_answers; 563# my $one_correct = 1/@correct_answers;
459 my $temp_score = 0; 564# my $temp_score = 0;
460 foreach( @correct_answers ){ 565# foreach( @correct_answers ){
461 $rh_ans->{correct_ans} = $_; 566# $rh_ans->{correct_ans} = $_;
462 foreach( @student_answers ){ 567# foreach( @student_answers ){
463 $rh_ans->{student_ans} = $_; 568# $rh_ans->{student_ans} = $_;
464 if( $options{compare} eq 'cplx' ){ 569# if( $options{compare} eq 'cplx' ){
465 $rh_ans = &compare_cplx( $rh_ans, %options); 570# $rh_ans = &compare_cplx( $rh_ans, %options);
466 }else{ 571# }else{
467 $rh_ans = &compare_numbers( $rh_ans, %options); 572# $rh_ans = &compare_numbers( $rh_ans, %options);
468 } 573# }
469 if( $rh_ans->{score} == 1 ) 574# if( $rh_ans->{score} == 1 )
470 { 575# {
471 $temp_score += $one_correct; 576# $temp_score += $one_correct;
472 $rh_ans->{score} = 0; 577# $rh_ans->{score} = 0;
473 last; 578# last;
474 } 579# }
475 } 580# }
476 } 581# }
477 $rh_ans->{score} = $temp_score; 582# $rh_ans->{score} = $temp_score;
478 $rh_ans; 583# $rh_ans;
479 584#
480} 585# }
481 586
482sub multi_cmp{ 587
483 my $pointer = shift;
484 my %options = @_;
485 my @evals = @{$pointer};
486 my $answer_evaluator = new AnswerEvaluator;
487 $answer_evaluator->install_evaluator( sub {
488 my $rh_ans = shift;
489 $rh_ans->{score} = 1;#in order to use AND below, score must be 1
490 $rh_ans->{preview_text_string} = "";#needs to be initialized to prevent warnings
491 my @student_answers = split/,/,$rh_ans->{student_ans};
492 foreach my $eval ( @evals ){
493 my $temp_eval = new AnswerEvaluator;
494 my $temp_hash = $temp_eval->ans_hash;
495 $temp_hash->{preview_text_string} = "";#needs to be initialized to prevent warnings
496 foreach my $temp ( @student_answers ){
497 $eval->evaluate($temp);
498 $temp = $eval->ans_hash->{student_ans} unless $eval->ans_hash->{student_ans}=~ /you/i;
499 $temp_hash = $temp_hash->OR( $eval->ans_hash );
500 if( $eval->ans_hash->{score} == 1){ last; }
501 }
502 $rh_ans = $rh_ans->AND( $temp_hash );
503 }
504 $rh_ans->{correct_ans} =~ s/No correct answer specified (OR|AND) //g;
505 $rh_ans->{student_ans} = "";
506 foreach( @student_answers ){ $rh_ans->{student_ans} .= "$_, "; }
507 $rh_ans->{student_ans} =~ s/, \Z//;
508 if( scalar(@evals) != scalar(@student_answers) ){ $rh_ans->{score} = 0; }#wrong number of answers makes answer wrong
509 $rh_ans; });
510 $answer_evaluator;
511}
512 588
513# Output is text displaying the complex numver in "e to the i theta" form. The 589# Output is text displaying the complex numver in "e to the i theta" form. The
514# formats for the argument theta is determined by the option C<theta_format> and the 590# formats for the argument theta is determined by the option C<theta_format> and the
515# format for the modulus is determined by the C<r_format> option. 591# format for the modulus is determined by the C<r_format> option.
516 592
740 $rh_ans->{student_ans} =~ s/\]/i\)/; 816 $rh_ans->{student_ans} =~ s/\]/i\)/;
741 } 817 }
742 $rh_ans; 818 $rh_ans;
743} 819}
744 820
821# this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05
745sub cplx_cmp2 { 822# sub cplx_cmp2 {
746 my $correctAnswer = shift; 823# my $correctAnswer = shift;
747 my %cplx_params = @_; 824# my %cplx_params = @_;
748 my @keys = qw ( correctAnswer tolerance tolType format mode zeroLevel zeroLevelTol debug ); 825# my @keys = qw ( correctAnswer tolerance tolType format mode zeroLevel zeroLevelTol debug );
749 assign_option_aliases( \%cplx_params, 826# assign_option_aliases( \%cplx_params,
750 'reltol' => 'relTol', 827# 'reltol' => 'relTol',
751 ); 828# );
752 set_default_options(\%cplx_params, 829# set_default_options(\%cplx_params,
753 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative', 830# 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative',
754 # default mode should be relative, to obtain this tol must not be defined 831# # default mode should be relative, to obtain this tol must not be defined
755 'tolerance' => $main::numAbsTolDefault, 832# 'tolerance' => $main::numAbsTolDefault,
756 'relTol' => $main::numRelPercentTolDefault, 833# 'relTol' => $main::numRelPercentTolDefault,
757 'zeroLevel' => $main::numZeroLevelDefault, 834# 'zeroLevel' => $main::numZeroLevelDefault,
758 'zeroLevelTol' => $main::numZeroLevelTolDefault, 835# 'zeroLevelTol' => $main::numZeroLevelTolDefault,
759 'format' => $main::numFormatDefault, 836# 'format' => $main::numFormatDefault,
760 'debug' => 0, 837# 'debug' => 0,
761 'mode' => 'std', 838# 'mode' => 'std',
762 839#
763 ); 840# );
764 $correctAnswer = cplx($correctAnswer,0) unless ref($correctAnswer) =~/Complex/; 841# $correctAnswer = cplx($correctAnswer,0) unless ref($correctAnswer) =~/Complex/;
765 my $format = $cplx_params{'format'}; 842# my $format = $cplx_params{'format'};
766 my $mode = $cplx_params{'mode'}; 843# my $mode = $cplx_params{'mode'};
767 844#
768 if( $cplx_params{tolType} eq 'relative' ) { 845# if( $cplx_params{tolType} eq 'relative' ) {
769 $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'}; 846# $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'};
770 } 847# }
771 848#
772 my $formattedCorrectAnswer; 849# my $formattedCorrectAnswer;
773 my $correct_num_answer; 850# my $correct_num_answer;
774 my $corrAnswerIsString = 0; 851# my $corrAnswerIsString = 0;
775 852#
776 853#
777 if (defined($cplx_params{strings}) && $cplx_params{strings}) { 854# if (defined($cplx_params{strings}) && $cplx_params{strings}) {
778 my $legalString = ''; 855# my $legalString = '';
779 my @legalStrings = @{$cplx_params{strings}}; 856# my @legalStrings = @{$cplx_params{strings}};
780 $correct_num_answer = $correctAnswer; 857# $correct_num_answer = $correctAnswer;
781 $formattedCorrectAnswer = $correctAnswer; 858# $formattedCorrectAnswer = $correctAnswer;
782 foreach $legalString (@legalStrings) { 859# foreach $legalString (@legalStrings) {
783 if ( uc($correctAnswer) eq uc($legalString) ) { 860# if ( uc($correctAnswer) eq uc($legalString) ) {
784 $corrAnswerIsString = 1; 861# $corrAnswerIsString = 1;
785 862#
786 last; 863# last;
787 } 864# }
788 } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric 865# } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric
789 } else { 866# } else {
790 $correct_num_answer = $correctAnswer; 867# $correct_num_answer = $correctAnswer;
791 $formattedCorrectAnswer = prfmt( $correctAnswer, $cplx_params{'format'} ); 868# $formattedCorrectAnswer = prfmt( $correctAnswer, $cplx_params{'format'} );
792 } 869# }
793 $correct_num_answer = math_constants($correct_num_answer); 870# $correct_num_answer = math_constants($correct_num_answer);
794 my $PGanswerMessage = ''; 871# my $PGanswerMessage = '';
795 872#
796 my ($inVal,$correctVal,$PG_eval_errors,$PG_full_error_report); 873# my ($inVal,$correctVal,$PG_eval_errors,$PG_full_error_report);
797 874#
798 if (defined($correct_num_answer) && $correct_num_answer =~ /\S/ && $corrAnswerIsString == 0 ) { 875# if (defined($correct_num_answer) && $correct_num_answer =~ /\S/ && $corrAnswerIsString == 0 ) {
799 ($correctVal, $PG_eval_errors,$PG_full_error_report) = PG_answer_eval($correct_num_answer); 876# ($correctVal, $PG_eval_errors,$PG_full_error_report) = PG_answer_eval($correct_num_answer);
800 } else { # case of a string answer 877# } else { # case of a string answer
801 $PG_eval_errors = ' '; 878# $PG_eval_errors = ' ';
802 $correctVal = $correctAnswer; 879# $correctVal = $correctAnswer;
803 } 880# }
804 881#
805 if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal)) && $corrAnswerIsString == 0)) { 882# if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal)) && $corrAnswerIsString == 0)) {
806 ##error message from eval or above 883# ##error message from eval or above
807 warn "Error in 'correct' answer: $PG_eval_errors<br> 884# warn "Error in 'correct' answer: $PG_eval_errors<br>
808 The answer $correctAnswer evaluates to $correctVal, 885# The answer $correctAnswer evaluates to $correctVal,
809 which cannot be interpreted as a number. "; 886# which cannot be interpreted as a number. ";
810 887#
811 } 888# }
812 ######################################################################## 889# ########################################################################
813 $correctVal = $correct_num_answer;#it took me two and a half hours to figure out that correctVal wasn't 890# $correctVal = $correct_num_answer;#it took me two and a half hours to figure out that correctVal wasn't
814 #getting the number properly 891# #getting the number properly
815 #construct the answer evaluator 892# #construct the answer evaluator
816 my $answer_evaluator = new AnswerEvaluator; 893# my $answer_evaluator = new AnswerEvaluator;
817 894#
818 895#
819 $answer_evaluator->{debug} = $cplx_params{debug}; 896# $answer_evaluator->{debug} = $cplx_params{debug};
820 $answer_evaluator->ans_hash( 897# $answer_evaluator->ans_hash(
821 correct_ans => $correctVal, 898# correct_ans => $correctVal,
822 type => "${mode}_number", 899# type => "${mode}_number",
823 tolerance => $cplx_params{tolerance}, 900# tolerance => $cplx_params{tolerance},
824 tolType => 'absolute', # $cplx_params{tolType}, 901# tolType => 'absolute', # $cplx_params{tolType},
825 original_correct_ans => $formattedCorrectAnswer, 902# original_correct_ans => $formattedCorrectAnswer,
826 answerIsString => $corrAnswerIsString, 903# answerIsString => $corrAnswerIsString,
827 answer_form => 'cartesian', 904# answer_form => 'cartesian',
828 ); 905# );
829 my ($in, $formattedSubmittedAnswer); 906# my ($in, $formattedSubmittedAnswer);
830 $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift; 907# $answer_evaluator->install_pre_filter(sub {my $rh_ans = shift;
831 $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;} 908# $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; $rh_ans;}
832 ); 909# );
833 if (defined($cplx_params{strings}) && $cplx_params{strings}) { 910# if (defined($cplx_params{strings}) && $cplx_params{strings}) {
834 $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params); 911# $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params);
835 } 912# }
836 #$answer_evaluator->install_pre_filter(\&check_syntax); 913# #$answer_evaluator->install_pre_filter(\&check_syntax);
837 914#
838 $answer_evaluator->install_pre_filter(\&math_constants); 915# $answer_evaluator->install_pre_filter(\&math_constants);
839 $answer_evaluator->install_pre_filter(\&cplx_constants); 916# $answer_evaluator->install_pre_filter(\&cplx_constants);
840 $answer_evaluator->install_pre_filter(\&check_for_polar); 917# $answer_evaluator->install_pre_filter(\&check_for_polar);
841 if ($mode eq 'std') { 918# if ($mode eq 'std') {
842 # do nothing 919# # do nothing
843 } elsif ($mode eq 'strict_polar') { 920# } elsif ($mode eq 'strict_polar') {
844 $answer_evaluator->install_pre_filter(\&is_a_polar); 921# $answer_evaluator->install_pre_filter(\&is_a_polar);
845 } elsif ($mode eq 'strict_num_cartesian') { 922# } elsif ($mode eq 'strict_num_cartesian') {
846 $answer_evaluator->install_pre_filter(\&is_a_numeric_cartesian); 923# $answer_evaluator->install_pre_filter(\&is_a_numeric_cartesian);
847 } elsif ($mode eq 'strict_num_polar') { 924# } elsif ($mode eq 'strict_num_polar') {
848 $answer_evaluator->install_pre_filter(\&is_a_numeric_polar); 925# $answer_evaluator->install_pre_filter(\&is_a_numeric_polar);
849 } elsif ($mode eq 'strict') { 926# } elsif ($mode eq 'strict') {
850 $answer_evaluator->install_pre_filter(\&is_a_numeric_complex); 927# $answer_evaluator->install_pre_filter(\&is_a_numeric_complex);
851 } elsif ($mode eq 'arith') { 928# } elsif ($mode eq 'arith') {
852 $answer_evaluator->install_pre_filter(\&is_an_arithmetic_expression); 929# $answer_evaluator->install_pre_filter(\&is_an_arithmetic_expression);
853 } elsif ($mode eq 'frac') { 930# } elsif ($mode eq 'frac') {
854 $answer_evaluator->install_pre_filter(\&is_a_fraction); 931# $answer_evaluator->install_pre_filter(\&is_a_fraction);
855 932#
856 } else { 933# } else {
857 $PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.'; 934# $PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.';
858 $formattedSubmittedAnswer = $in; 935# $formattedSubmittedAnswer = $in;
859 } 936# }
860 if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string. 937# if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string.
861 $answer_evaluator->install_evaluator(\&compare_cplx2, %cplx_params); 938# $answer_evaluator->install_evaluator(\&compare_cplx2, %cplx_params);
862 } 939# }
863 940#
864 941#
865############################################################################### 942# ###############################################################################
866# We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's 943# # We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's
867# can be displayed in the answer message. This may still cause a few anomolies when strings are used 944# # can be displayed in the answer message. This may still cause a few anomolies when strings are used
868# 945# #
869############################################################################### 946# ###############################################################################
870 947#
871 $answer_evaluator->install_post_filter(\&fix_answers_for_display); 948# $answer_evaluator->install_post_filter(\&fix_answers_for_display);
872 $answer_evaluator->install_post_filter(\&fix_for_polar_display); 949# $answer_evaluator->install_post_filter(\&fix_for_polar_display);
873 950#
874 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; 951# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift;
875 return $rh_ans unless $rh_ans->catch_error('EVAL'); 952# return $rh_ans unless $rh_ans->catch_error('EVAL');
876 $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message}; 953# $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message};
877 $rh_ans->clear_error('EVAL'); } ); 954# $rh_ans->clear_error('EVAL'); } );
878 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } ); 955# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } );
879 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } ); 956# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } );
880 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } ); 957# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } );
881 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } ); 958# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } );
882 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('STRING'); } ); 959# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('STRING'); } );
883 $answer_evaluator; 960# $answer_evaluator;
884} 961# }
885 962
886 963
887# compares two complex numbers by comparing their real and imaginary parts 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
888sub compare_cplx2 { 966# sub compare_cplx2 {
889 my ($rh_ans, %options) = @_; 967# my ($rh_ans, %options) = @_;
890 my @answers = split/,/,$rh_ans->{student_ans}; 968# my @answers = split/,/,$rh_ans->{student_ans};
891 foreach( @answers ) 969# foreach( @answers )
892 { 970# {
893 $rh_ans->{student_ans} = $_; 971# $rh_ans->{student_ans} = $_;
894 $rh_ans = &check_syntax( $rh_ans ); 972# $rh_ans = &check_syntax( $rh_ans );
895 my ($inVal,$PG_eval_errors,$PG_full_error_report) = PG_answer_eval($rh_ans->{student_ans}); 973# my ($inVal,$PG_eval_errors,$PG_full_error_report) = PG_answer_eval($rh_ans->{student_ans});
896 974#
897 if ($PG_eval_errors) { 975# if ($PG_eval_errors) {
898 $rh_ans->throw_error('EVAL','There is a syntax error in your answer'); 976# $rh_ans->throw_error('EVAL','There is a syntax error in your answer');
899 $rh_ans->{ans_message} = clean_up_error_msg($PG_eval_errors); 977# $rh_ans->{ans_message} = clean_up_error_msg($PG_eval_errors);
900 # return $rh_ans; 978# # return $rh_ans;
901 } else { 979# } else {
902 $rh_ans->{student_ans} = prfmt($inVal,$options{format}); 980# $rh_ans->{student_ans} = prfmt($inVal,$options{format});
903 } 981# }
904 982#
905 $inVal = cplx($inVal,0) unless ref($inVal) =~/Complex/; 983# $inVal = cplx($inVal,0) unless ref($inVal) =~/Complex/;
906 my $permitted_error_Re; 984# my $permitted_error_Re;
907 my $permitted_error_Im; 985# my $permitted_error_Im;
908 if ($rh_ans->{tolType} eq 'absolute') { 986# if ($rh_ans->{tolType} eq 'absolute') {
909 $permitted_error_Re = $rh_ans->{tolerance}; 987# $permitted_error_Re = $rh_ans->{tolerance};
910 $permitted_error_Im = $rh_ans->{tolerance}; 988# $permitted_error_Im = $rh_ans->{tolerance};
911 } 989# }
912 elsif ( abs($rh_ans->{correct_ans}) <= $options{zeroLevel}) { 990# elsif ( abs($rh_ans->{correct_ans}) <= $options{zeroLevel}) {
913 $permitted_error_Re = $options{zeroLevelTol}; ## want $tol to be non zero 991# $permitted_error_Re = $options{zeroLevelTol}; ## want $tol to be non zero
914 $permitted_error_Im = $options{zeroLevelTol}; ## want $tol to be non zero 992# $permitted_error_Im = $options{zeroLevelTol}; ## want $tol to be non zero
915 } 993# }
916 else { 994# else {
917 $permitted_error_Re = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Re); 995# $permitted_error_Re = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Re);
918 $permitted_error_Im = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Im); 996# $permitted_error_Im = abs($rh_ans->{tolerance}*$rh_ans->{correct_ans}->Complex::Im);
919 997#
920 } 998# }
921 999#
922 $rh_ans->{score} = 1 if ( abs( $rh_ans->{correct_ans}->Complex::Re - $inVal->Complex::Re) <= 1000# $rh_ans->{score} = 1 if ( abs( $rh_ans->{correct_ans}->Complex::Re - $inVal->Complex::Re) <=
923 $permitted_error_Re && abs($rh_ans->{correct_ans}->Complex::Im - $inVal->Complex::Im )<= $permitted_error_Im ); 1001# $permitted_error_Re && abs($rh_ans->{correct_ans}->Complex::Im - $inVal->Complex::Im )<= $permitted_error_Im );
924 if( $rh_ans->{score} == 1 ){ return $rh_ans; } 1002# if( $rh_ans->{score} == 1 ){ return $rh_ans; }
925 1003#
926 1004#
927 } 1005# }
928 $rh_ans; 1006# $rh_ans;
929 1007#
930} 1008# }
931 1009
932 1010# this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05
933sub cplx_cmp_mult { 1011# sub cplx_cmp_mult {
934 my $correctAnswer = shift; 1012# my $correctAnswer = shift;
935 my %cplx_params = @_; 1013# my %cplx_params = @_;
936 my @keys = qw ( correctAnswer tolerance tolType format mode zeroLevel zeroLevelTol debug ); 1014# my @keys = qw ( correctAnswer tolerance tolType format mode zeroLevel zeroLevelTol debug );
937 assign_option_aliases( \%cplx_params, 1015# assign_option_aliases( \%cplx_params,
938 'reltol' => 'relTol', 1016# 'reltol' => 'relTol',
939 ); 1017# );
940 set_default_options(\%cplx_params, 1018# set_default_options(\%cplx_params,
941 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative', 1019# 'tolType' => (defined($cplx_params{tol}) ) ? 'absolute' : 'relative',
942 # default mode should be relative, to obtain this tol must not be defined 1020# # default mode should be relative, to obtain this tol must not be defined
943 'tolerance' => $main::numAbsTolDefault, 1021# 'tolerance' => $main::numAbsTolDefault,
944 'relTol' => $main::numRelPercentTolDefault, 1022# 'relTol' => $main::numRelPercentTolDefault,
945 'zeroLevel' => $main::numZeroLevelDefault, 1023# 'zeroLevel' => $main::numZeroLevelDefault,
946 'zeroLevelTol' => $main::numZeroLevelTolDefault, 1024# 'zeroLevelTol' => $main::numZeroLevelTolDefault,
947 'format' => $main::numFormatDefault, 1025# 'format' => $main::numFormatDefault,
948 'debug' => 0, 1026# 'debug' => 0,
949 'mode' => 'std', 1027# 'mode' => 'std',
950 1028#
951 ); 1029# );
952 $correctAnswer = cplx($correctAnswer,0) unless ref($correctAnswer) =~/Complex/; 1030# $correctAnswer = cplx($correctAnswer,0) unless ref($correctAnswer) =~/Complex/;
953 my $format = $cplx_params{'format'}; 1031# my $format = $cplx_params{'format'};
954 my $mode = $cplx_params{'mode'}; 1032# my $mode = $cplx_params{'mode'};
955 1033#
956 if( $cplx_params{tolType} eq 'relative' ) { 1034# if( $cplx_params{tolType} eq 'relative' ) {
957 $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'}; 1035# $cplx_params{'tolerance'} = .01*$cplx_params{'relTol'};
958 } 1036# }
959 1037#
960 my $formattedCorrectAnswer; 1038# my $formattedCorrectAnswer;
961 my $correct_num_answer; 1039# my $correct_num_answer;
962 my $corrAnswerIsString = 0; 1040# my $corrAnswerIsString = 0;
963 1041#
964 1042#
965 if (defined($cplx_params{strings}) && $cplx_params{strings}) { 1043# if (defined($cplx_params{strings}) && $cplx_params{strings}) {
966 my $legalString = ''; 1044# my $legalString = '';
967 my @legalStrings = @{$cplx_params{strings}}; 1045# my @legalStrings = @{$cplx_params{strings}};
968 $correct_num_answer = $correctAnswer; 1046# $correct_num_answer = $correctAnswer;
969 $formattedCorrectAnswer = $correctAnswer; 1047# $formattedCorrectAnswer = $correctAnswer;
970 foreach $legalString (@legalStrings) { 1048# foreach $legalString (@legalStrings) {
971 if ( uc($correctAnswer) eq uc($legalString) ) { 1049# if ( uc($correctAnswer) eq uc($legalString) ) {
972 $corrAnswerIsString = 1; 1050# $corrAnswerIsString = 1;
973 1051#
974 last; 1052# last;
975 } 1053# }
976 } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric 1054# } ## at this point $corrAnswerIsString = 0 iff correct answer is numeric
977 } else { 1055# } else {
978 $correct_num_answer = $correctAnswer; 1056# $correct_num_answer = $correctAnswer;
979 $formattedCorrectAnswer = prfmt( $correctAnswer, $cplx_params{'format'} ); 1057# $formattedCorrectAnswer = prfmt( $correctAnswer, $cplx_params{'format'} );
980 } 1058# }
981 $correct_num_answer = math_constants($correct_num_answer); 1059# $correct_num_answer = math_constants($correct_num_answer);
982 my $PGanswerMessage = ''; 1060# my $PGanswerMessage = '';
983 1061#
984 my ($inVal,$correctVal,$PG_eval_errors,$PG_full_error_report); 1062# my ($inVal,$correctVal,$PG_eval_errors,$PG_full_error_report);
985 1063#
986 if (defined($correct_num_answer) && $correct_num_answer =~ /\S/ && $corrAnswerIsString == 0 ) { 1064# if (defined($correct_num_answer) && $correct_num_answer =~ /\S/ && $corrAnswerIsString == 0 ) {
987 ($correctVal, $PG_eval_errors,$PG_full_error_report) = PG_answer_eval($correct_num_answer); 1065# ($correctVal, $PG_eval_errors,$PG_full_error_report) = PG_answer_eval($correct_num_answer);
988 } else { # case of a string answer 1066# } else { # case of a string answer
989 $PG_eval_errors = ' '; 1067# $PG_eval_errors = ' ';
990 $correctVal = $correctAnswer; 1068# $correctVal = $correctAnswer;
991 } 1069# }
992 1070#
993 if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal)) && $corrAnswerIsString == 0)) { 1071# if ( ($PG_eval_errors && $corrAnswerIsString == 0) or ((not is_a_number($correctVal)) && $corrAnswerIsString == 0)) {
994 ##error message from eval or above 1072# ##error message from eval or above
995 warn "Error in 'correct' answer: $PG_eval_errors<br> 1073# warn "Error in 'correct' answer: $PG_eval_errors<br>
996 The answer $correctAnswer evaluates to $correctVal, 1074# The answer $correctAnswer evaluates to $correctVal,
997 which cannot be interpreted as a number. "; 1075# which cannot be interpreted as a number. ";
998 1076#
999 } 1077# }
1000 ######################################################################## 1078# ########################################################################
1001 $correctVal = $correct_num_answer;#it took me two and a half hours to figure out that correctVal wasn't 1079# $correctVal = $correct_num_answer;#it took me two and a half hours to figure out that correctVal wasn't
1002 #getting the number properly 1080# #getting the number properly
1003 #construct the answer evaluator 1081# #construct the answer evaluator
1004 my $counter = 0; 1082# my $counter = 0;
1005 my $answer_evaluator = new AnswerEvaluator; 1083# my $answer_evaluator = new AnswerEvaluator;
1006 1084#
1007 my $number; 1085# my $number;
1008 $answer_evaluator->install_pre_filter( sub{ my $rh_ans = shift; my @temp = 1086# $answer_evaluator->install_pre_filter( sub{ my $rh_ans = shift; my @temp =
1009 split/,/,$rh_ans->{student_ans}; $number = @temp; warn "this number ", $number; $rh_ans;}); 1087# split/,/,$rh_ans->{student_ans}; $number = @temp; warn "this number ", $number; $rh_ans;});
1010 warn "number ", $number; 1088# warn "number ", $number;
1011 while( $counter < 4 ) 1089# while( $counter < 4 )
1012 { 1090# {
1013 $answer_evaluator = &answer_mult( $correctVal, $mode, $formattedCorrectAnswer, 1091# $answer_evaluator = &answer_mult( $correctVal, $mode, $formattedCorrectAnswer,
1014 $corrAnswerIsString, $counter, %cplx_params ); 1092# $corrAnswerIsString, $counter, %cplx_params );
1015 warn "answer_evaluator ", $answer_evaluator; 1093# warn "answer_evaluator ", $answer_evaluator;
1016 $answer_evaluator->install_evaluator( sub { my $rh_ans = shift; warn "score ", $rh_ans->{score}; 1094# $answer_evaluator->install_evaluator( sub { my $rh_ans = shift; warn "score ", $rh_ans->{score};
1017 $rh_ans;}); 1095# $rh_ans;});
1018 $counter += 1; 1096# $counter += 1;
1019 } 1097# }
1020 1098#
1021 $answer_evaluator; 1099# $answer_evaluator;
1100#
1101# }
1022 1102
1023} 1103# this does not seem to be in use, so I'm commenting it out. Mike Gage 6/27/05
1024
1025sub answer_mult{ 1104# sub answer_mult{
1026 my $correctVal = shift; 1105# my $correctVal = shift;
1027 my $mode = shift; 1106# my $mode = shift;
1028 my $formattedCorrectAnswer = shift; 1107# my $formattedCorrectAnswer = shift;
1029 my $corrAnswerIsString = shift; 1108# my $corrAnswerIsString = shift;
1030 my $counter = shift; 1109# my $counter = shift;
1031 warn "counter ", $counter; 1110# warn "counter ", $counter;
1032 1111#
1033 my %cplx_params = @_; 1112# my %cplx_params = @_;
1034 my $answer_evaluator = new AnswerEvaluator; 1113# my $answer_evaluator = new AnswerEvaluator;
1035 1114#
1036 1115#
1037 $answer_evaluator->{debug} = $cplx_params{debug}; 1116# $answer_evaluator->{debug} = $cplx_params{debug};
1038 $answer_evaluator->ans_hash( 1117# $answer_evaluator->ans_hash(
1039 correct_ans => $correctVal, 1118# correct_ans => $correctVal,
1040 type => "${mode}_number", 1119# type => "${mode}_number",
1041 tolerance => $cplx_params{tolerance}, 1120# tolerance => $cplx_params{tolerance},
1042 tolType => 'absolute', # $cplx_params{tolType}, 1121# tolType => 'absolute', # $cplx_params{tolType},
1043 original_correct_ans => $formattedCorrectAnswer, 1122# original_correct_ans => $formattedCorrectAnswer,
1044 answerIsString => $corrAnswerIsString, 1123# answerIsString => $corrAnswerIsString,
1045 answer_form => 'cartesian', 1124# answer_form => 'cartesian',
1046 ); 1125# );
1047 $answer_evaluator->install_pre_filter(sub { 1126# $answer_evaluator->install_pre_filter(sub {
1048 my $rh_ans = shift; 1127# my $rh_ans = shift;
1049 $rh_ans->{original_student_ans} = $rh_ans->{student_ans}; 1128# $rh_ans->{original_student_ans} = $rh_ans->{student_ans};
1050 my @answers = split/,/,$rh_ans->{student_ans}; 1129# my @answers = split/,/,$rh_ans->{student_ans};
1051 $rh_ans -> {student_ans} = $answers[$counter]; 1130# $rh_ans -> {student_ans} = $answers[$counter];
1052 $rh_ans; 1131# $rh_ans;
1053 } 1132# }
1054 ); 1133# );
1055 if (defined($cplx_params{strings}) && $cplx_params{strings}) { 1134# if (defined($cplx_params{strings}) && $cplx_params{strings}) {
1056 $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params); 1135# $answer_evaluator->install_pre_filter(\&check_strings, %cplx_params);
1057 } 1136# }
1058 $answer_evaluator->install_pre_filter(\&check_syntax); 1137# $answer_evaluator->install_pre_filter(\&check_syntax);
1059 $answer_evaluator->install_pre_filter(\&math_constants); 1138# $answer_evaluator->install_pre_filter(\&math_constants);
1060 $answer_evaluator->install_pre_filter(\&cplx_constants); 1139# $answer_evaluator->install_pre_filter(\&cplx_constants);
1061 $answer_evaluator->install_pre_filter(\&check_for_polar); 1140# $answer_evaluator->install_pre_filter(\&check_for_polar);
1062 if ($mode eq 'std') { 1141# if ($mode eq 'std') {
1063 # do nothing 1142# # do nothing
1064 } elsif ($mode eq 'strict_polar') { 1143# } elsif ($mode eq 'strict_polar') {
1065 $answer_evaluator->install_pre_filter(\&is_a_polar); 1144# $answer_evaluator->install_pre_filter(\&is_a_polar);
1066 } elsif ($mode eq 'strict_num_cartesian') { 1145# } elsif ($mode eq 'strict_num_cartesian') {
1067 $answer_evaluator->install_pre_filter(\&is_a_numeric_cartesian); 1146# $answer_evaluator->install_pre_filter(\&is_a_numeric_cartesian);
1068 } elsif ($mode eq 'strict_num_polar') { 1147# } elsif ($mode eq 'strict_num_polar') {
1069 $answer_evaluator->install_pre_filter(\&is_a_numeric_polar); 1148# $answer_evaluator->install_pre_filter(\&is_a_numeric_polar);
1070 } elsif ($mode eq 'strict') { 1149# } elsif ($mode eq 'strict') {
1071 $answer_evaluator->install_pre_filter(\&is_a_numeric_complex); 1150# $answer_evaluator->install_pre_filter(\&is_a_numeric_complex);
1072 } elsif ($mode eq 'arith') { 1151# } elsif ($mode eq 'arith') {
1073 $answer_evaluator->install_pre_filter(\&is_an_arithmetic_expression); 1152# $answer_evaluator->install_pre_filter(\&is_an_arithmetic_expression);
1074 } elsif ($mode eq 'frac') { 1153# } elsif ($mode eq 'frac') {
1075 $answer_evaluator->install_pre_filter(\&is_a_fraction); 1154# $answer_evaluator->install_pre_filter(\&is_a_fraction);
1076 1155#
1077 } else { 1156# } else {
1078 #$PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.'; 1157# #$PGanswerMessage = 'Tell your professor that there is an error in his or her answer mechanism. No mode was specified.';
1079 } 1158# }
1080 if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string. 1159# if ($corrAnswerIsString == 0 ){ # avoiding running compare_numbers when correct answer is a string.
1081 $answer_evaluator->install_evaluator(\&compare_cplx, %cplx_params); 1160# $answer_evaluator->install_evaluator(\&compare_cplx, %cplx_params);
1082 } 1161# }
1083 1162#
1084 1163#
1085############################################################################### 1164# ###############################################################################
1086# We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's 1165# # We'll leave these next lines out for now, so that the evaluated versions of the student's and professor's
1087# can be displayed in the answer message. This may still cause a few anomolies when strings are used 1166# # can be displayed in the answer message. This may still cause a few anomolies when strings are used
1088# 1167# #
1089############################################################################### 1168# ###############################################################################
1090 1169#
1091 $answer_evaluator->install_post_filter(\&fix_answers_for_display); 1170# $answer_evaluator->install_post_filter(\&fix_answers_for_display);
1092 $answer_evaluator->install_post_filter(\&fix_for_polar_display); 1171# $answer_evaluator->install_post_filter(\&fix_for_polar_display);
1093 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; 1172# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift;
1094 return $rh_ans unless $rh_ans->catch_error('EVAL'); 1173# return $rh_ans unless $rh_ans->catch_error('EVAL');
1095 $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message}; 1174# $rh_ans->{student_ans} = $rh_ans->{original_student_ans}. ' '. $rh_ans->{error_message};
1096 $rh_ans->clear_error('EVAL'); } ); 1175# $rh_ans->clear_error('EVAL'); } );
1097 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } ); 1176# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('SYNTAX'); } );
1098 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } ); 1177# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('POLAR'); } );
1099 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } ); 1178# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('CARTESIAN'); } );
1100 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } ); 1179# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; $rh_ans->clear_error('COMPLEX'); } );
1101 $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; warn "ans hash", $rh_ans->clear_error('STRING'); } ); 1180# $answer_evaluator->install_post_filter(sub {my $rh_ans = shift; warn "ans hash", $rh_ans->clear_error('STRING'); } );
1102 $answer_evaluator; 1181# $answer_evaluator;
1103} 1182# }
1104 1183#
1105 1184
1106 1185
11071; 11861;

Legend:
Removed from v.2986  
changed lines
  Added in v.3319

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9