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

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9