[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 3601 - (download) (as text) (annotate)
Tue Sep 6 21:02:05 2005 UTC (14 years, 4 months ago) by dpvc
File size: 47896 byte(s)
Movified the copying of functions from Complex1:: into main:: to avoid
conflicts with the PGcommonFunctions.pl versions (these errors were
trapped, but still show up in the error log unnecessarily).

Also commented out some code that was not doing anything other than
producing error messages in the error log.  (It was left over from a
syntax check on the professor's answer, but the actual check was
removed, leaving a portion that tries to process the answer, but
usually fails (because things like "1+4i" need to be converted to
"1+4*i" before they can be used in PG_answer_eval, but that was not
being done).

Because of this, it is not possible currently to do cplx_cmp("1+4i"),
and instead you must to cplx_cmp(new Complex(1,4)).

To fix this, you would need to call check_syntax (and the other
filters that are called on the student's answer) before calling
PG_answer_eval.  Of course, you should only do this when the
professor's answer isn't already a Complex object.

I am going to work on a Legacy module like the ones for num_cmp and
fun_cmp to replace cplx_cmp, which should avoid these problems and
make the changes suggested above unnecessary.

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9