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

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9