[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 5373 - (download) (as text) (annotate)
Sun Aug 19 02:01:57 2007 UTC (12 years, 3 months ago) by dpvc
File size: 6003 byte(s)
Normalized comments and headers to that they will format their POD
documentation properly.  (I know that the POD processing was supposed
to strip off the initial #, but that doesn't seem to happen, so I've
added a space throughout.)

    1 loadMacros("MathObjects.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 $context = SolutionFor::getContext();     # use a context in which equality is defined
   66   my $f = main::Formula($context,shift);       # get equation as a formula
   67 
   68   #
   69   #  Get the professor's correct point
   70   #
   71   my $p = shift; $p = main::Point($p) if ref($p) eq "ARRAY";
   72   $p = main::Compute($p) unless Value::isValue($p);
   73 
   74   #
   75   #  Get any user options (e.g., vars => ['x','y'])
   76   #
   77   my %options = (vars=>undef,@_);
   78 
   79   #
   80   #  Do some error checking
   81   #
   82   Value::Error("Your formula doesn't look like an implicit equation")
   83      unless $f->type eq 'Equality';
   84   Value::Error("Professor's answer should be a point or a number")
   85      unless Value::isNumber($p) || $p->type eq 'Point';
   86 
   87   #
   88   #  Save the formula for future reference, and make a callable
   89   #  perl function out of it.
   90   #
   91   $p->{f} = $f;
   92   $p->{F} = $f->perlFunction(undef,$options{vars});
   93 
   94   #
   95   #  Save some data about the original object
   96   #  and make the Value package think we are one of its objects
   97   #
   98   $p->{originalClass} = $p->cmp_class;
   99   $p->{isValue} = 1;
  100 
  101   #
  102   #  Make the object into the correct SolutionFor subclass
  103   #
  104   $p = bless $p, "SolutionFor::".$p->class;
  105 
  106   #
  107   #  Make sure professor's answer actually works
  108   #
  109   Value::Error("Professor's answer of %s does not satisfy the given equation",$p->string)
  110     unless $p->f($p);
  111 
  112   #
  113   #  Return the SolutionFor object
  114   #
  115   return $p;
  116 }
  117 
  118 ######################################################################
  119 #
  120 #  Define the new class (we make subclasses below)
  121 #  (we need subclasses in order to make things work
  122 #  properly with single-variable complex or real-valued
  123 #  equations)
  124 #
  125 package SolutionFor;
  126 
  127 #
  128 #  Evaluate the formula on the given point
  129 #
  130 sub f {
  131   my $self = shift;
  132   &{$self->{F}}(shift->value);
  133 }
  134 
  135 #
  136 #  The name of this object for error messages
  137 #
  138 sub cmp_class {shift->{originalClass}}
  139 
  140 #
  141 #  Do a comparison by testing if the formula's equality
  142 #  operation returns true or false.
  143 #  (Since we are implementing <=> here, we need
  144 #  to return 0 when true and 1 when false.)
  145 #
  146 sub compare {
  147   my ($l,$r) = @_;
  148   $r = Value::makeValue($r,context=>$l->context);
  149   return ($l->f($r)) ? 0 : 1;
  150 }
  151 
  152 #
  153 #  Set up a new context that is a copy of the current one, but
  154 #  has the equality operator defined, and the SolutionFor object
  155 #  prededence set so that comparisons with points or numbers will
  156 #  be promoted to comparisons with the SolutionFor
  157 #
  158 sub getContext {
  159   my $oldContext = main::Context();
  160   $oldContext->{precedence}{SolutionFor} = $oldContext->{precedence}{special};
  161   my $context = $oldContext->copy;
  162   Parser::BOP::equality->Allow($context);
  163   return $context
  164 }
  165 
  166 ######################################################################
  167 #
  168 #  A separate class for Reals, to get Value::Real in the ISA list
  169 #
  170 package SolutionFor::Real;
  171 our @ISA = qw(SolutionFor Value::Real Value);
  172 
  173 #
  174 #  Pass the real number directly
  175 #
  176 sub f {
  177   my $self = shift;
  178   &{$self->{F}}(shift);
  179 }
  180 
  181 
  182 ######################################################################
  183 #
  184 #  A separate class for Complexes
  185 #
  186 package SolutionFor::Complex;
  187 our @ISA = qw(SolutionFor Value::Complex Value);
  188 
  189 #
  190 #  Pass the complex number directly
  191 #
  192 sub f {
  193   my $self = shift;
  194   &{$self->{F}}(shift);
  195 }
  196 
  197 ######################################################################
  198 #
  199 #  A separate class for Points
  200 #
  201 package SolutionFor::Point;
  202 our @ISA = qw(SolutionFor Value::Point Value);
  203 
  204 #
  205 #  Use the Point's defaults, but turn off coordinate hints
  206 #  (since a wrong coordinate isn't detectable)
  207 #
  208 sub cmp_defaults {(
  209   shift->SUPER::cmp_defaults,
  210   showCoordinateHints => 0,
  211 )}
  212 
  213 1; # make Perl happy

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9