[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 5551 - (download) (as text) (annotate)
Tue Oct 2 20:48:05 2007 UTC (12 years, 2 months ago) by sh002i
File size: 8113 byte(s)
improved formatting for docs -- these were in pod sections but were all
formatted as verbatim sections, and i moved them into normal paragraphs,
lists, etc. should make things more readable from the web.

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9