[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 5441 - (download) (as text) (annotate)
Tue Aug 28 22:40:15 2007 UTC (12 years, 5 months ago) by dpvc
File size: 8176 byte(s)
Add context names for the context(s) created here.

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9