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

View of /trunk/pg/macros/contextLimitedVector.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: 7900 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 _contextLimitedVector_init {}; # don't load it again
    4 
    5 =head3 Context("LimitedVector")
    6 
    7  ##########################################################
    8  #
    9  #  Implements a context in which vectors can be entered,
   10  #  but no vector operations are permitted.  So students will
   11  #  be able to perform operations within the coordinates
   12  #  of the vectors, but not between vectors.
   13  #
   14  #  Vectors can still be entered either in < , , > or ijk format.
   15  #  Most of the complication here is to handle ijk format
   16  #  properly.  Each coordinate vector is allowed to appear
   17  #  only once, so we have to keep track of that, and allow
   18  #  SOME vector operations, but only when one term is
   19  #  one of the coordinate constants, or one of the formulas
   20  #  we've already OKed.
   21  #
   22  #  You control which format to use by setting the context
   23  #  to one of the following:
   24  #
   25  #       Context("LimitedVector-coordinate");
   26  #       Context("LimitedVector-ijk");
   27  #       Context("LimitedVector");      # either one
   28  #
   29 
   30 =cut
   31 
   32 #
   33 #  Handle common checking for BOPs
   34 #
   35 package LimitedVector::BOP;
   36 
   37 #
   38 #  Do original check and then if the operands are numbers, its OK.
   39 #  Otherwise, check if there is a duplicate constant from either term
   40 #  Otherwise, do an operator-specific check for if vectors are OK.
   41 #  Otherwise report an error.
   42 #
   43 sub _check {
   44   my $self = shift;
   45   my $super = ref($self); $super =~ s/LimitedVector/Parser/;
   46   &{$super."::_check"}($self);
   47   return if $self->checkNumbers;
   48   if ($self->context->{flags}{vector_format} ne 'coordinate') {
   49     $self->checkConstants($self->{lop});
   50     $self->checkConstants($self->{rop});
   51     return if $self->checkVectors;
   52   }
   53   my $bop = $self->{def}{string} || $self->{bop};
   54   $self->Error("In this context, '%s' can only be used with Numbers",$bop)
   55     if $self->{equation}{context}{flags}{vector_format} eq 'coordinate';
   56   $self->Error("In this context, '%s' can only be used with Numbers or i,j and k",$bop);
   57 }
   58 
   59 #
   60 #  filled in by subclasses
   61 #
   62 sub checkVectors {return 0}
   63 
   64 #
   65 #  Check if a constant has been repeated
   66 #  (we maintain a hash that lists if one is below us in the parse tree)
   67 #
   68 sub checkConstants {
   69   my $self = shift; my $op = shift;
   70   my $duplicate = '';
   71   if ($op->class eq 'Constant') {
   72     return unless $op->{name} =~ m/^[ijk]$/;
   73     $duplicate = $op->{name} if $self->{ijk}{$op->{name}};
   74     $self->{ijk}{$op->{name}} = 1;
   75   } else {
   76     foreach my $x ('i','j','k') {
   77       $duplicate = $x if $self->{ijk}{$x} && $op->{ijk}{$x};
   78       $self->{ijk}{$x} = $self->{ijk}{$x} || $op->{ijk}{$x};
   79     }
   80   }
   81   Value::Error("The constant '%s' may appear only once in your formula",$duplicate)
   82     if $duplicate;
   83 }
   84 
   85 ##############################################
   86 #
   87 #  Now we get the individual replacements for the operators
   88 #  that we don't want to allow.  We inherit everything from
   89 #  the original Parser::BOP class, and just add the
   90 #  vector checks here.
   91 #
   92 
   93 package LimitedVector::BOP::add;
   94 our @ISA = qw(LimitedVector::BOP Parser::BOP::add);
   95 
   96 sub checkVectors {
   97   my $self = shift;
   98   return (($self->{lop}->class eq 'Constant' || $self->{lop}->class =~ m/[BU]OP/) &&
   99           ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/));
  100 }
  101 
  102 ##############################################
  103 
  104 package LimitedVector::BOP::subtract;
  105 our @ISA = qw(LimitedVector::BOP Parser::BOP::subtract);
  106 
  107 sub checkVectors {
  108   my $self = shift;
  109   return (($self->{lop}->class eq 'Constant' || $self->{lop}->class =~ m/[BU]OP/) &&
  110           ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/));
  111 }
  112 
  113 ##############################################
  114 
  115 package LimitedVector::BOP::multiply;
  116 our @ISA = qw(LimitedVector::BOP Parser::BOP::multiply);
  117 
  118 sub checkVectors {
  119   my $self = shift;
  120   return (($self->{lop}->class eq 'Constant' || $self->{lop}->type eq 'Number') &&
  121     ($self->{rop}->class eq 'Constant' || $self->{rop}->type eq 'Number'));
  122 }
  123 
  124 ##############################################
  125 
  126 package LimitedVector::BOP::divide;
  127 our @ISA = qw(LimitedVector::BOP Parser::BOP::divide);
  128 
  129 sub checkVectors {
  130   my $self = shift;
  131   my $bop = $self->{def}{string} || $self->{bop};
  132   $self->Error("In this context, '%s' can only be used with Numbers",$bop);
  133 }
  134 
  135 ##############################################
  136 ##############################################
  137 #
  138 #  Now we do the same for the unary operators
  139 #
  140 
  141 package LimitedVector::UOP;
  142 
  143 sub _check {
  144   my $self = shift;
  145   my $super = ref($self); $super =~ s/LimitedVector/Parser/;
  146   &{$super."::_check"}($self);
  147   return if $self->checkNumber;
  148   if ($self->context->{flags}{vector_format} ne 'coordinate') {
  149     LimitedVector::BOP::checkConstants($self,$self->{op});
  150     return if $self->checkVector;
  151   }
  152   my $uop = $self->{def}{string} || $self->{uop};
  153   $self->Error("In this context, '%s' can only be used with Numbers",$uop)
  154     if $self->{equation}{context}{flags}{vector_format} eq 'coordinate';
  155   $self->Error("In this context, '%s' can only be used with Numbers or i,j and k",$uop);
  156 }
  157 
  158 sub checkVector {return 0}
  159 
  160 ##############################################
  161 
  162 package LimitedVector::UOP::plus;
  163 our @ISA = qw(LimitedVector::UOP Parser::UOP::plus);
  164 
  165 sub checkVector {return shift->{op}->class eq 'Constant'}
  166 
  167 ##############################################
  168 
  169 package LimitedVector::UOP::minus;
  170 our @ISA = qw(LimitedVector::UOP Parser::UOP::minus);
  171 
  172 sub checkVector {return shift->{op}->class eq 'Constant'}
  173 
  174 ##############################################
  175 ##############################################
  176 #
  177 #  Absolute value does vector norm, so we
  178 #  trap that as well.
  179 #
  180 
  181 package LimitedVector::List::AbsoluteValue;
  182 our @ISA = qw(Parser::List::AbsoluteValue);
  183 
  184 sub _check {
  185   my $self = shift;
  186   $self->SUPER::_check;
  187   return if $self->{coords}[0]->type eq 'Number';
  188   $self->Error("Vector norm is not allowed in this context");
  189 }
  190 
  191 ##############################################
  192 
  193 package LimitedVector::List::Vector;
  194 our @ISA = qw(Parser::List::Vector);
  195 
  196 sub _check {
  197   my $self = shift;
  198   $self->SUPER::_check;
  199   return if $self->context->{flags}{vector_format} ne 'ijk';
  200   $self->Error("Vectors must be given in the form 'ai+bj+ck' in this context");
  201 }
  202 
  203 ##############################################
  204 ##############################################
  205 
  206 package main;
  207 
  208 #
  209 #  Now build the new context that calls the
  210 #  above classes rather than the usual ones
  211 #
  212 
  213 $context{LimitedVector} = Parser::Context->getCopy("Vector");
  214 $context{LimitedVector}->operators->set(
  215    '+' => {class => 'LimitedVector::BOP::add'},
  216    '-' => {class => 'LimitedVector::BOP::subtract'},
  217    '*' => {class => 'LimitedVector::BOP::multiply'},
  218   '* ' => {class => 'LimitedVector::BOP::multiply'},
  219   ' *' => {class => 'LimitedVector::BOP::multiply'},
  220    ' ' => {class => 'LimitedVector::BOP::multiply'},
  221    '/' => {class => 'LimitedVector::BOP::divide'},
  222   ' /' => {class => 'LimitedVector::BOP::divide'},
  223   '/ ' => {class => 'LimitedVector::BOP::divide'},
  224   'u+' => {class => 'LimitedVector::UOP::plus'},
  225   'u-' => {class => 'LimitedVector::UOP::minus'},
  226 );
  227 #
  228 #  Remove these operators and functions
  229 #
  230 $context{LimitedVector}->operators->undefine('_','U','><','.');
  231 $context{LimitedVector}->functions->undefine('norm','unit');
  232 $context{LimitedVector}->lists->set(
  233   AbsoluteValue => {class => 'LimitedVector::List::AbsoluteValue'},
  234   Vector        => {class => 'LimitedVector::List::Vector'},
  235 );
  236 #
  237 #  Format can be 'coordinate', 'ijk', or 'either'
  238 #
  239 $context{LimitedVector}->flags->set(vector_format => 'either');
  240 
  241 $context{'LimitedVector-ijk'} = $context{LimitedVector}->copy;
  242 $context{'LimitedVector-ijk'}->flags->set(vector_format => 'ijk');
  243 
  244 $context{'LimitedVector-coordinate'} = $context{LimitedVector}->copy;
  245 $context{'LimitedVector-coordinate'}->flags->set(vector_format => 'coordinate');
  246 $context{'LimitedVector-coordinate'}->constants->undefine('i','j','k');
  247 
  248 Context("LimitedVector");
  249 
  250 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9