[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 5551 - (view) (download) (as text)

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9