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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6134 - (download) (as text) (annotate)
Sat Oct 3 16:39:42 2009 UTC (10 years, 3 months ago) by dpvc
File size: 6191 byte(s)
Reduction rule should be off by default

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2009 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: pg/macros/parserPrime.pl,v 1.2 2009/10/03 15:58:49 dpvc Exp $
    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 parserPrime.pl - defines a prime operator (') to perform differentiation
   20                  (can be used in student answers as well).
   21 
   22 =head1 DESCRIPTION
   23 
   24 This file defines the code necessary to make the prime (') operator perform
   25 differentiation within a Formula object.  For example, Formula("(x^2)'") would
   26 equal Formula("2*x"), and Formula("(x^2)''") would equal Real(2).  The context
   27 also includes reduction rules to replace the prime notaiton by the actual
   28 derivative.
   29 
   30 To accomplish this, put the line
   31 
   32   loadMacros("parserPrime.pl");
   33 
   34 at the beginning of your problem file, then set the Context to the one you wish
   35 to use in the problem.  Then use the command:
   36 
   37   parser::Prime->Enable;
   38 
   39 (You can also pass the Enable command a context pointer if you wish to
   40 alter a context other than the current one.)
   41 
   42 Once this is done, you will be able to enter primes in your Formulas
   43 to refer to differentiation.  For example:
   44 
   45   Formula("(3x^2+2x+1)'")
   46 
   47 would mean the derivative of 3x^2+2x+1 and would be equivalent to
   48 
   49   Formula("3*2*x+2")
   50 
   51 The variable of differentiation is taken from the variables used in
   52 the formula being differentiated.  If there is more than one variable
   53 used, the first one alphabetically is used.  For example
   54 
   55   Formula("(ln(x))' + (x^2+3y)'")
   56 
   57 would produce the equivalent to
   58 
   59   Formula("(1/x) + (2*x+0)").
   60 
   61 This can have unexpected results, however, since.
   62 
   63   Formula("(x^2)' + (y^2)'")
   64 
   65 would generate
   66 
   67   Formula("2*x + 2*y")
   68 
   69 which may not be what you want.  In order to specify the variable for
   70 differentiation, you can list it in the Enable() call.  For example:
   71 
   72   parser::Prime->Enable("x");
   73 
   74 would make
   75 
   76   Formula("(x^2)' + (y^2)'")
   77 
   78 generate
   79 
   80   Formula("2*x + 0")
   81 
   82 rather than the default 2x+2y.
   83 
   84 The prime operator also defines a reduction rule that allows the prime
   85 notation to be replaced by the actual derivative when the Formula is
   86 reduced.  This is off by default, but you can set it via
   87 
   88   Context()->reduction->set("(f)'"=>1);
   89 
   90 so that it will be on for all reductions, or specify it for a single
   91 reduction as follows:
   92 
   93   $f = Formula("(x^2)'")->reduce("(f)'"=>1);
   94 
   95 to obtain $f as Formula("2*x").
   96 
   97 Note that once the prime has been added to the Context, student
   98 answers will be allowed to include primes as well, so if you want
   99 students to actually perform the differentiation themselves, you may
  100 wish to disable the prime at the end of the problem (so it will not be
  101 active while student answers are being parsed).  To do that use
  102 
  103   parser::Prime->Disable;
  104 
  105 (You can pass Disable a context pointer to remove the prime operator
  106 from a context other than the current one.)
  107 
  108 =cut
  109 
  110 sub _parserPrime_init {};    # don't load a second time
  111 
  112 ##########################################
  113 #
  114 #  Package to enable and disable the prime operator
  115 #
  116 package parser::Prime;
  117 
  118 #
  119 #  Add prime to the given or current context
  120 #
  121 sub Enable {
  122   my $self = shift; my $x = shift;
  123   my $context = main::Context();
  124   if (Value::isContext($x)) {$context = $x; $x = shift}
  125   $context->operators->add("'"=>{
  126     precedence => 8.5, associativity => "right", type => "unary", string => "'",
  127     class => "parser::Prime::UOP::prime", isCommand => 1
  128   });
  129   $context->reduction->set("(f)'" => 0);
  130   $context->flags->set(prime_variable => $x) if defined($x);
  131 }
  132 
  133 #
  134 #  Remove prime from the context
  135 #
  136 sub Disable {
  137   my $self = shift; my $context = shift || main::Context();
  138   $context->operators->remove("'");
  139 }
  140 
  141 ##########################################
  142 #
  143 #  Prime operator is a subclass of the unary operator class
  144 #
  145 package parser::Prime::UOP::prime;
  146 our @ISA = ('Parser::UOP');
  147 
  148 #
  149 #  Do a typecheck on the operand
  150 #
  151 sub _check {
  152   my $self = shift;
  153   return if $self->checkInfinite || $self->checkString ||
  154             $self->checkList || $self->checkNumber;
  155   $self->{type} = {%{$self->{op}->typeRef}};
  156 }
  157 
  158 #
  159 #  A hack to prevent double-primes from inserting parentheses
  160 #   in string and TeX output (change the precedence to hide it)
  161 #
  162 sub string {
  163   my ($self,$precedence,$showparens,$position,$outerRight) = @_;
  164   my $uop = $self->{def}; $precedence -= .01 if $uop->{precedence} == $precedence;
  165   return $self->SUPER::string($precedence,$showparens,$position,$outerRight);
  166 }
  167 sub TeX {
  168   my ($self,$precedence,$showparens,$position,$outerRight) = @_;
  169   my $uop = $self->{def}; $precedence -= .01 if $uop->{precedence} == $precedence;
  170   return $self->SUPER::TeX($precedence,$showparens,$position,$outerRight);
  171 }
  172 
  173 #
  174 #  Produce a perl version of the derivative
  175 #
  176 sub perl {
  177   my $self = shift;
  178   return $self->{op}->D($self->getVar)->perl;
  179 }
  180 
  181 #
  182 #  Evaluate the derivative
  183 #
  184 sub eval {
  185   my $self = shift;
  186   return $self->{op}->D($self->getVar)->eval;
  187 }
  188 
  189 #
  190 #  Reduce by replacing with derivative
  191 #
  192 sub reduce {
  193   my $self = shift;
  194   return $self unless $self->context->{reduction}{"(f)'"};
  195   return $self->{op}->D($self->getVar);
  196 }
  197 
  198 sub getVar {
  199   my $self = shift;
  200   return $self->context->flag("prime_variable") ||
  201          (keys(%{$self->getVariables}))[0] ||
  202    (keys(%{$self->{equation}{variables}}))[0] || 'x';
  203 }
  204 
  205 
  206 #
  207 #  Handle derivative by taking derivative of a prime by taking
  208 #  derivative of the prime's value (which is itself a derivative)
  209 #
  210 sub D {
  211   my $self = shift; my $x = shift;
  212   return $self->{op}->D($x)->D($x);
  213 }
  214 
  215 1;
  216 

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9