[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 5556 - (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 :     # $CVSHeader: webwork2/lib/WeBWorK.pm,v 1.100 2007/08/13 22:59:53 sh002i Exp $
5 :     #
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 :     my $fID = ANS_NUM_TO_NAME($main::ans_rule_count-1);
64 :     my $gID = ANS_NUM_TO_NAME($main::ans_rule_count);
65 :     my %ans = composition_ans_list($fID=>$f,$gID=>$g,@_);
66 :     ANS($ans{$fID},$ans{$gID});
67 :     }
68 :    
69 : sh002i 5551 =head2 NAMED_COMPOSITION_ANS
70 : dpvc 2732
71 : sh002i 5551 NAMED_COMPOSITION_ANS($fID=>$f, $gID=>$g, %options)
72 : gage 4997
73 : sh002i 5551 An answer checked to see if $f composed with $g matches a given function, where
74 :     $fID and $gID are the names of the answer rules for the functions $f and $g, and
75 :     $f and $g are the answers for the functions. %options are any of the options
76 :     allowed by composition_ans_list() below.
77 :    
78 :     This routine allows you to put the answer blanks for $f and $g at any location
79 :     in the problem, and in any order.
80 :    
81 :     Example:
82 :    
83 :     BEGIN_TEXT
84 :     \(g\circ f = (1+x)^2\) when
85 :     \(f(x)\) = \{NAMED_ANS('f',20)\} and \(g(x)\) = \{NAMED_ANS('g',20)\}
86 :     END_TEXT
87 :     NAMED_COMPOSITION_ANS(f => "x^2", g => "1+x");
88 :    
89 : gage 4997 =cut
90 :    
91 : dpvc 2732 sub NAMED_COMPOSITION_ANS {NAMED_ANS(composition_ans_list(@_))}
92 :    
93 : sh002i 5551 =head2 composition_ans_list
94 : gage 4997
95 : sh002i 5551 composition_ans_list($fID=>$f, $gID=>$g, %options)
96 : dpvc 2732
97 : sh002i 5551 This is an internal routine that returns the named answer checkers
98 :     used by COMPOSITION_ANS and NAMED_COMPOSITION_ANS above.
99 :    
100 :     $fID and $gID are the names of the answer rules for the functions and $f and $g
101 :     are the answers for these functions. %options are from among:
102 :    
103 :     =over
104 :    
105 :     =item S<C<< var => 'x' >>>
106 :    
107 :     the name of the variable to use when
108 :     both functions use the same one
109 :    
110 :     =item S<C<< vars => ['x','t'] >>>
111 :    
112 :     the names of the variables for $f and $g
113 :    
114 :     =item S<C<< showVariableHints => 1 or 0 >>>
115 :    
116 :     do/don't show errors when the variable
117 :     used by the student is incorrect
118 :    
119 :     =back
120 :    
121 : gage 4997 =cut
122 :    
123 : dpvc 2732 sub composition_ans_list {
124 :     my ($fID,$f,$gID,$g,%params) = @_; my @IDs = ($fID,$gID);
125 :     #
126 :     # Get options
127 :     #
128 :     $params{vars} = [$params{var},$params{var}] if $params{var} && !$params{vars};
129 :     $params{showVariableHints} = 1 unless defined($params{showVariableHints});
130 :     my $isPreview = $main::inputs_ref->{previewAnswers};
131 :     my $vars = $params{vars} || [];
132 :     my @options = (ignoreInfinity=>0,ignoreStrings=>0);
133 :     my ($i,$error);
134 :    
135 :     #
136 :     # Get correct answer data and determine which variables to use
137 :     #
138 : dpvc 5054 $f = Value->Package("Formula")->new($f); $g = Value->Package("Formula")->new($g);
139 : dpvc 2732 my %correct = ($fID => $f, $gID => $g);
140 :     my %x = ($fID => $vars->[0], $gID => $vars->[1]);
141 :     foreach $i (@IDs) {
142 :     unless ($x{$i}) {
143 :     die "Can't tell which variable to use for $correct{$i}: ".
144 :     "use var=>'x' or vars=>['x','y'] to specify it"
145 :     if scalar(keys %{$correct{$i}->{variables}}) > 1;
146 :     $x{$i} = (keys %{$correct{$i}->{variables}})[0];
147 :     }
148 :     die "$correct{$i} is not a function of $x{$i}"
149 :     unless defined($correct{$i}->{variables}{$x{$i}});
150 :     }
151 :     my %y = ($fID => $x{$gID}, $gID => $x{$fID});
152 :     my %ans = ($fID => message_cmp($f), $gID => message_cmp($g));
153 :     my $fog = $f->substitute($x{$fID}=>$g); # the composition
154 :    
155 :     #
156 :     # Check that the student formulas parse OK,
157 :     # produce a number, contain the correct variable,
158 :     # don't contain the composition itself in a simple way,
159 :     # and aren't the identity.
160 :     #
161 :     my %student = ($fID => $main::inputs_ref->{$fID},
162 :     $gID => $main::inputs_ref->{$gID});
163 :     foreach $i (@IDs) {
164 :     next unless defined($student{$i});
165 :     $student{$i} = Parser::Formula($student{$i});
166 :     if (!defined($student{$i})) {$error = 1; next}
167 :     $ans{$i}->{rh_ans}{preview_latex_string} = $student{$i}->TeX;
168 :     if ($student{$i}->type ne 'Number') {
169 :     $ans{$i} = $correct{$i}->cmp(@options);
170 :     $error = 1; next;
171 :     }
172 :     if ($x{$fID} ne $x{$gID} && defined($student{$i}->{variables}{$y{$i}})) {
173 :     $ans{$i}->{rh_ans}{ans_message} = "Your formula may not contain $y{$i}"
174 :     unless $isPreview || !$params{showVariableHints};
175 :     $error = 1; next;
176 :     }
177 :     if (!defined($student{$i}->{variables}{$x{$i}})) {
178 :     $ans{$i}->{rh_ans}{ans_message} = "Your formula is not a function of $x{$i}"
179 :     unless $isPreview || !$params{showVariableHints};
180 :     $error = 1; next;
181 :     }
182 :     if (($student{$i}->{tree}->class eq 'BOP' &&
183 :     ($fog == $student{$i}->{tree}{lop} || $fog == $student{$i}->{tree}{rop})) ||
184 :     ($student{$i}->{tree}->class eq 'UOP' && $fog == $student{$i}->{tree}{op})) {
185 :     $ans{$i}->{rh_ans}{ans_message} =
186 :     "Your formula may not have the composition as one of its terms";
187 :     $error = 1; next;
188 :     }
189 :     if ($fog == $student{$i}) {
190 :     $ans{$i}->{rh_ans}{ans_message} =
191 :     "Your formula my not be the composition itself";
192 :     $error = 1; next;
193 :     }
194 :     if ($student{$i} == $x{$i}) {
195 :     $ans{$i}->{rh_ans}{ans_message} = "The identity function is not allowed"
196 :     unless $isPreview;
197 :     $error = 1; next;
198 :     }
199 : dpvc 5054
200 : dpvc 2732 }
201 :    
202 :     #
203 : gage 4997 # If no error, and both answers are given, check if compositions are equal
204 : dpvc 2732 #
205 :     if (!$error && defined($student{$fID}) && defined($student{$gID})) {
206 :     if ($fog == $student{$fID}->substitute($x{$fID}=>$student{$gID})) {
207 :     $ans{$fID}->{rh_ans}{score} = $ans{$gID}->{rh_ans}{score} = 1;
208 :     }
209 :     }
210 :    
211 :     return (%ans);
212 :     }
213 :    
214 : sh002i 5551 =head2 message_cmp
215 :    
216 :     message_cmp($correct)
217 :    
218 :     Returns an answer evaluator that always returns incorrect, with a given error
219 :     message. Used by COMPOSITION_ANS to produce "dummy" answer checkers for the two
220 :     parts of the composition.
221 :    
222 :     =cut
223 :    
224 : dpvc 2732 sub message_cmp {
225 :     my $correct = shift;
226 :     my $answerEvaluator = new AnswerEvaluator;
227 :     $answerEvaluator->ans_hash(
228 :     type => "message",
229 :     correct_ans => $correct->string,
230 :     ans_message => $message,
231 :     );
232 :     $answerEvaluator->install_evaluator(sub {shift});
233 :     return $answerEvaluator;
234 :     }
235 :    
236 :     1;
237 : sh002i 5551

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9