[system] / trunk / pg / macros / parserSolutionFor.pl Repository: Repository Listing bbplugincoursesdistsnplrochestersystemwww # View of /trunk/pg/macros/parserSolutionFor.pl

Wed Oct 3 18:47:43 2007 UTC (12 years, 4 months ago) by sh002i
File size: 5793 byte(s)
```reformatted documentation for the rest of the MathObjects-related macros
```

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