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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 : dpvc 5371 loadMacros("MathObjects.pl");
2 : dpvc 2726
3 :     sub _contextLimitedVector_init {}; # don't load it again
4 :    
5 : gage 4997 =head3 Context("LimitedVector")
6 :    
7 : dpvc 5373 ##########################################################
8 :     #
9 :     # Implements a context in which vectors can be entered,
10 :     # but no vector operations are permitted. So students will
11 :     # be able to perform operations within the coordinates
12 :     # of the vectors, but not between vectors.
13 :     #
14 :     # Vectors can still be entered either in < , , > or ijk format.
15 :     # Most of the complication here is to handle ijk format
16 :     # properly. Each coordinate vector is allowed to appear
17 :     # only once, so we have to keep track of that, and allow
18 :     # SOME vector operations, but only when one term is
19 :     # one of the coordinate constants, or one of the formulas
20 :     # we've already OKed.
21 :     #
22 :     # You control which format to use by setting the context
23 :     # to one of the following:
24 :     #
25 :     # Context("LimitedVector-coordinate");
26 :     # Context("LimitedVector-ijk");
27 :     # Context("LimitedVector"); # either one
28 :     #
29 : dpvc 2726
30 : dpvc 5050 =cut
31 :    
32 : dpvc 2726 #
33 :     # Handle common checking for BOPs
34 :     #
35 :     package LimitedVector::BOP;
36 :    
37 :     #
38 :     # Do original check and then if the operands are numbers, its OK.
39 :     # Otherwise, check if there is a duplicate constant from either term
40 :     # Otherwise, do an operator-specific check for if vectors are OK.
41 :     # Otherwise report an error.
42 :     #
43 :     sub _check {
44 :     my $self = shift;
45 :     my $super = ref($self); $super =~ s/LimitedVector/Parser/;
46 :     &{$super."::_check"}($self);
47 :     return if $self->checkNumbers;
48 : dpvc 5050 if ($self->context->{flags}{vector_format} ne 'coordinate') {
49 : dpvc 2726 $self->checkConstants($self->{lop});
50 :     $self->checkConstants($self->{rop});
51 :     return if $self->checkVectors;
52 :     }
53 :     my $bop = $self->{def}{string} || $self->{bop};
54 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers",$bop)
55 : dpvc 2726 if $self->{equation}{context}{flags}{vector_format} eq 'coordinate';
56 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers or i,j and k",$bop);
57 : dpvc 2726 }
58 :    
59 :     #
60 :     # filled in by subclasses
61 :     #
62 :     sub checkVectors {return 0}
63 :    
64 :     #
65 :     # Check if a constant has been repeated
66 :     # (we maintain a hash that lists if one is below us in the parse tree)
67 :     #
68 :     sub checkConstants {
69 :     my $self = shift; my $op = shift;
70 :     my $duplicate = '';
71 :     if ($op->class eq 'Constant') {
72 :     return unless $op->{name} =~ m/^[ijk]$/;
73 :     $duplicate = $op->{name} if $self->{ijk}{$op->{name}};
74 :     $self->{ijk}{$op->{name}} = 1;
75 :     } else {
76 :     foreach my $x ('i','j','k') {
77 :     $duplicate = $x if $self->{ijk}{$x} && $op->{ijk}{$x};
78 :     $self->{ijk}{$x} = $self->{ijk}{$x} || $op->{ijk}{$x};
79 :     }
80 :     }
81 : dpvc 3371 Value::Error("The constant '%s' may appear only once in your formula",$duplicate)
82 : dpvc 2726 if $duplicate;
83 :     }
84 :    
85 :     ##############################################
86 :     #
87 :     # Now we get the individual replacements for the operators
88 :     # that we don't want to allow. We inherit everything from
89 :     # the original Parser::BOP class, and just add the
90 :     # vector checks here.
91 :     #
92 :    
93 :     package LimitedVector::BOP::add;
94 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::add);
95 :    
96 :     sub checkVectors {
97 :     my $self = shift;
98 :     return (($self->{lop}->class eq 'Constant' || $self->{lop}->class =~ m/[BU]OP/) &&
99 :     ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/));
100 :     }
101 :    
102 :     ##############################################
103 :    
104 :     package LimitedVector::BOP::subtract;
105 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::subtract);
106 :    
107 :     sub checkVectors {
108 :     my $self = shift;
109 :     return (($self->{lop}->class eq 'Constant' || $self->{lop}->class =~ m/[BU]OP/) &&
110 :     ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/));
111 :     }
112 :    
113 :     ##############################################
114 :    
115 :     package LimitedVector::BOP::multiply;
116 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::multiply);
117 :    
118 :     sub checkVectors {
119 :     my $self = shift;
120 :     return (($self->{lop}->class eq 'Constant' || $self->{lop}->type eq 'Number') &&
121 :     ($self->{rop}->class eq 'Constant' || $self->{rop}->type eq 'Number'));
122 :     }
123 :    
124 :     ##############################################
125 :    
126 :     package LimitedVector::BOP::divide;
127 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::divide);
128 :    
129 :     sub checkVectors {
130 :     my $self = shift;
131 :     my $bop = $self->{def}{string} || $self->{bop};
132 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers",$bop);
133 : dpvc 2726 }
134 :    
135 :     ##############################################
136 :     ##############################################
137 :     #
138 :     # Now we do the same for the unary operators
139 :     #
140 :    
141 :     package LimitedVector::UOP;
142 :    
143 :     sub _check {
144 :     my $self = shift;
145 :     my $super = ref($self); $super =~ s/LimitedVector/Parser/;
146 :     &{$super."::_check"}($self);
147 :     return if $self->checkNumber;
148 : dpvc 5050 if ($self->context->{flags}{vector_format} ne 'coordinate') {
149 : dpvc 2726 LimitedVector::BOP::checkConstants($self,$self->{op});
150 :     return if $self->checkVector;
151 :     }
152 :     my $uop = $self->{def}{string} || $self->{uop};
153 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers",$uop)
154 : dpvc 2726 if $self->{equation}{context}{flags}{vector_format} eq 'coordinate';
155 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers or i,j and k",$uop);
156 : dpvc 2726 }
157 :    
158 :     sub checkVector {return 0}
159 :    
160 :     ##############################################
161 :    
162 :     package LimitedVector::UOP::plus;
163 :     our @ISA = qw(LimitedVector::UOP Parser::UOP::plus);
164 :    
165 :     sub checkVector {return shift->{op}->class eq 'Constant'}
166 :    
167 :     ##############################################
168 :    
169 :     package LimitedVector::UOP::minus;
170 :     our @ISA = qw(LimitedVector::UOP Parser::UOP::minus);
171 :    
172 :     sub checkVector {return shift->{op}->class eq 'Constant'}
173 :    
174 :     ##############################################
175 :     ##############################################
176 :     #
177 :     # Absolute value does vector norm, so we
178 :     # trap that as well.
179 :     #
180 :    
181 :     package LimitedVector::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]->type eq 'Number';
188 :     $self->Error("Vector norm is not allowed in this context");
189 :     }
190 :    
191 :     ##############################################
192 :    
193 :     package LimitedVector::List::Vector;
194 :     our @ISA = qw(Parser::List::Vector);
195 :    
196 :     sub _check {
197 :     my $self = shift;
198 :     $self->SUPER::_check;
199 : dpvc 5050 return if $self->context->{flags}{vector_format} ne 'ijk';
200 : dpvc 2726 $self->Error("Vectors must be given in the form 'ai+bj+ck' in this context");
201 :     }
202 :    
203 :     ##############################################
204 :     ##############################################
205 :    
206 :     package main;
207 :    
208 :     #
209 :     # Now build the new context that calls the
210 :     # above classes rather than the usual ones
211 :     #
212 :    
213 : dpvc 5370 $context{LimitedVector} = Parser::Context->getCopy("Vector");
214 : dpvc 2726 $context{LimitedVector}->operators->set(
215 :     '+' => {class => 'LimitedVector::BOP::add'},
216 :     '-' => {class => 'LimitedVector::BOP::subtract'},
217 :     '*' => {class => 'LimitedVector::BOP::multiply'},
218 :     '* ' => {class => 'LimitedVector::BOP::multiply'},
219 :     ' *' => {class => 'LimitedVector::BOP::multiply'},
220 :     ' ' => {class => 'LimitedVector::BOP::multiply'},
221 :     '/' => {class => 'LimitedVector::BOP::divide'},
222 :     ' /' => {class => 'LimitedVector::BOP::divide'},
223 :     '/ ' => {class => 'LimitedVector::BOP::divide'},
224 :     'u+' => {class => 'LimitedVector::UOP::plus'},
225 :     'u-' => {class => 'LimitedVector::UOP::minus'},
226 :     );
227 :     #
228 :     # Remove these operators and functions
229 :     #
230 :     $context{LimitedVector}->operators->undefine('_','U','><','.');
231 :     $context{LimitedVector}->functions->undefine('norm','unit');
232 :     $context{LimitedVector}->lists->set(
233 :     AbsoluteValue => {class => 'LimitedVector::List::AbsoluteValue'},
234 :     Vector => {class => 'LimitedVector::List::Vector'},
235 :     );
236 :     #
237 :     # Format can be 'coordinate', 'ijk', or 'either'
238 :     #
239 :     $context{LimitedVector}->flags->set(vector_format => 'either');
240 :    
241 :     $context{'LimitedVector-ijk'} = $context{LimitedVector}->copy;
242 :     $context{'LimitedVector-ijk'}->flags->set(vector_format => 'ijk');
243 :    
244 :     $context{'LimitedVector-coordinate'} = $context{LimitedVector}->copy;
245 :     $context{'LimitedVector-coordinate'}->flags->set(vector_format => 'coordinate');
246 :     $context{'LimitedVector-coordinate'}->constants->undefine('i','j','k');
247 :    
248 :     Context("LimitedVector");
249 : dpvc 5373
250 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9