[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 6058 - (download) (as text) (annotate)
Thu Jun 25 23:28:44 2009 UTC (10 years, 6 months ago) by gage
File size: 6669 byte(s)
syncing pg HEAD with pg2.4.7 on 6/25/2009

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader$
    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 =head1 NAME
   18 
   19 parserSolutionFor.pl - An answer checker that checks if a student's answer
   20 satisifies an implicit equation.
   21 
   22 =head1 DESCRIPTION
   23 
   24 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 
   31 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 =cut
   70 
   71 loadMacros("MathObjects.pl");
   72 
   73 sub _parserSolutionFor_init {}; # don't reload this file
   74 
   75 #
   76 #  Create a SolutionFor object of the correct type
   77 #
   78 sub SolutionFor {
   79   #
   80   #  Get the professor's equation
   81   #
   82   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 
   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   $p->{originalClass} = $p->cmp_class;
  116   $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   Value::Error("Professor's answer of %s does not satisfy the given equation",$p->string)
  127     unless $p->f($p);
  128 
  129   #
  130   #  Return the SolutionFor object
  131   #
  132   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   my ($l,$r) = @_;
  165   $r = Value::makeValue($r,context=>$l->context);
  166   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 sub getContext {
  176   my $oldContext = main::Context();
  177   $oldContext->{precedence}{SolutionFor} = $oldContext->{precedence}{special};
  178   my $context = $oldContext->copy;
  179   Parser::BOP::equality->Allow($context);
  180   return $context
  181 }
  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