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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6219 - (download) (as text) (annotate)
Thu Apr 1 00:21:45 2010 UTC (9 years, 9 months ago) by dpvc
File size: 6613 byte(s)
Provide a limited context in which rational functions can be specified

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2010 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: pg/macros/contextRationalFunction.pl,v 1.1 2010/03/31 21:01:14 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 contextRationalFunction.pl - Only allow rational functions
   20                              (and their products and powers)
   21 
   22 =head1 DESCRIPTION
   23 
   24 Implements a context in which students can only enter rational
   25 functions, with some control over whether a single division is
   26 allowed, or whether products of rational functions are allowed.
   27 
   28 Select the context using:
   29 
   30   Context("RationalFunction");
   31 
   32 The RationalFunction context supports all the flags of the
   33 PolynomialFactors context, except for strictDivision, since rational
   34 functions allow division of polynomials.
   35 
   36 In addition, there is a singleQuotients flag that controls whether
   37 products of rational functions are allowed or not.  By default, they
   38 are allowed, but you can set this flag to 1 in order to force the
   39 student answer to be as a single fraction.
   40 
   41 Finally, there is also a strict context that does not allow
   42 operations even within the coefficients.  Select it using:
   43 
   44   Context("RationalFunction-Strict");
   45 
   46 In addition to disallowing operations within the coefficients, this
   47 context does not reduce constant operations (since they are not
   48 allowed), and sets the singlePowers, singleFactors, singleQuotients,
   49 and stricPowers flags automatically.  In addition, it disables all the
   50 functions, though they can be re-enabled, if needed.
   51 
   52 =cut
   53 
   54 ##################################################
   55 
   56 loadMacros(
   57   "MathObjects.pl",
   58   "contextPolynomialFactors.pl"
   59 );
   60 
   61 sub _contextRationalFunction_init {RationalFunction::Init()}
   62 
   63 ##############################################
   64 
   65 package RationalFunction::BOP::multiply;
   66 our @ISA = qw(PolynomialFactors::BOP::multiply);
   67 
   68 sub checkFactors {
   69   my $self = shift; my ($l,$r) = @_;
   70   $self->SUPER::checkFactors($l,$r);
   71   if (($l->{isPoly}||0) >= 6 || ($r->{isPoly}||0) >= 6) {
   72     $self->Error("You can not use multiplication with rational functions as operands ".
   73                  "(do you need parentheses around the denominator?)")
   74       if $self->context->flag("singleQuotients");
   75     $self->{isPoly} = 7; # product containing rational functions
   76   }
   77   return 1;
   78 }
   79 
   80 ##############################################
   81 
   82 package RationalFunction::BOP::divide;
   83 our @ISA = qw(PolynomialFactors::BOP::divide);
   84 
   85 sub checkPolynomial {
   86   my $self = shift; my ($l,$r) = ($self->{lop},$self->{rop});
   87   if ((!$l->{isPoly} || $l->{isPoly} == 2) && LimitedPolynomial::isConstant($r)) {
   88     $self->{isPoly} = $l->{isPoly};
   89     $self->{powers} = $l->{powers}; delete $l->{powers};
   90     $self->{exponents} = $l->{exponents}; delete $l->{exponents};
   91   } elsif (($l->{isPoly}||0) >= 6 || ($r->{isPoly}||0) >= 6) {
   92     $self->Error("Only one polynomial division is allowed in a rational function");
   93   } else {
   94     PolynomialFactors::markFactor($l);
   95     PolynomialFactors::markFactor($r);
   96     $self->checkFactors($l,$r);
   97   }
   98   return 1;
   99 }
  100 
  101 sub checkFactors {
  102   my $self = shift; my ($l,$r) = @_;
  103   my $single = $self->context->flag("singleFactors");
  104   $self->Error("Only one constant multiple or fraction is allowed (combine or cancel them)")
  105     if $l->{factors}{0} && $r->{factors}{0} && $self->context->flag("singleFactors");
  106   $self->{factors} = $l->{factors}; delete $l->{factors};
  107   foreach my $factor (keys %{$r->{factors}}) {
  108     if ($single && $self->{factors}{$factor}) {
  109       $self->Error("Each factor can appear only once (combine or cancel like factors)") unless $factor eq "0";
  110       $self->Error("Only one constant coefficient or negation is allowed (combine or cancel them)");
  111     }
  112     $self->{factors}{$factor} = 1;
  113   }
  114   delete $r->{factors};
  115   $self->{isPoly} = 6; # rational function
  116   return 1;
  117 }
  118 
  119 ##############################################
  120 
  121 package RationalFunction::BOP::power;
  122 our @ISA = qw(PolynomialFactors::BOP::power);
  123 
  124 sub checkPolynomial {
  125   my $self = shift; my ($l,$r) = ($self->{lop},$self->{rop});
  126   $self->SUPER::checkPolynomial;
  127   $self->{isPoly} = 6 if ($l->{isPoly}||0) >= 6;
  128   return 1;
  129 }
  130 
  131 ##############################################
  132 
  133 package RationalFunction::UOP::minus;
  134 our @ISA = qw(PolynomialFactors::UOP::minus);
  135 
  136 sub checkPolynomial {
  137   my $self = shift;
  138   $self->SUPER::checkPolynomial;
  139   $self->{isPoly} = 6 if ($self->{op}{isPoly}||0) >= 6;
  140   return 1;
  141 }
  142 
  143 ##############################################
  144 
  145 package RationalFunction;
  146 our @ISA = ('PolynomialFactors');
  147 
  148 sub Init {
  149   #
  150   #  Build the new context that calls the
  151   #  above classes rather than the usual ones
  152   #
  153 
  154   my $context = $main::context{RationalFunction} = Parser::Context->getCopy("PolynomialFactors");
  155   $context->{name} = "RationalFunction";
  156   $context->operators->set(
  157      '*' => {class => 'RationalFunction::BOP::multiply'},
  158     '* ' => {class => 'RationalFunction::BOP::multiply'},
  159     ' *' => {class => 'RationalFunction::BOP::multiply'},
  160      ' ' => {class => 'RationalFunction::BOP::multiply'},
  161      '/' => {class => 'RationalFunction::BOP::divide'},
  162     ' /' => {class => 'RationalFunction::BOP::divide'},
  163     '/ ' => {class => 'RationalFunction::BOP::divide'},
  164      '^' => {class => 'RationalFunction::BOP::power'},
  165     '**' => {class => 'RationalFunction::BOP::power'},
  166     'u-' => {class => 'RationalFunction::UOP::minus'},
  167   );
  168   $context->flags->set(strictPowers => 1);
  169 
  170   #
  171   #  A context where coefficients can't include operations
  172   #
  173   $context = $main::context{"RationalFunction-Strict"} = $context->copy;
  174   $context->flags->set(
  175     strictCoefficients => 1,
  176     singlePowers => 1, singleFactors => 1, singleQuotients => 1,
  177     reduceConstants => 0,
  178   );
  179   $context->functions->disable("All");  # can be re-enabled if needed
  180 
  181   main::Context("RationalFunction");  ### FIXME:  probably should require author to set this explicitly
  182 }
  183 
  184 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9