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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 2726 Revision 5371
1loadMacros("Parser.pl"); 1loadMacros("MathObjects.pl");
2 2
3sub _contextLimitedComplex_init {}; # don't load it again 3sub _contextLimitedComplex_init {}; # don't load it again
4 4
5=head3 Context("LimitedComplex")
6
5########################################################## 7 ##########################################################
6# 8 #
7# Implements a context in which complex numbers can be entered, 9 # Implements a context in which complex numbers can be entered,
8# but no complex operations are permitted. So students will 10 # but no complex operations are permitted. So students will
9# be able to perform operations within the real and imaginary 11 # be able to perform operations within the real and imaginary
10# parts of the complex numbers, but not between complex numbers. 12 # parts of the complex numbers, but not between complex numbers.
11# 13 #
12# 14 #
13# Complex Numbers can still be entered in a+bi or r*e^(it) form. 15 # Complex Numbers can still be entered in a+bi or a*e^(bt) form.
14# The e and i are allowed to be entered only once, so we have 16 # 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, 17 # to keep track of that, and allow SOME complex operations,
16# but only when one term is one of these constants (or an expression 18 # but only when one term is one of these constants (or an expression
17# involving it that we've already OKed). 19 # involving it that we've already OKed).
18# 20 #
19# You control which format to use by setting the complex_format 21 # You control which format to use by setting the complex_format
20# context flag to 'cartesian', 'polar' or 'either'. E.g., 22 # context flag to 'cartesian', 'polar' or 'either'. E.g.,
21# 23 #
22# Context()->flags->set(complex_format => 'polar'); 24 # Context()->flags->set(complex_format => 'polar');
23# 25 #
24# The default is 'either'. There are predefined contexts that 26 # The default is 'either'. There are predefined contexts that
25# already have these values set: 27 # already have these values set:
26# 28 #
27# Context("LimitedComplex-cartesian"); 29 # Context("LimitedComplex-cartesian");
28# Context("LimitedComplex-polar"); 30 # Context("LimitedComplex-polar");
29# 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
30 48
31# 49#
32# Handle common checking for BOPs 50# Handle common checking for BOPs
33# 51#
34package LimitedComplex::BOP; 52package LimitedComplex::BOP;
40# 58#
41sub _check { 59sub _check {
42 my $self = shift; 60 my $self = shift;
43 my $super = ref($self); $super =~ s/LimitedComplex/Parser/; 61 my $super = ref($self); $super =~ s/LimitedComplex/Parser/;
44 &{$super."::_check"}($self); 62 &{$super."::_check"}($self);
45 return if $self->{lop}->isRealNumber && $self->{rop}->isRealNumber; 63 if ($self->{lop}->isRealNumber && $self->{rop}->isRealNumber) {
64 return unless $self->context->{flags}{strict_numeric};
65 } else {
46 Value::Error("The constant 'i' may appear only once in your formula") 66 Value::Error("The constant 'i' may appear only once in your formula")
47 if ($self->{lop}->isComplex and $self->{rop}->isComplex); 67 if ($self->{lop}->isComplex and $self->{rop}->isComplex);
48 return if $self->checkComplex; 68 return if $self->checkComplex;
49 my $bop = $self->{def}{string} || $self->{bop};
50 $self->Error("Exponential form is 'r*e^(ai)'") 69 $self->Error("Exponential form is 'a*e^(bi)'")
51 if $self->{lop}{isPower} || $self->{rop}{isPower}; 70 if $self->{lop}{isPower} || $self->{rop}{isPower};
71 }
52 $self->Error("Your answer should be of the form a+bi") 72 $self->Error("Your answer should be of the form %s",$self->theForm)
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} 73}
58 74
59# 75#
60# filled in by subclasses 76# filled in by subclasses
61# 77#
62sub checkComplex {return 0} 78sub checkComplex {return 0}
79
80#
81# Get the form for use in error messages
82#
83sub theForm {
84 my $self = shift;
85 my $format = $self->context->{flags}{complex_format};
86 return 'a+bi' if $format eq 'cartesian';
87 return 'a*e^(bi)' if $format eq 'polar';
88 return 'a+bi or a*e^(bi)';
89}
63 90
64############################################## 91##############################################
65# 92#
66# Now we get the individual replacements for the operators 93# Now we get the individual replacements for the operators
67# that we don't want to allow. We inherit everything from 94# that we don't want to allow. We inherit everything from
74package LimitedComplex::BOP::add; 101package LimitedComplex::BOP::add;
75our @ISA = qw(LimitedComplex::BOP Parser::BOP::add); 102our @ISA = qw(LimitedComplex::BOP Parser::BOP::add);
76 103
77sub checkComplex { 104sub checkComplex {
78 my $self = shift; 105 my $self = shift;
79 return 0 if $self->{equation}{context}{flags}{complex_format} eq 'polar'; 106 return 0 if $self->context->{flags}{complex_format} eq 'polar';
80 my ($l,$r) = ($self->{lop},$self->{rop}); 107 my ($l,$r) = ($self->{lop},$self->{rop});
81 if ($l->isComplex) {my $tmp = $l; $l = $r; $r = $tmp}; 108 if ($l->isComplex) {my $tmp = $l; $l = $r; $r = $tmp};
82 return $r->class eq 'Constant' || $r->{isMult} || 109 return $r->class eq 'Constant' || $r->{isMult} ||
83 ($r->class eq 'Complex' && $r->{value}[0] == 0); 110 ($r->class eq 'Complex' && $r->{value}[0] == 0);
84} 111}
88package LimitedComplex::BOP::subtract; 115package LimitedComplex::BOP::subtract;
89our @ISA = qw(LimitedComplex::BOP Parser::BOP::subtract); 116our @ISA = qw(LimitedComplex::BOP Parser::BOP::subtract);
90 117
91sub checkComplex { 118sub checkComplex {
92 my $self = shift; 119 my $self = shift;
93 return 0 if $self->{equation}{context}{flags}{complex_format} eq 'polar'; 120 return 0 if $self->context->{flags}{complex_format} eq 'polar';
94 my ($l,$r) = ($self->{lop},$self->{rop}); 121 my ($l,$r) = ($self->{lop},$self->{rop});
95 if ($l->isComplex) {my $tmp = $l; $l = $r; $r = $tmp}; 122 if ($l->isComplex) {my $tmp = $l; $l = $r; $r = $tmp};
96 return $r->class eq 'Constant' || $r->{isMult} || 123 return $r->class eq 'Constant' || $r->{isMult} ||
97 ($r->class eq 'Complex' && $r->{value}[0] == 0); 124 ($r->class eq 'Complex' && $r->{value}[0] == 0);
98} 125}
124# Base must be 'e' (then we know the other is the complex 151# Base must be 'e' (then we know the other is the complex
125# since we only get here if exactly one term is complex) 152# since we only get here if exactly one term is complex)
126# 153#
127sub checkComplex { 154sub checkComplex {
128 my $self = shift; 155 my $self = shift;
129 return 0 if $self->{equation}{context}{flags}{complex_format} eq 'cartesian'; 156 return 0 if $self->context->{flags}{complex_format} eq 'cartesian';
130 my ($l,$r) = ($self->{lop},$self->{rop}); 157 my ($l,$r) = ($self->{lop},$self->{rop});
131 $self->{isPower} = 1; 158 $self->{isPower} = 1;
132 return 1 if ($l->class eq 'Constant' && $l->{name} eq 'e' && 159 return 1 if ($l->class eq 'Constant' && $l->{name} eq 'e' &&
133 ($r->class eq 'Constant' || $r->{isMult} || 160 ($r->class eq 'Constant' || $r->{isMult} || $r->{isOp} ||
134 $r->class eq 'Complex' && $r->{value}[0] == 0)); 161 $r->class eq 'Complex' && $r->{value}[0] == 0));
135 $self->Error("Exponentials can only be of the form 'e^(ai)' in this context"); 162 $self->Error("Exponentials can only be of the form 'e^(ai)' in this context");
136} 163}
137 164
138############################################## 165##############################################
145 172
146sub _check { 173sub _check {
147 my $self = shift; 174 my $self = shift;
148 my $super = ref($self); $super =~ s/LimitedComplex/Parser/; 175 my $super = ref($self); $super =~ s/LimitedComplex/Parser/;
149 &{$super."::_check"}($self); 176 &{$super."::_check"}($self);
150 my $op = $self->{op}; 177 my $op = $self->{op}; $self->{isOp} = 1;
151 return if $op->isRealNumber; 178 if ($op->isRealNumber) {
179 return unless $self->context->{flags}{strict_numeric};
180 return if $op->class eq 'Number';
181 } else {
152 return if $self->{op}{isMult} || $self->{op}{isPower}; 182 return if $self->{op}{isMult} || $self->{op}{isPower};
153 return if $op->class eq 'Constant' && $op->{name} eq 'i'; 183 return if $op->class eq 'Constant' && $op->{name} eq 'i';
154 my $uop = $self->{def}{string} || $self->{uop}; 184 }
155 $self->Error("Your answer should be of the form a+bi") 185 $self->Error("Your answer should be of the form %s",$self->theForm)
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} 186}
161 187
162sub checkComplex {return 0} 188sub checkComplex {return 0}
189
190sub theForm {LimitedComplex::BOP::theForm(@_)}
163 191
164############################################## 192##############################################
165 193
166package LimitedComplex::UOP::plus; 194package LimitedComplex::UOP::plus;
167our @ISA = qw(LimitedComplex::UOP Parser::UOP::plus); 195our @ISA = qw(LimitedComplex::UOP Parser::UOP::plus);
196# 224#
197# Now build the new context that calls the 225# Now build the new context that calls the
198# above classes rather than the usual ones 226# above classes rather than the usual ones
199# 227#
200 228
201$context{LimitedComplex} = Context("Complex"); 229$context{LimitedComplex} = Parser::Context->getCopy("Complex");
202$context{LimitedComplex}->operators->set( 230$context{LimitedComplex}->operators->set(
203 '+' => {class => 'LimitedComplex::BOP::add'}, 231 '+' => {class => 'LimitedComplex::BOP::add'},
204 '-' => {class => 'LimitedComplex::BOP::subtract'}, 232 '-' => {class => 'LimitedComplex::BOP::subtract'},
205 '*' => {class => 'LimitedComplex::BOP::multiply'}, 233 '*' => {class => 'LimitedComplex::BOP::multiply'},
206 '* ' => {class => 'LimitedComplex::BOP::multiply'}, 234 '* ' => {class => 'LimitedComplex::BOP::multiply'},
219# 247#
220$context{LimitedComplex}->lists->set( 248$context{LimitedComplex}->lists->set(
221 AbsoluteValue => {class => 'LimitedComplex::List::AbsoluteValue'}, 249 AbsoluteValue => {class => 'LimitedComplex::List::AbsoluteValue'},
222); 250);
223$context{LimitedComplex}->operators->undefine('_','U'); 251$context{LimitedComplex}->operators->undefine('_','U');
224Parser::Context::Functions::Disable('Complex'); 252$context{LimitedComplex}->functions->disable('Complex');
225foreach my $fn ($context{LimitedComplex}->functions->names) 253foreach my $fn ($context{LimitedComplex}->functions->names)
226 {$context{LimitedComplex}->{functions}{$fn}{nocomplex} = 1} 254 {$context{LimitedComplex}->{functions}{$fn}{nocomplex} = 1}
227# 255#
228# Format can be 'cartesian', 'polar', or 'either' 256# Format can be 'cartesian', 'polar', or 'either'
229# 257#
233$context{'LimitedComplex-cartesian'}->flags->set(complex_format => 'cartesian'); 261$context{'LimitedComplex-cartesian'}->flags->set(complex_format => 'cartesian');
234 262
235$context{'LimitedComplex-polar'} = $context{LimitedComplex}->copy; 263$context{'LimitedComplex-polar'} = $context{LimitedComplex}->copy;
236$context{'LimitedComplex-polar'}->flags->set(complex_format => 'polar'); 264$context{'LimitedComplex-polar'}->flags->set(complex_format => 'polar');
237 265
266$context{'LimitedComplex-cartesian-strict'} = $context{'LimitedComplex-cartesian'}->copy;
267$context{'LimitedComplex-cartesian-strict'}->flags->set(strict_numeric => 1);
268$context{'LimitedComplex-cartesian-strict'}->functions->disable('All');
269
270$context{'LimitedComplex-polar-strict'} = $context{'LimitedComplex-polar'}->copy;
271$context{'LimitedComplex-polar-strict'}->flags->set(strict_numeric => 1);
272$context{'LimitedComplex-polar-strict'}->functions->disable('All');
273
274$context{'LimitedComplex-strict'} = $context{'LimitedComplex'}->copy;
275$context{'LimitedComplex-strict'}->flags->set(strict_numeric => 1);
276$context{'LimitedComplex-strict'}->functions->disable('All');
277
238Context("LimitedComplex"); 278Context("LimitedComplex");

Legend:
Removed from v.2726  
changed lines
  Added in v.5371

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9