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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3319 - (download) (as text) (annotate)
Tue Jun 28 19:36:52 2005 UTC (14 years, 7 months ago) by gage
File size: 46738 byte(s)
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