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

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9