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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6058 - (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 : gage 6058 # $CVSHeader$
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 5553 =head1 NAME
18 : dpvc 3196
19 : sh002i 5553 parserSolutionFor.pl - An answer checker that checks if a student's answer
20 :     satisifies an implicit equation.
21 : dpvc 3196
22 : gage 4997 =head1 DESCRIPTION
23 :    
24 : sh002i 5553 This is a Parser class that implements an answer checker that
25 :     checks if a student's answer satisfies an implicit equation.
26 :     We define a SolutionFor object class that lets you specify an
27 :     equality that the student answer must satisfy, and a point that
28 :     DOES satify the equation. The overloaded == operator will
29 :     check if a given point satisfies the given equality.
30 : dpvc 3196
31 : sh002i 5553 Use SolutionFor(equality,point[,options]) to create a SolutionFor object.
32 :     The equality is a Formula object containing an equality, or a string
33 :     representing such a formula, and the point is a Point object or string
34 :     containing a point that satisfies the equation (to be used as the
35 :     correct answer when the student asks to see the answers).
36 :    
37 :     The variables to use are declared in the Context in the usual way,
38 :     and the coordinates of the student point will be considered to be in
39 :     alphabetical order. You can override this by supplying the vars=>[...]
40 :     option, where you specify the variable names in the order you want the
41 :     student to give them. E.g., vars=>['y','x'] will make the student answer
42 :     represent the point (y,x) rather than the default (x,y).
43 :    
44 :     Usage examples:
45 :    
46 :     Context("Vector")->variables->are(x=>'Real',y=>'Real');
47 :     $f = SolutionFor("x^2 = cos(y)","(1,0)");
48 :     $f = SolutionFor("x^2 - y = 0",[2,4]);
49 :     $f = SolutionFor("x^2 - y = 0",Point(4,2),vars=>['y','x']);
50 :    
51 :     Then use
52 :    
53 :     ANS($f->cmp);
54 :    
55 :     to get the answer checker for $f.
56 :    
57 :     You can use $f->{f} to get the Formula object for the equality used
58 :     in the object, and $f->f(point) to determine if the given point is
59 :     a solution to the equality or not. For example, if you want to include
60 :     the TeX version of a formula within the text of a problem, you can use:
61 :    
62 :     Context()->texStrings;
63 :     BEGIN_TEXT
64 :     A solution to \($f->{f}\) is \((x,y)\) = \{ans_rule(30)\}.
65 :     END_TEXT
66 :     Context()->normalStrings;
67 :     ANS($f->cmp);
68 :    
69 : gage 4997 =cut
70 :    
71 : sh002i 5553 loadMacros("MathObjects.pl");
72 :    
73 :     sub _parserSolutionFor_init {}; # don't reload this file
74 :    
75 : dpvc 3196 #
76 :     # Create a SolutionFor object of the correct type
77 :     #
78 :     sub SolutionFor {
79 :     #
80 :     # Get the professor's equation
81 :     #
82 : dpvc 5069 my $context = SolutionFor::getContext(); # use a context in which equality is defined
83 :     my $f = main::Formula($context,shift); # get equation as a formula
84 : dpvc 3196
85 :     #
86 :     # Get the professor's correct point
87 :     #
88 :     my $p = shift; $p = main::Point($p) if ref($p) eq "ARRAY";
89 :     $p = main::Compute($p) unless Value::isValue($p);
90 :    
91 :     #
92 :     # Get any user options (e.g., vars => ['x','y'])
93 :     #
94 :     my %options = (vars=>undef,@_);
95 :    
96 :     #
97 :     # Do some error checking
98 :     #
99 :     Value::Error("Your formula doesn't look like an implicit equation")
100 :     unless $f->type eq 'Equality';
101 :     Value::Error("Professor's answer should be a point or a number")
102 :     unless Value::isNumber($p) || $p->type eq 'Point';
103 :    
104 :     #
105 :     # Save the formula for future reference, and make a callable
106 :     # perl function out of it.
107 :     #
108 :     $p->{f} = $f;
109 :     $p->{F} = $f->perlFunction(undef,$options{vars});
110 :    
111 :     #
112 :     # Save some data about the original object
113 :     # and make the Value package think we are one of its objects
114 :     #
115 : dpvc 5069 $p->{originalClass} = $p->cmp_class;
116 : dpvc 3196 $p->{isValue} = 1;
117 :    
118 :     #
119 :     # Make the object into the correct SolutionFor subclass
120 :     #
121 :     $p = bless $p, "SolutionFor::".$p->class;
122 :    
123 :     #
124 :     # Make sure professor's answer actually works
125 :     #
126 : dpvc 3371 Value::Error("Professor's answer of %s does not satisfy the given equation",$p->string)
127 : dpvc 3196 unless $p->f($p);
128 :    
129 :     #
130 :     # Return the SolutionFor object
131 : dpvc 5069 #
132 : dpvc 3196 return $p;
133 :     }
134 :    
135 :     ######################################################################
136 :     #
137 :     # Define the new class (we make subclasses below)
138 :     # (we need subclasses in order to make things work
139 :     # properly with single-variable complex or real-valued
140 :     # equations)
141 :     #
142 :     package SolutionFor;
143 :    
144 :     #
145 :     # Evaluate the formula on the given point
146 :     #
147 :     sub f {
148 :     my $self = shift;
149 :     &{$self->{F}}(shift->value);
150 :     }
151 :    
152 :     #
153 :     # The name of this object for error messages
154 :     #
155 :     sub cmp_class {shift->{originalClass}}
156 :    
157 :     #
158 :     # Do a comparison by testing if the formula's equality
159 :     # operation returns true or false.
160 :     # (Since we are implementing <=> here, we need
161 :     # to return 0 when true and 1 when false.)
162 :     #
163 :     sub compare {
164 : dpvc 5069 my ($l,$r) = @_;
165 :     $r = Value::makeValue($r,context=>$l->context);
166 : dpvc 3196 return ($l->f($r)) ? 0 : 1;
167 :     }
168 :    
169 :     #
170 :     # Set up a new context that is a copy of the current one, but
171 :     # has the equality operator defined, and the SolutionFor object
172 :     # prededence set so that comparisons with points or numbers will
173 :     # be promoted to comparisons with the SolutionFor
174 :     #
175 : dpvc 5069 sub getContext {
176 : dpvc 3196 my $oldContext = main::Context();
177 :     $oldContext->{precedence}{SolutionFor} = $oldContext->{precedence}{special};
178 :     my $context = $oldContext->copy;
179 :     Parser::BOP::equality->Allow($context);
180 : dpvc 5069 return $context
181 : dpvc 3196 }
182 :    
183 :     ######################################################################
184 :     #
185 :     # A separate class for Reals, to get Value::Real in the ISA list
186 :     #
187 :     package SolutionFor::Real;
188 :     our @ISA = qw(SolutionFor Value::Real Value);
189 :    
190 :     #
191 :     # Pass the real number directly
192 :     #
193 :     sub f {
194 :     my $self = shift;
195 :     &{$self->{F}}(shift);
196 :     }
197 :    
198 :    
199 :     ######################################################################
200 :     #
201 :     # A separate class for Complexes
202 :     #
203 :     package SolutionFor::Complex;
204 :     our @ISA = qw(SolutionFor Value::Complex Value);
205 :    
206 :     #
207 :     # Pass the complex number directly
208 :     #
209 :     sub f {
210 :     my $self = shift;
211 :     &{$self->{F}}(shift);
212 :     }
213 :    
214 :     ######################################################################
215 :     #
216 :     # A separate class for Points
217 :     #
218 :     package SolutionFor::Point;
219 :     our @ISA = qw(SolutionFor Value::Point Value);
220 :    
221 :     #
222 :     # Use the Point's defaults, but turn off coordinate hints
223 :     # (since a wrong coordinate isn't detectable)
224 :     #
225 :     sub cmp_defaults {(
226 :     shift->SUPER::cmp_defaults,
227 :     showCoordinateHints => 0,
228 :     )}
229 :    
230 :     1; # make Perl happy

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9