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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5551 - (view) (download) (as text)

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9