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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5556 - (download) (as text) (annotate)
Thu Oct 4 16:40:49 2007 UTC (12 years, 3 months ago) by sh002i
File size: 6995 byte(s)
added standard copyright/license header

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork2/lib/WeBWorK.pm,v 1.100 2007/08/13 22:59:53 sh002i 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 contextLimitedPowers.pl - Restrict the base or power allowed in exponentials.
   20 
   21 =head1 DESCRIPTION
   22 
   23 Implements subclasses of the "^" operator that restrict
   24 the base or power that is allowed.  There are four
   25 available restrictions:
   26 
   27   No raising e to a power
   28   Only allowing integer powers (positive or negative)
   29   Only allowing positive interger powers
   30   Only allowing positive interger powers (and 0)
   31 
   32 You install these via one of the commands:
   33 
   34   LimitedPowers::NoBaseE();
   35   LimitedPowers::OnlyIntegers();
   36   LimitedPowers::OnlyPositiveIntegers();
   37   LimitedPowers::OnlyNonNegativeIntegers();
   38 
   39 Only one of the three can be in effect at a time; setting
   40 a second one overrides the first.
   41 
   42 These function affect the current context, or you can pass
   43 a context reference, as in
   44 
   45   $context = Context("Numeric")->copy;
   46   LimitedPowers::OnlyIntegers($context);
   47 
   48 For the Interger power functions, you can pass additional
   49 parameters that control the range of values that are allowed
   50 for the powers.  The oprtions include:
   51 
   52 =over
   53 
   54 =item S<C<< minPower => m >>>
   55 
   56 only integer powers bigger than or equal
   57 to m are allowed.  (If m is undef, then
   58 there is no minimum power.)
   59 
   60 =item S<C<< maxPower => M >>>
   61 
   62 only integer powers less than or equal
   63 to M are allowed.  (If M is undef, then
   64 there is no maximum power.)
   65 
   66 =item S<C<< message => "text" >>>
   67 
   68 a description of the type of power
   69 allowed (e.g., "positive integer constants");
   70 
   71 =item S<C<< checker => code >>>
   72 
   73 a reference to a subroutine that will be
   74 used to check if the powers are acceptable.
   75 It should accept a reference to the BOP::power
   76 structure and return 1 or 0 depending on
   77 whether the power is OK or not.
   78 
   79 =back
   80 
   81 For example:
   82 
   83     LimitedPowers::OnlyIntegers(
   84         minPower => -5, maxPower => 5,
   85         message => "integer constants between -5 and 5",
   86     );
   87 
   88 would accept only powers between -5 and 5, while
   89 
   90     LimitedPowers::OnlyIntegers(
   91         checker => sub {
   92             return 0 unless LimitedPowers::isInteger(@_);
   93             my $self = shift; my $p = shift; # the power as a constant
   94             return $p != 0 && $p != 1;
   95         },
   96         message => "integer constants other than 0 or 1",
   97     );
   98 
   99 would accept any integer power other than 0 and 1.
  100 
  101 =cut
  102 
  103 loadMacros("MathObjects.pl");
  104 
  105 sub _contextLimitedPowers_init {}; # don't load it again
  106 
  107 package LimitedPowers;
  108 
  109 sub NoBaseE {
  110   my $context = (Value::isContext($_[0]) ? shift : Value->context);
  111   $context->operators->set(
  112     '^'  => {class => 'LimitedPowers::NoBaseE', isCommand=>1, perl=>'LimitedPowers::NoBaseE->_eval', @_},
  113     '**' => {class => 'LimitedPowers::NoBaseE', isCommand=>1, perl=>'LimitedPowers::NoBaseE->_eval', @_},
  114   );
  115 }
  116 
  117 sub OnlyIntegers {
  118   my $context = (Value::isContext($_[0]) ? shift : Value->context);
  119   $context->operators->set(
  120     '^'  => {class => 'LimitedPowers::OnlyIntegers', message => "integer constants", @_},
  121     '**' => {class => 'LimitedPowers::OnlyIntegers', message => "integer constants",@_},
  122   );
  123 }
  124 
  125 sub OnlyNonNegativeIntegers {
  126   my $context = (Value::isContext($_[0]) ? shift : Value->context);
  127   OnlyIntegers($context, minPower=>0, message=>"non-negative integer constants", @_);
  128 }
  129 
  130 sub OnlyPositiveIntegers {
  131   my $context = (Value::isContext($_[0]) ? shift : Value->context);
  132   OnlyIntegers($context, minPower => 1, message => "positive integer constants", @_);
  133 }
  134 
  135 sub OnlyNonTrivialPositiveIntegers {
  136   my $context = (Value::isContext($_[0]) ? shift : Value->context);
  137   OnlyIntegers($context, minPower=>2, message=>"integer constants bigger than 1", @_);
  138 }
  139 
  140 #
  141 #  Test for whether the power is an integer in the specified range
  142 #
  143 sub isInteger {
  144   my $self = shift; my $n = shift;
  145   my $def = $self->{def};
  146   return 0 if defined($def->{minPower}) && $n < $def->{minPower};
  147   return 0 if defined($def->{maxPower}) && $n > $def->{maxPower};
  148   return Value::Real->make($n - int($n)) == 0;
  149 }
  150 
  151 #
  152 #  Legacy code to accommodate older approach to setting the operators
  153 #
  154 our @NoBaseE = (
  155   '^'  => {class => 'LimitedPowers::NoBaseE', isCommand=>1, perl=>'LimitedPowers::NoBaseE->_eval'},
  156   '**' => {class => 'LimitedPowers::NoBaseE', isCommand=>1, perl=>'LimitedPowers::NoBaseE->_eval'},
  157 );
  158 our @OnlyIntegers = (
  159   '^'  => {class => 'LimitedPowers::OnlyIntegers', message => "integer constants"},
  160   '**' => {class => 'LimitedPowers::OnlyIntegers', message => "integer constants"},
  161 );
  162 our @OnlyNonNegativeIntegers = (
  163   '^'  => {class => 'LimitedPowers::OnlyIntegers', minPower => 0, message => "non-negative integer constants"},
  164   '**' => {class => 'LimitedPowers::OnlyIntegers', minPower => 0, message => "non-negative integer constants"},
  165 );
  166 our @OnlyPositiveIntegers = (
  167   '^'  => {class => 'LimitedPowers::OnlyIntegers', minPower => 1, message => "positive integer constants"},
  168   '**' => {class => 'LimitedPowers::OnlyIntegers', minPower => 1, message => "positive integer constants"},
  169 );
  170 our @OnlyNonTrivialPositiveIntegers = (
  171   '^'  => {class => 'LimitedPowers::OnlyIntegers', minPower => 2, message => "integer constants bigger than 1"},
  172   '**' => {class => 'LimitedPowers::OnlyIntegers', minPower => 2, message => "integer constants bigger than 1"},
  173 );
  174 
  175 
  176 ##################################################
  177 
  178 package LimitedPowers::NoBaseE;
  179 @ISA = qw(Parser::BOP::power);
  180 
  181 my $e = CORE::exp(1);
  182 
  183 sub _check {
  184   my $self = shift;
  185   $self->SUPER::_check(@_);
  186   $self->Error("Can't raise e to a power") if $self->{lop}->string eq 'e';
  187 }
  188 
  189 sub _eval {
  190   my $self = shift;
  191   Value::cmp_Message("Can't raise e to a power") if $_[0] - $e == 0;
  192   $self->SUPER::_eval(@_);
  193 }
  194 
  195 ##################################################
  196 
  197 package LimitedPowers::OnlyIntegers;
  198 @ISA = qw(Parser::BOP::power);
  199 
  200 sub _check {
  201   my $self = shift; my $p = $self->{rop}; my $def = $self->{def};
  202   my $checker = (defined($def->{checker}) ? $def->{checker} :  \&LimitedPowers::isInteger);
  203   $self->SUPER::_check(@_);
  204   $self->Error("Powers must be $def->{message}")
  205     if $p->type ne 'Number' || !$p->{isConstant} || !&{$checker}($self,$p->eval);
  206 }
  207 
  208 ##################################################
  209 
  210 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9