[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 1102 - (download) (as text) (annotate)
Tue Jun 10 16:23:47 2003 UTC (16 years, 8 months ago) by lr003k
File size: 42176 byte(s)
ok, I'm pretty sure that this one is the one we want. Unfortunately the other one was an old one, that cmpl_cmp4 was not used
anywhere and I had removed it later, and this one has multi_cmp. Sorry for all the confusion.

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9