[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 2726 - (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 :     # 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