| … | |
… | |
| 5 | # is, macros allowing a more flexible answer checking |
5 | # is, macros allowing a more flexible answer checking |
| 6 | #################################################################### |
6 | #################################################################### |
| 7 | # Copyright @ 1995-2000 University of Rochester |
7 | # Copyright @ 1995-2000 University of Rochester |
| 8 | # All Rights Reserved |
8 | # All Rights Reserved |
| 9 | #################################################################### |
9 | #################################################################### |
| 10 | |
10 | #$Id$ |
| 11 | |
11 | |
| 12 | =head1 NAME |
12 | =head1 NAME |
| 13 | |
13 | |
| 14 | PGanswermacros.pl -- located in the courseScripts directory |
14 | PGanswermacros.pl -- located in the courseScripts directory |
| 15 | |
15 | |
| … | |
… | |
| 107 | =cut |
107 | =cut |
| 108 | |
108 | |
| 109 | BEGIN { |
109 | BEGIN { |
| 110 | be_strict(); # an alias for use strict. This means that all global variable must contain main:: as a prefix. |
110 | be_strict(); # an alias for use strict. This means that all global variable must contain main:: as a prefix. |
| 111 | } |
111 | } |
|
|
112 | sub _PGanswermacros_export { |
|
|
113 | my @EXPORT = ( |
|
|
114 | '&std_num_cmp', '&std_num_cmp_list', '&std_num_cmp_abs', |
|
|
115 | '&std_num_cmp_abs_list', '&frac_num_cmp', '&frac_num_cmp_list', |
|
|
116 | '&frac_num_cmp_abs', '&frac_num_cmp_abs_list', '&arith_num_cmp', |
|
|
117 | '&arith_num_cmp_list', '&arith_num_cmp_abs', '&arith_num_cmp_abs_list', |
|
|
118 | '&strict_num_cmp', '&strict_num_cmp_list', '&strict_num_cmp_abs', |
|
|
119 | '&strict_num_cmp_abs_list', '&numerical_compare_with_units', |
|
|
120 | '&std_num_str_cmp', '&num_cmp', '&num_rel_cmp', '&NUM_CMP', |
|
|
121 | '&NUM_CMP_LIST', '&adaptive_function_cmp', '&function_cmp', |
|
|
122 | '&function_cmp_up_to_constant', '&function_cmp_abs', |
|
|
123 | '&function_cmp_up_to_constant_abs', '&multivar_function_cmp', |
|
|
124 | '&fun_cmp', '&FUNCTION_CMP', '&is_array', '&check_syntax', |
|
|
125 | '&std_num_filter', '&std_num_array_filter', '&function_from_string2', |
|
|
126 | '&is_zero_array', '&best_approx_parameters', |
|
|
127 | '&calculate_difference_vector', '&str_filters', '&remove_whitespace', |
|
|
128 | '&compress_whitespace', '&trim_whitespace', '&ignore_case', |
|
|
129 | '&ignore_order', '&std_str_cmp', '&std_str_cmp_list', '&std_cs_str_cmp', |
|
|
130 | '&std_cs_str_cmp_list', '&strict_str_cmp', '&strict_str_cmp_list', |
|
|
131 | '&unordered_str_cmp', '&unordered_str_cmp_list', |
|
|
132 | '&unordered_cs_str_cmp', '&unordered_cs_str_cmp_list', |
|
|
133 | '&ordered_str_cmp', '&ordered_str_cmp_list', '&ordered_cs_str_cmp', |
|
|
134 | '&ordered_cs_str_cmp_list', '&str_cmp', '&STR_CMP', '&checkbox_cmp', |
|
|
135 | '&radio_cmp', '&store_ans_at', '&DUMMY_ANSWER', '&escapeHTML', |
|
|
136 | '&anstext', '&ansradio', '&mail_answers_to', '&mail_answers_to2', |
|
|
137 | '&install_problem_grader', '&std_problem_grader', |
|
|
138 | '&std_problem_grader2', '&avg_problem_grader', '&get_var_array', |
|
|
139 | '&get_limits_array', '&check_option_list', '&function_invalid_params', |
|
|
140 | '&is_a_number', '&is_a_fraction', '&is_an_arithmetic_expression', |
|
|
141 | '&math_constants', '&clean_up_error_msg', '&prfmt', '&pretty_print', |
|
|
142 | '&set_default_options', '&assign_option_aliases', |
|
|
143 | ); |
|
|
144 | @EXPORT; |
|
|
145 | } |
| 112 | |
146 | |
|
|
147 | my ($BR, $PAR,$numRelPercentTolDefault,$numZeroLevelDefault,$numZeroLevelTolDefault, |
|
|
148 | $numAbsTolDefault,$numFormatDefault,$functRelPercentTolDefault,$functZeroLevelDefault, |
|
|
149 | $functZeroLevelTolDefault,$functAbsTolDefault,$functNumOfPoints,$functVarDefault, |
|
|
150 | $functLLimitDefault, $functULimitDefault, $functMaxConstantOfIntegration, |
|
|
151 | ); |
|
|
152 | |
|
|
153 | sub _PGanswermacros_init { |
|
|
154 | PG_restricted_eval(q{ |
| 113 | my $BR = $main::BR; # convenient localizations. |
155 | $BR = $main::BR; # convenient localizations. |
| 114 | my $PAR = $main::PAR; |
156 | $PAR = $main::PAR; |
| 115 | |
157 | |
| 116 | # import defaults |
158 | # import defaults |
| 117 | # these are now imported from the %envir variable |
159 | # these are now imported from the %envir variable |
| 118 | my $numRelPercentTolDefault = $main::numRelPercentTolDefault; |
160 | $numRelPercentTolDefault = $main::numRelPercentTolDefault; |
| 119 | my $numZeroLevelDefault = $main::numZeroLevelDefault; |
161 | $numZeroLevelDefault = $main::numZeroLevelDefault; |
| 120 | my $numZeroLevelTolDefault = $main::numZeroLevelTolDefault; |
162 | $numZeroLevelTolDefault = $main::numZeroLevelTolDefault; |
| 121 | my $numAbsTolDefault = $main::numAbsTolDefault; |
163 | $numAbsTolDefault = $main::numAbsTolDefault; |
| 122 | my $numFormatDefault = $main::numFormatDefault; |
164 | $numFormatDefault = $main::numFormatDefault; |
| 123 | |
165 | |
| 124 | my $functRelPercentTolDefault = $main::functRelPercentTolDefault; |
166 | $functRelPercentTolDefault = $main::functRelPercentTolDefault; |
| 125 | my $functZeroLevelDefault = $main::functZeroLevelDefault; |
167 | $functZeroLevelDefault = $main::functZeroLevelDefault; |
| 126 | my $functZeroLevelTolDefault = $main::functZeroLevelTolDefault; |
168 | $functZeroLevelTolDefault = $main::functZeroLevelTolDefault; |
| 127 | my $functAbsTolDefault = $main::functAbsTolDefault; |
169 | $functAbsTolDefault = $main::functAbsTolDefault; |
| 128 | my $functNumOfPoints = $main::functNumOfPoints; |
170 | $functNumOfPoints = $main::functNumOfPoints; |
| 129 | my $functVarDefault = $main::functVarDefault; |
171 | $functVarDefault = $main::functVarDefault; |
| 130 | my $functLLimitDefault = $main::functLLimitDefault; |
172 | $functLLimitDefault = $main::functLLimitDefault; |
| 131 | my $functULimitDefault = $main::functULimitDefault; |
173 | $functULimitDefault = $main::functULimitDefault; |
| 132 | my $functMaxConstantOfIntegration = $main::functMaxConstantOfIntegration; |
174 | $functMaxConstantOfIntegration = $main::functMaxConstantOfIntegration; |
|
|
175 | |
|
|
176 | } |
|
|
177 | ); |
| 133 | |
178 | |
| 134 | |
179 | } |
| 135 | |
180 | |
| 136 | ########################################################################## |
181 | ########################################################################## |
| 137 | ########################################################################## |
182 | ########################################################################## |
| 138 | ## Number answer evaluators |
183 | ## Number answer evaluators |
| 139 | |
184 | |
| … | |
… | |
| 466 | |
511 | |
| 467 | num_cmp(\@answerList, %options); |
512 | num_cmp(\@answerList, %options); |
| 468 | |
513 | |
| 469 | } |
514 | } |
| 470 | |
515 | |
|
|
516 | |
| 471 | sub frac_num_cmp_abs { # only allow fraction expressions as submitted answer with absolute tolerance |
517 | sub frac_num_cmp_abs { # only allow fraction expressions as submitted answer with absolute tolerance |
| 472 | my ( $correctAnswer, $absTol, $format ) = @_; |
518 | my ( $correctAnswer, $absTol, $format ) = @_; |
| 473 | |
519 | |
| 474 | my %options = ( 'tolerance' => $absTol, |
520 | my %options = ( 'tolerance' => $absTol, |
| 475 | 'format' => $format |
521 | 'format' => $format |
| … | |
… | |
| 484 | 'zeroLevelTol' => 0, |
530 | 'zeroLevelTol' => 0, |
| 485 | 'debug' => 0, |
531 | 'debug' => 0, |
| 486 | ); |
532 | ); |
| 487 | num_cmp([$correctAnswer], %options); |
533 | num_cmp([$correctAnswer], %options); |
| 488 | |
534 | |
|
|
535 | |
| 489 | } |
536 | } |
| 490 | |
537 | |
| 491 | ## See std_num_cmp_list for usage |
538 | ## See std_num_cmp_list for usage |
| 492 | sub frac_num_cmp_abs_list { |
539 | sub frac_num_cmp_abs_list { |
| 493 | my ( $absTol, $format, @answerList ) = @_; |
540 | my ( $absTol, $format, @answerList ) = @_; |
| … | |
… | |
| 669 | |
716 | |
| 670 | ## See std_num_cmp_list for usage |
717 | ## See std_num_cmp_list for usage |
| 671 | sub strict_num_cmp_abs_list { # compare numbers |
718 | sub strict_num_cmp_abs_list { # compare numbers |
| 672 | my ( $absTol, $format, @answerList ) = @_; |
719 | my ( $absTol, $format, @answerList ) = @_; |
| 673 | |
720 | |
|
|
721 | |
| 674 | my %options = ( 'tolerance' => $absTol, |
722 | my %options = ( 'tolerance' => $absTol, |
| 675 | 'format' => $format |
723 | 'format' => $format |
| 676 | ); |
724 | ); |
| 677 | |
725 | |
| 678 | set_default_options (\%options, |
726 | set_default_options (\%options, |
| … | |
… | |
| 685 | 'debug' => 0, |
733 | 'debug' => 0, |
| 686 | ); |
734 | ); |
| 687 | |
735 | |
| 688 | num_cmp(\@answerList, %options); |
736 | num_cmp(\@answerList, %options); |
| 689 | |
737 | |
|
|
738 | |
|
|
739 | |
| 690 | } |
740 | } |
|
|
741 | |
| 691 | |
742 | |
| 692 | ## Compares a number with units |
743 | ## Compares a number with units |
| 693 | ## Deprecated; use num_cmp() |
744 | ## Deprecated; use num_cmp() |
| 694 | ## |
745 | ## |
| 695 | ## IN: a string which includes the numerical answer and the units |
746 | ## IN: a string which includes the numerical answer and the units |
| … | |
… | |
| 698 | ## format -- the format to use when displaying the answer |
749 | ## format -- the format to use when displaying the answer |
| 699 | ## tol -- an absolute tolerance, or |
750 | ## tol -- an absolute tolerance, or |
| 700 | ## relTol -- a relative tolerance |
751 | ## relTol -- a relative tolerance |
| 701 | ## zeroLevel -- if the correct answer is this close to zero, then zeroLevelTol applies |
752 | ## zeroLevel -- if the correct answer is this close to zero, then zeroLevelTol applies |
| 702 | ## zeroLevelTol -- absolute tolerance to allow when correct answer is close to zero |
753 | ## zeroLevelTol -- absolute tolerance to allow when correct answer is close to zero |
|
|
754 | |
|
|
755 | |
| 703 | |
756 | |
| 704 | |
757 | |
| 705 | sub check_units { |
758 | sub check_units { |
| 706 | my ($rh_ans, %options) = @_; |
759 | my ($rh_ans, %options) = @_; |
| 707 | |
760 | |
| … | |
… | |
| 1162 | 'tolerance' => 1, |
1215 | 'tolerance' => 1, |
| 1163 | 'reltol' => undef, #alternate spelling |
1216 | 'reltol' => undef, #alternate spelling |
| 1164 | 'unit' => undef); #alternate spelling |
1217 | 'unit' => undef); #alternate spelling |
| 1165 | |
1218 | |
| 1166 | my @output_list; |
1219 | my @output_list; |
|
|
1220 | my( $relPercentTol, $format, $zeroLevel, $zeroLevelTol) = @opt; |
| 1167 | |
1221 | |
| 1168 | unless( ref($correctAnswer) eq 'ARRAY' || scalar( @opt ) == 0 || |
1222 | unless( ref($correctAnswer) eq 'ARRAY' || scalar( @opt ) == 0 || |
| 1169 | ( defined($opt[0]) and exists $known_options{$opt[0]} ) ) { |
1223 | ( defined($opt[0]) and exists $known_options{$opt[0]} ) ) { |
| 1170 | # unless the first parameter is a list of arrays |
1224 | # unless the first parameter is a list of arrays |
| 1171 | # or the second parameter is a known option or |
1225 | # or the second parameter is a known option or |
| … | |
… | |
| 1173 | # use the old num_cmp which does not use options, but has inputs |
1227 | # use the old num_cmp which does not use options, but has inputs |
| 1174 | # $relPercentTol,$format,$zeroLevel,$zeroLevelTol |
1228 | # $relPercentTol,$format,$zeroLevel,$zeroLevelTol |
| 1175 | warn "This method of using num_cmp() is deprecated. Please rewrite this" . |
1229 | warn "This method of using num_cmp() is deprecated. Please rewrite this" . |
| 1176 | " problem using the options style of parameter passing (or" . |
1230 | " problem using the options style of parameter passing (or" . |
| 1177 | " check that your first option is spelled correctly)."; |
1231 | " check that your first option is spelled correctly)."; |
| 1178 | my( $relPercentTol, $format, $zeroLevel, $zeroLevelTol) = @opt; |
1232 | |
| 1179 | |
1233 | |
|
|
1234 | %out_options = ( 'relTol' => $relPercentTol, |
|
|
1235 | 'format' => $format, |
|
|
1236 | 'zeroLevel' => $zeroLevel, |
|
|
1237 | 'zeroLevelTol' => $zeroLevelTol, |
|
|
1238 | 'mode' => 'std' |
|
|
1239 | ); |
|
|
1240 | } |
|
|
1241 | else { |
|
|
1242 | # handle options |
|
|
1243 | |
|
|
1244 | |
| 1180 | @opt = ( 'relTol' => $relPercentTol, |
1245 | @opt = ( 'relTol' => $relPercentTol, |
| 1181 | 'format' => $format, |
1246 | 'format' => $format, |
| 1182 | 'zeroLevel' => $numZeroLevelDefault, |
1247 | 'zeroLevel' => $numZeroLevelDefault, |
| 1183 | 'zeroLevelTol' => $numZeroLevelTolDefault, |
1248 | 'zeroLevelTol' => $numZeroLevelTolDefault, |
| 1184 | 'mode' => 'std' |
1249 | 'mode' => 'std' |
| 1185 | ); |
1250 | ); |
| … | |
… | |
| 1193 | 'reltol' => 'relTol', |
1258 | 'reltol' => 'relTol', |
| 1194 | 'unit' => 'units', |
1259 | 'unit' => 'units', |
| 1195 | ); |
1260 | ); |
| 1196 | |
1261 | |
| 1197 | |
1262 | |
|
|
1263 | |
|
|
1264 | |
|
|
1265 | |
| 1198 | set_default_options( \%out_options, |
1266 | set_default_options( \%out_options, |
| 1199 | 'tolType' => (defined($out_options{tol}) ) ? 'absolute' : 'relative', |
1267 | 'tolType' => (defined($out_options{tol}) ) ? 'absolute' : 'relative', |
| 1200 | 'tolerance' => (defined($out_options{tol}) ) ? $numAbsTolDefault : $numRelPercentTolDefault, |
1268 | 'tolerance' => (defined($out_options{tol}) ) ? $numAbsTolDefault : $numRelPercentTolDefault, |
| 1201 | 'mode' => 'std', |
1269 | 'mode' => 'std', |
| 1202 | 'format' => $numFormatDefault, |
1270 | 'format' => $numFormatDefault, |
| … | |
… | |
| 1210 | |
1278 | |
| 1211 | ); |
1279 | ); |
| 1212 | |
1280 | |
| 1213 | |
1281 | |
| 1214 | |
1282 | |
|
|
1283 | |
|
|
1284 | |
|
|
1285 | |
|
|
1286 | |
| 1215 | # can't use both units and strings |
1287 | # can't use both units and strings |
| 1216 | if( defined( $out_options{'units'} ) && defined( $out_options{'strings'} ) ) { |
1288 | if( defined( $out_options{'units'} ) && defined( $out_options{'strings'} ) ) { |
| 1217 | warn "Can't use both 'units' and 'strings' in the same problem " . |
1289 | warn "Can't use both 'units' and 'strings' in the same problem " . |
| 1218 | "(check your parameters to num_cmp() )"; |
1290 | "(check your parameters to num_cmp() )"; |
|
|
1291 | |
| 1219 | } |
1292 | } |
| 1220 | |
1293 | |
| 1221 | |
1294 | |
| 1222 | # my ($tolType, $tol); |
1295 | # my ($tolType, $tol); |
| 1223 | if ($out_options{tolType} eq 'absolute') { |
1296 | if ($out_options{tolType} eq 'absolute') { |