Parent Directory
|
Revision Log
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 |