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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2726 - (download) (as text) (annotate)
Sat Sep 4 20:21:32 2004 UTC (15 years, 4 months ago) by dpvc
File size: 8113 byte(s)
These files provide contexts for the Parser in which only limited
operations are allowed.  The LimitedNumeric context is analogous to
strict_num_cmp().  The other contexts are similar, but for the
indicated type of answer.  In the LimitedVector context, for example,
the student can enter vectors, and can perform numeric operations
within the coordinates of the vectors, but can't perform vector
operations like vector addition or cross product.

    1 loadMacros("Parser.pl");
    2 
    3 sub _contextLimitedComplex_init {}; # don't load it again
    4 
    5 ##########################################################
    6 #
    7 #  Implements a context in which complex numbers can be entered,
    8 #  but no complex operations are permitted.  So students will
    9 #  be able to perform operations within the real and imaginary
   10 #  parts of the complex numbers, but not between complex numbers.
   11 #
   12 #
   13 #  Complex Numbers can still be entered in a+bi or r*e^(it) form.
   14 #  The e and i are allowed to be entered only once, so we have
   15 #  to keep track of that, and allow SOME complex operations,
   16 #  but only when one term is one of these constants (or an expression
   17 #  involving it that we've already OKed).
   18 #
   19 #  You control which format to use by setting the complex_format
   20 #  context flag to 'cartesian', 'polar' or 'either'. E.g.,
   21 #
   22 #      Context()->flags->set(complex_format => 'polar');
   23 #
   24 #  The default is 'either'.  There are predefined contexts that
   25 #  already have these values set:
   26 #
   27 #      Context("LimitedComplex-cartesian");
   28 #      Context("LimitedComplex-polar");
   29 #
   30 
   31 #
   32 #  Handle common checking for BOPs
   33 #
   34 package LimitedComplex::BOP;
   35 
   36 #
   37 #  Do original check and then if the operands are numbers, its OK.
   38 #  Otherwise, do an operator-specific check for if complex numbers are OK.
   39 #  Otherwise report an error.
   40 #
   41 sub _check {
   42   my $self = shift;
   43   my $super = ref($self); $super =~ s/LimitedComplex/Parser/;
   44   &{$super."::_check"}($self);
   45   return if $self->{lop}->isRealNumber && $self->{rop}->isRealNumber;
   46   Value::Error("The constant 'i' may appear only once in your formula")
   47     if ($self->{lop}->isComplex and $self->{rop}->isComplex);
   48   return if $self->checkComplex;
   49   my $bop = $self->{def}{string} || $self->{bop};
   50   $self->Error("Exponential form is 'r*e^(ai)'")
   51     if $self->{lop}{isPower} || $self->{rop}{isPower};
   52   $self->Error("Your answer should be of the form a+bi")
   53     if $self->{equation}{context}{flags}{complex_format} eq 'cartesian';
   54   $self->Error("Your answer should be of the form r*e^(ai)")
   55     if $self->{equation}{context}{flags}{complex_format} eq 'polar';
   56   $self->Error("Your answer should be of the form a+bi or r*e^(ai)");
   57 }
   58 
   59 #
   60 #  filled in by subclasses
   61 #
   62 sub checkComplex {return 0}
   63 
   64 ##############################################
   65 #
   66 #  Now we get the individual replacements for the operators
   67 #  that we don't want to allow.  We inherit everything from
   68 #  the original Parser::BOP class, and just add the
   69 #  complex checks here.  Note that checkComplex only
   70 #  gets called if exactly one of the terms is complex
   71 #  and the other is real.
   72 #
   73 
   74 package LimitedComplex::BOP::add;
   75 our @ISA = qw(LimitedComplex::BOP Parser::BOP::add);
   76 
   77 sub checkComplex {
   78   my $self = shift;
   79   return 0 if $self->{equation}{context}{flags}{complex_format} eq 'polar';
   80   my ($l,$r) = ($self->{lop},$self->{rop});
   81   if ($l->isComplex) {my $tmp = $l; $l = $r; $r = $tmp};
   82   return $r->class eq 'Constant' || $r->{isMult} ||
   83     ($r->class eq 'Complex' && $r->{value}[0] == 0);
   84 }
   85 
   86 ##############################################
   87 
   88 package LimitedComplex::BOP::subtract;
   89 our @ISA = qw(LimitedComplex::BOP Parser::BOP::subtract);
   90 
   91 sub checkComplex {
   92   my $self = shift;
   93   return 0 if $self->{equation}{context}{flags}{complex_format} eq 'polar';
   94   my ($l,$r) = ($self->{lop},$self->{rop});
   95   if ($l->isComplex) {my $tmp = $l; $l = $r; $r = $tmp};
   96   return $r->class eq 'Constant' || $r->{isMult} ||
   97     ($r->class eq 'Complex' && $r->{value}[0] == 0);
   98 }
   99 
  100 ##############################################
  101 
  102 package LimitedComplex::BOP::multiply;
  103 our @ISA = qw(LimitedComplex::BOP Parser::BOP::multiply);
  104 
  105 sub checkComplex {
  106   my $self = shift;
  107   my ($l,$r) = ($self->{lop},$self->{rop});
  108   $self->{isMult} = !$r->{isPower};
  109   return (($l->class eq 'Constant' || $l->isRealNumber) &&
  110     ($r->class eq 'Constant' || $r->isRealNumber || $r->{isPower}));
  111 }
  112 
  113 ##############################################
  114 
  115 package LimitedComplex::BOP::divide;
  116 our @ISA = qw(LimitedComplex::BOP Parser::BOP::divide);
  117 
  118 ##############################################
  119 
  120 package LimitedComplex::BOP::power;
  121 our @ISA = qw(LimitedComplex::BOP Parser::BOP::power);
  122 
  123 #
  124 #  Base must be 'e' (then we know the other is the complex
  125 #  since we only get here if exactly one term is complex)
  126 #
  127 sub checkComplex {
  128   my $self = shift;
  129   return 0 if $self->{equation}{context}{flags}{complex_format} eq 'cartesian';
  130   my ($l,$r) = ($self->{lop},$self->{rop});
  131   $self->{isPower} = 1;
  132   return 1 if ($l->class eq 'Constant' && $l->{name} eq 'e' &&
  133          ($r->class eq 'Constant' || $r->{isMult} ||
  134     $r->class eq 'Complex' && $r->{value}[0] == 0));
  135   $self->Error("Exponentials can only be of the form 'e^(ai)' in this context");
  136 }
  137 
  138 ##############################################
  139 ##############################################
  140 #
  141 #  Now we do the same for the unary operators
  142 #
  143 
  144 package LimitedComplex::UOP;
  145 
  146 sub _check {
  147   my $self = shift;
  148   my $super = ref($self); $super =~ s/LimitedComplex/Parser/;
  149   &{$super."::_check"}($self);
  150   my $op = $self->{op};
  151   return if $op->isRealNumber;
  152   return if $self->{op}{isMult} || $self->{op}{isPower};
  153   return if $op->class eq 'Constant' && $op->{name} eq 'i';
  154   my $uop = $self->{def}{string} || $self->{uop};
  155   $self->Error("Your answer should be of the form a+bi")
  156     if $self->{equation}{context}{flags}{complex_format} eq 'cartesian';
  157   $self->Error("Your answer should be of the form r*e^(ai)")
  158     if $self->{equation}{context}{flags}{complex_format} eq 'polar';
  159   $self->Error("Your answer should be of the form a+bi or r*e^(ai)");
  160 }
  161 
  162 sub checkComplex {return 0}
  163 
  164 ##############################################
  165 
  166 package LimitedComplex::UOP::plus;
  167 our @ISA = qw(LimitedComplex::UOP Parser::UOP::plus);
  168 
  169 ##############################################
  170 
  171 package LimitedComplex::UOP::minus;
  172 our @ISA = qw(LimitedComplex::UOP Parser::UOP::minus);
  173 
  174 ##############################################
  175 ##############################################
  176 #
  177 #  Absolute value does complex norm, so we
  178 #  trap that as well.
  179 #
  180 
  181 package LimitedComplex::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]->isRealNumber;
  188   $self->Error("Can't take absolute value of Complex Numbers in this context");
  189 }
  190 
  191 ##############################################
  192 ##############################################
  193 
  194 package main;
  195 
  196 #
  197 #  Now build the new context that calls the
  198 #  above classes rather than the usual ones
  199 #
  200 
  201 $context{LimitedComplex} = Context("Complex");
  202 $context{LimitedComplex}->operators->set(
  203    '+' => {class => 'LimitedComplex::BOP::add'},
  204    '-' => {class => 'LimitedComplex::BOP::subtract'},
  205    '*' => {class => 'LimitedComplex::BOP::multiply'},
  206   '* ' => {class => 'LimitedComplex::BOP::multiply'},
  207   ' *' => {class => 'LimitedComplex::BOP::multiply'},
  208    ' ' => {class => 'LimitedComplex::BOP::multiply'},
  209    '/' => {class => 'LimitedComplex::BOP::divide'},
  210   ' /' => {class => 'LimitedComplex::BOP::divide'},
  211   '/ ' => {class => 'LimitedComplex::BOP::divide'},
  212    '^' => {class => 'LimitedComplex::BOP::power'},
  213   '**' => {class => 'LimitedComplex::BOP::power'},
  214   'u+' => {class => 'LimitedComplex::UOP::plus'},
  215   'u-' => {class => 'LimitedComplex::UOP::minus'},
  216 );
  217 #
  218 #  Remove these operators and functions
  219 #
  220 $context{LimitedComplex}->lists->set(
  221   AbsoluteValue => {class => 'LimitedComplex::List::AbsoluteValue'},
  222 );
  223 $context{LimitedComplex}->operators->undefine('_','U');
  224 Parser::Context::Functions::Disable('Complex');
  225 foreach my $fn ($context{LimitedComplex}->functions->names)
  226   {$context{LimitedComplex}->{functions}{$fn}{nocomplex} = 1}
  227 #
  228 #  Format can be 'cartesian', 'polar', or 'either'
  229 #
  230 $context{LimitedComplex}->flags->set(complex_format => 'either');
  231 
  232 $context{'LimitedComplex-cartesian'} = $context{LimitedComplex}->copy;
  233 $context{'LimitedComplex-cartesian'}->flags->set(complex_format => 'cartesian');
  234 
  235 $context{'LimitedComplex-polar'} = $context{LimitedComplex}->copy;
  236 $context{'LimitedComplex-polar'}->flags->set(complex_format => 'polar');
  237 
  238 Context("LimitedComplex");

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9