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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4997 - (download) (as text) (annotate)
Mon Jun 11 18:16:40 2007 UTC (12 years, 8 months ago) by gage
File size: 6181 byte(s)
Fixing docementation so that it can be read from the web.

    1 loadMacros("Parser.pl");
    2 
    3 sub _parserSolutionFor_init {}; # don't reload this file
    4 
    5 =head1 DESCRIPTION
    6 
    7 ######################################################################
    8 #
    9 #  This is a Parser class that implements an answer checker that
   10 #  checks if a student's answer satisfies an implicit equation.
   11 #  We define a SolutionFor object class that lets you specify an
   12 #  equality that the student answer must satisfy, and a point that
   13 #  DOES satify the equation.  The overloaded == operator will
   14 #  check if a given point satisfies the given equality.
   15 #
   16 #  Use SolutionFor(equality,point[,options]) to create a SolutionFor object.
   17 #  The equality is a Formula object containing an equality, or a string
   18 #  representing such a formula, and the point is a Point object or string
   19 #  containing a point that satisfies the equation (to be used as the
   20 #  correct answer when the student asks to see the answers).
   21 #
   22 #  The variables to use are declared in the Context in the usual way,
   23 #  and the coordinates of the student point will be considered to be in
   24 #  alphabetical order.  You can override this by supplying the vars=>[...]
   25 #  option, where you specify the variable names in the order you want the
   26 #  student to give them.  E.g., vars=>['y','x'] will make the student answer
   27 #  represent the point (y,x) rather than the default (x,y).
   28 #
   29 #  Usage examples:
   30 #
   31 #     Context("Vector")->variables->are(x=>'Real',y=>'real');
   32 #     $f = SolutionFor("x^2 = cos(y)","(1,0)");
   33 #     $f = SolutionFor("x^2 - y = 0",[2,4]);
   34 #     $f = SolutionFor("x^2 - y = 0",Point(4,2),vars=>['y','x']);
   35 #
   36 #  Then use
   37 #
   38 #     ANS($f->cmp);
   39 #
   40 #  to get the answer checker for $f.
   41 #
   42 #  You can use $f->{f} to get the Formula object for the equality used
   43 #  in the object, and $f->f(point) to determine if the given point is
   44 #  a solution to the equality or not.  For example, if you want to include
   45 #  the TeX version of a formula within the text of a problem, you can use:
   46 #
   47 #     Context()->texStrings;
   48 #     BEGIN_TEXT
   49 #       A solution to \($f->{f}\) is \((x,y)\) = \{ans_rule(30)\}.
   50 #     END_TEXT
   51 #     Context()->normalStrings;
   52 #     ANS($f->cmp);
   53 #
   54 ######################################################################
   55 
   56 =cut
   57 
   58 #
   59 #  Create a SolutionFor object of the correct type
   60 #
   61 sub SolutionFor {
   62   #
   63   #  Get the professor's equation
   64   #
   65   my $oldContext = SolutionFor::SetContext();  # use a context in which equality is defined
   66   my $f = main::Formula(shift);                # get equation as a formula
   67   SolutionFor::RestoreContext($oldContext);    # go back to user's context
   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,$flag) = @_;
  149   if ($l->promotePrecedence($r)) {return $r->compare($l,!$flag)}
  150   $r = Value::makeValue($r);
  151   return ($l->f($r)) ? 0 : 1;
  152 }
  153 
  154 #
  155 #  Set up a new context that is a copy of the current one, but
  156 #  has the equality operator defined, and the SolutionFor object
  157 #  prededence set so that comparisons with points or numbers will
  158 #  be promoted to comparisons with the SolutionFor
  159 #
  160 sub SetContext {
  161   my $oldContext = main::Context();
  162   $oldContext->{precedence}{SolutionFor} = $oldContext->{precedence}{special};
  163   my $context = $oldContext->copy;
  164   Parser::BOP::equality->Allow($context);
  165   main::Context($context);
  166   return $oldContext
  167 }
  168 
  169 #
  170 #  Put back a saved context
  171 #
  172 sub RestoreContext {main::Context(@_)}
  173 
  174 
  175 ######################################################################
  176 #
  177 #  A separate class for Reals, to get Value::Real in the ISA list
  178 #
  179 package SolutionFor::Real;
  180 our @ISA = qw(SolutionFor Value::Real Value);
  181 
  182 #
  183 #  Pass the real number directly
  184 #
  185 sub f {
  186   my $self = shift;
  187   &{$self->{F}}(shift);
  188 }
  189 
  190 
  191 ######################################################################
  192 #
  193 #  A separate class for Complexes
  194 #
  195 package SolutionFor::Complex;
  196 our @ISA = qw(SolutionFor Value::Complex Value);
  197 
  198 #
  199 #  Pass the complex number directly
  200 #
  201 sub f {
  202   my $self = shift;
  203   &{$self->{F}}(shift);
  204 }
  205 
  206 ######################################################################
  207 #
  208 #  A separate class for Points
  209 #
  210 package SolutionFor::Point;
  211 our @ISA = qw(SolutionFor Value::Point Value);
  212 
  213 #
  214 #  Use the Point's defaults, but turn off coordinate hints
  215 #  (since a wrong coordinate isn't detectable)
  216 #
  217 sub cmp_defaults {(
  218   shift->SUPER::cmp_defaults,
  219   showCoordinateHints => 0,
  220 )}
  221 
  222 1; # make Perl happy

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9