[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 5553 - (download) (as text) (annotate)
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 
    6 =head1 DESCRIPTION
    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
   19 correct answer when the student asks to see the answers).
   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 
   55 loadMacros("MathObjects.pl");
   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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9