[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 5392 - (view) (download) (as text)

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9