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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9