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

Annotation of /trunk/pg/macros/answerComposition.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5054 - (view) (download) (as text)

1 : gage 4997
2 :    
3 :     =head1 DESCRIPTION
4 :    
5 : dpvc 2732 ######################################################################
6 :     #
7 :     # An answer checker that determines if two functions compose
8 :     # to form a given function. (For use in problems where you ask
9 :     # a student to break a given function into a composition of two
10 :     # simpler functions, neither of which is allowed to be the identity
11 :     # function.)
12 :     #
13 :    
14 : gage 4997 =cut
15 :    
16 : dpvc 2732 sub _answerComposition_init {}; # don't reload this file
17 :    
18 : gage 4997 =head3 COMPOSITION_ANS($fn_f,$fn_g)
19 :    
20 : dpvc 2732 ######################################################################
21 :     #
22 :     # An answer checked to see if f composed with g matches a given function.
23 :     #
24 :     # Usage: COMPOSITION_ANS(f,g,options)
25 :     #
26 :     # where f and g are one possible decomposition of the target function
27 :     # (these are used to display the "correct" answer, and the composition
28 :     # is computed from them) and options are any of the options allowed
29 :     # by composition_ans_list() below.
30 :     #
31 :     # This function actually supplies TWO answer checkers, for the two
32 :     # previous answer blanks. So be sure to call it immediately after
33 :     # the answer blanks have been supplied. (It may be best to use the
34 :     # NAMED_COMPOSITION_ANS checker below, which specifies the answer
35 :     # blanks explicitly.)
36 :     #
37 :     # Example:
38 :     #
39 :     # BEGIN_TEXT
40 :     # \(f\circ g = (1+x)^2\) when
41 :     # \(f(x)\) = \{ans_rule(20)\} and \(g(x)\) = \{ans_rule(20)\}
42 :     # END_TEXT
43 :     # COMPOSITION_ANS("x^2","1+x");
44 :     #
45 : gage 4997
46 :     =cut
47 :    
48 : dpvc 2732 sub COMPOSITION_ANS {
49 :     my $f = shift; my $g = shift;
50 :     my $fID = ANS_NUM_TO_NAME($main::ans_rule_count-1);
51 :     my $gID = ANS_NUM_TO_NAME($main::ans_rule_count);
52 :     my %ans = composition_ans_list($fID=>$f,$gID=>$g,@_);
53 :     ANS($ans{$fID},$ans{$gID});
54 :     }
55 :    
56 : gage 4997 =head3 NAMED_COMPOSITION_ANS(fID=>f,gID=>g,options)
57 : dpvc 2732
58 :     ######################################################################
59 :     #
60 :     # An answer checked to see if f composed with g matches a given function.
61 :     #
62 : gage 4997 # Usage: NAMED_COMPOSITION_ANS(fID=>f,gID=>g,options)
63 : dpvc 2732 #
64 :     # where fID and gID are the names of the answer rules for the functions
65 :     # f and g, and f and g are the answers for the functions. Options are
66 :     # any of the options allowed by composition_ans_list() below.
67 :     #
68 :     # This routine allows you to put the f and g answer blanks at any
69 :     # location in the problem, and in any order.
70 :     #
71 :     # Example:
72 :     #
73 :     # BEGIN_TEXT
74 :     # \(g\circ f = (1+x)^2\) when
75 :     # \(f(x)\) = \{NAMED_ANS('f',20)\} and \(g(x)\) = \{NAMED_ANS('g',20)\}
76 :     # END_TEXT
77 :     # NAMED_COMPOSITION_ANS(f => "x^2", g => "1+x");
78 :     #
79 : gage 4997
80 :     =cut
81 :    
82 : dpvc 2732 sub NAMED_COMPOSITION_ANS {NAMED_ANS(composition_ans_list(@_))}
83 :    
84 : gage 4997 =head3 composition_ans_list(fID=>f,gID=>g,options)
85 :    
86 : dpvc 2732 ######################################################################
87 :     #
88 :     # This is an internal routine that returns the named answer checkers
89 :     # used by COMPOSITION_ANS and NAMED_COMPOSITION_ANS above.
90 :     #
91 :     # Usage: composition_ans_list(fID=>f,gID=>g,options)
92 :     #
93 :     # where fID and gID are the names of the answer rules for the functions
94 :     # and f and g are the answers for these functions. Options are from
95 :     # among:
96 :     #
97 :     # var => 'x' the name of the variable to use when
98 :     # both functions use the same one
99 :     #
100 : gage 4997 # vars => ['x','t'] the names of the variables for f and g
101 : dpvc 2732 #
102 :     # showVariableHints => 1 or 0
103 :     # do/don't show errors when the variable
104 :     # used by the student is incorrect
105 :     #
106 :    
107 : gage 4997 =cut
108 :    
109 : dpvc 2732 sub composition_ans_list {
110 :     my ($fID,$f,$gID,$g,%params) = @_; my @IDs = ($fID,$gID);
111 :     #
112 :     # Get options
113 :     #
114 :     $params{vars} = [$params{var},$params{var}] if $params{var} && !$params{vars};
115 :     $params{showVariableHints} = 1 unless defined($params{showVariableHints});
116 :     my $isPreview = $main::inputs_ref->{previewAnswers};
117 :     my $vars = $params{vars} || [];
118 :     my @options = (ignoreInfinity=>0,ignoreStrings=>0);
119 :     my ($i,$error);
120 :    
121 :     #
122 :     # Get correct answer data and determine which variables to use
123 :     #
124 : dpvc 5054 $f = Value->Package("Formula")->new($f); $g = Value->Package("Formula")->new($g);
125 : dpvc 2732 my %correct = ($fID => $f, $gID => $g);
126 :     my %x = ($fID => $vars->[0], $gID => $vars->[1]);
127 :     foreach $i (@IDs) {
128 :     unless ($x{$i}) {
129 :     die "Can't tell which variable to use for $correct{$i}: ".
130 :     "use var=>'x' or vars=>['x','y'] to specify it"
131 :     if scalar(keys %{$correct{$i}->{variables}}) > 1;
132 :     $x{$i} = (keys %{$correct{$i}->{variables}})[0];
133 :     }
134 :     die "$correct{$i} is not a function of $x{$i}"
135 :     unless defined($correct{$i}->{variables}{$x{$i}});
136 :     }
137 :     my %y = ($fID => $x{$gID}, $gID => $x{$fID});
138 :     my %ans = ($fID => message_cmp($f), $gID => message_cmp($g));
139 :     my $fog = $f->substitute($x{$fID}=>$g); # the composition
140 :    
141 :     #
142 :     # Check that the student formulas parse OK,
143 :     # produce a number, contain the correct variable,
144 :     # don't contain the composition itself in a simple way,
145 :     # and aren't the identity.
146 :     #
147 :     my %student = ($fID => $main::inputs_ref->{$fID},
148 :     $gID => $main::inputs_ref->{$gID});
149 :     foreach $i (@IDs) {
150 :     next unless defined($student{$i});
151 :     $student{$i} = Parser::Formula($student{$i});
152 :     if (!defined($student{$i})) {$error = 1; next}
153 :     $ans{$i}->{rh_ans}{preview_latex_string} = $student{$i}->TeX;
154 :     if ($student{$i}->type ne 'Number') {
155 :     $ans{$i} = $correct{$i}->cmp(@options);
156 :     $error = 1; next;
157 :     }
158 :     if ($x{$fID} ne $x{$gID} && defined($student{$i}->{variables}{$y{$i}})) {
159 :     $ans{$i}->{rh_ans}{ans_message} = "Your formula may not contain $y{$i}"
160 :     unless $isPreview || !$params{showVariableHints};
161 :     $error = 1; next;
162 :     }
163 :     if (!defined($student{$i}->{variables}{$x{$i}})) {
164 :     $ans{$i}->{rh_ans}{ans_message} = "Your formula is not a function of $x{$i}"
165 :     unless $isPreview || !$params{showVariableHints};
166 :     $error = 1; next;
167 :     }
168 :     if (($student{$i}->{tree}->class eq 'BOP' &&
169 :     ($fog == $student{$i}->{tree}{lop} || $fog == $student{$i}->{tree}{rop})) ||
170 :     ($student{$i}->{tree}->class eq 'UOP' && $fog == $student{$i}->{tree}{op})) {
171 :     $ans{$i}->{rh_ans}{ans_message} =
172 :     "Your formula may not have the composition as one of its terms";
173 :     $error = 1; next;
174 :     }
175 :     if ($fog == $student{$i}) {
176 :     $ans{$i}->{rh_ans}{ans_message} =
177 :     "Your formula my not be the composition itself";
178 :     $error = 1; next;
179 :     }
180 :     if ($student{$i} == $x{$i}) {
181 :     $ans{$i}->{rh_ans}{ans_message} = "The identity function is not allowed"
182 :     unless $isPreview;
183 :     $error = 1; next;
184 :     }
185 : dpvc 5054
186 : dpvc 2732 }
187 :    
188 :     #
189 : gage 4997 # If no error, and both answers are given, check if compositions are equal
190 : dpvc 2732 #
191 :     if (!$error && defined($student{$fID}) && defined($student{$gID})) {
192 :     if ($fog == $student{$fID}->substitute($x{$fID}=>$student{$gID})) {
193 :     $ans{$fID}->{rh_ans}{score} = $ans{$gID}->{rh_ans}{score} = 1;
194 :     }
195 :     }
196 :    
197 :     return (%ans);
198 :     }
199 :    
200 :    
201 :     ######################################################################
202 :     #
203 :     # Evaluator that always returns incorrect, with a given error
204 :     # message. Used by COMPOSITION_ANS to produce "dummy" answer
205 :     # checkers for the two parts of the composition.
206 :     #
207 :     sub message_cmp {
208 :     my $correct = shift;
209 :     my $answerEvaluator = new AnswerEvaluator;
210 :     $answerEvaluator->ans_hash(
211 :     type => "message",
212 :     correct_ans => $correct->string,
213 :     ans_message => $message,
214 :     );
215 :     $answerEvaluator->install_evaluator(sub {shift});
216 :     return $answerEvaluator;
217 :     }
218 :    
219 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9