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

1 : sh002i 5556 ################################################################################
2 :     # WeBWorK Online Homework Delivery System
3 :     # Copyright 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
4 : gage 6058 # $CVSHeader$
5 : sh002i 5556 #
6 :     # This program is free software; you can redistribute it and/or modify it under
7 :     # the terms of either: (a) the GNU General Public License as published by the
8 :     # Free Software Foundation; either version 2, or (at your option) any later
9 :     # version, or (b) the "Artistic License" which comes with this package.
10 :     #
11 :     # This program is distributed in the hope that it will be useful, but WITHOUT
12 :     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 :     # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14 :     # Artistic License for more details.
15 :     ################################################################################
16 :    
17 : sh002i 5551 =head1 NAME
18 : dpvc 2726
19 : sh002i 5551 contextLimitedVector.pl - Allow vector entry but now vector operations.
20 : dpvc 2726
21 : sh002i 5551 =head1 DESCRIPTION
22 : gage 4997
23 : sh002i 5551 Implements a context in which vectors can be entered,
24 :     but no vector operations are permitted. So students will
25 :     be able to perform operations within the coordinates
26 :     of the vectors, but not between vectors.
27 : dpvc 2726
28 : sh002i 5551 Vectors can still be entered either in < , , > or ijk format.
29 :     Most of the complication here is to handle ijk format
30 :     properly. Each coordinate vector is allowed to appear
31 :     only once, so we have to keep track of that, and allow
32 :     SOME vector operations, but only when one term is
33 :     one of the coordinate constants, or one of the formulas
34 :     we've already OKed.
35 :    
36 :     You control which format to use by setting the context
37 :     to one of the following:
38 :    
39 : sh002i 5555 Context("LimitedVector-coordinate");
40 :     Context("LimitedVector-ijk");
41 :     Context("LimitedVector"); # either one
42 : sh002i 5551
43 : dpvc 5050 =cut
44 :    
45 : sh002i 5551 loadMacros("MathObjects.pl");
46 :    
47 :     sub _contextLimitedVector_init {LimitedVector::Init()}; # don't load it again
48 :    
49 : dpvc 5392 ##################################################
50 : dpvc 2726 #
51 :     # Handle common checking for BOPs
52 :     #
53 :     package LimitedVector::BOP;
54 :    
55 :     #
56 :     # Do original check and then if the operands are numbers, its OK.
57 :     # Otherwise, check if there is a duplicate constant from either term
58 :     # Otherwise, do an operator-specific check for if vectors are OK.
59 :     # Otherwise report an error.
60 :     #
61 :     sub _check {
62 :     my $self = shift;
63 :     my $super = ref($self); $super =~ s/LimitedVector/Parser/;
64 :     &{$super."::_check"}($self);
65 :     return if $self->checkNumbers;
66 : dpvc 5050 if ($self->context->{flags}{vector_format} ne 'coordinate') {
67 : dpvc 2726 $self->checkConstants($self->{lop});
68 :     $self->checkConstants($self->{rop});
69 :     return if $self->checkVectors;
70 :     }
71 :     my $bop = $self->{def}{string} || $self->{bop};
72 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers",$bop)
73 : dpvc 2726 if $self->{equation}{context}{flags}{vector_format} eq 'coordinate';
74 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers or i,j and k",$bop);
75 : dpvc 2726 }
76 :    
77 :     #
78 :     # filled in by subclasses
79 :     #
80 :     sub checkVectors {return 0}
81 :    
82 :     #
83 :     # Check if a constant has been repeated
84 :     # (we maintain a hash that lists if one is below us in the parse tree)
85 :     #
86 :     sub checkConstants {
87 :     my $self = shift; my $op = shift;
88 :     my $duplicate = '';
89 :     if ($op->class eq 'Constant') {
90 :     return unless $op->{name} =~ m/^[ijk]$/;
91 :     $duplicate = $op->{name} if $self->{ijk}{$op->{name}};
92 :     $self->{ijk}{$op->{name}} = 1;
93 :     } else {
94 :     foreach my $x ('i','j','k') {
95 :     $duplicate = $x if $self->{ijk}{$x} && $op->{ijk}{$x};
96 :     $self->{ijk}{$x} = $self->{ijk}{$x} || $op->{ijk}{$x};
97 :     }
98 :     }
99 : dpvc 3371 Value::Error("The constant '%s' may appear only once in your formula",$duplicate)
100 : dpvc 2726 if $duplicate;
101 :     }
102 :    
103 :     ##############################################
104 :     #
105 :     # Now we get the individual replacements for the operators
106 :     # that we don't want to allow. We inherit everything from
107 :     # the original Parser::BOP class, and just add the
108 :     # vector checks here.
109 :     #
110 :    
111 :     package LimitedVector::BOP::add;
112 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::add);
113 :    
114 :     sub checkVectors {
115 :     my $self = shift;
116 :     return (($self->{lop}->class eq 'Constant' || $self->{lop}->class =~ m/[BU]OP/) &&
117 :     ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/));
118 :     }
119 :    
120 :     ##############################################
121 :    
122 :     package LimitedVector::BOP::subtract;
123 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::subtract);
124 :    
125 :     sub checkVectors {
126 :     my $self = shift;
127 :     return (($self->{lop}->class eq 'Constant' || $self->{lop}->class =~ m/[BU]OP/) &&
128 :     ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/));
129 :     }
130 :    
131 :     ##############################################
132 :    
133 :     package LimitedVector::BOP::multiply;
134 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::multiply);
135 :    
136 :     sub checkVectors {
137 :     my $self = shift;
138 :     return (($self->{lop}->class eq 'Constant' || $self->{lop}->type eq 'Number') &&
139 :     ($self->{rop}->class eq 'Constant' || $self->{rop}->type eq 'Number'));
140 :     }
141 :    
142 :     ##############################################
143 :    
144 :     package LimitedVector::BOP::divide;
145 :     our @ISA = qw(LimitedVector::BOP Parser::BOP::divide);
146 :    
147 :     sub checkVectors {
148 :     my $self = shift;
149 :     my $bop = $self->{def}{string} || $self->{bop};
150 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers",$bop);
151 : dpvc 2726 }
152 :    
153 :     ##############################################
154 :     ##############################################
155 :     #
156 :     # Now we do the same for the unary operators
157 :     #
158 :    
159 :     package LimitedVector::UOP;
160 :    
161 :     sub _check {
162 :     my $self = shift;
163 :     my $super = ref($self); $super =~ s/LimitedVector/Parser/;
164 :     &{$super."::_check"}($self);
165 :     return if $self->checkNumber;
166 : dpvc 5050 if ($self->context->{flags}{vector_format} ne 'coordinate') {
167 : dpvc 2726 LimitedVector::BOP::checkConstants($self,$self->{op});
168 :     return if $self->checkVector;
169 :     }
170 :     my $uop = $self->{def}{string} || $self->{uop};
171 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers",$uop)
172 : dpvc 2726 if $self->{equation}{context}{flags}{vector_format} eq 'coordinate';
173 : dpvc 3371 $self->Error("In this context, '%s' can only be used with Numbers or i,j and k",$uop);
174 : dpvc 2726 }
175 :    
176 :     sub checkVector {return 0}
177 :    
178 :     ##############################################
179 :    
180 :     package LimitedVector::UOP::plus;
181 :     our @ISA = qw(LimitedVector::UOP Parser::UOP::plus);
182 :    
183 :     sub checkVector {return shift->{op}->class eq 'Constant'}
184 :    
185 :     ##############################################
186 :    
187 :     package LimitedVector::UOP::minus;
188 :     our @ISA = qw(LimitedVector::UOP Parser::UOP::minus);
189 :    
190 :     sub checkVector {return shift->{op}->class eq 'Constant'}
191 :    
192 :     ##############################################
193 :     ##############################################
194 :     #
195 :     # Absolute value does vector norm, so we
196 :     # trap that as well.
197 :     #
198 :    
199 :     package LimitedVector::List::AbsoluteValue;
200 :     our @ISA = qw(Parser::List::AbsoluteValue);
201 :    
202 :     sub _check {
203 :     my $self = shift;
204 :     $self->SUPER::_check;
205 :     return if $self->{coords}[0]->type eq 'Number';
206 :     $self->Error("Vector norm is not allowed in this context");
207 :     }
208 :    
209 :     ##############################################
210 :    
211 :     package LimitedVector::List::Vector;
212 :     our @ISA = qw(Parser::List::Vector);
213 :    
214 :     sub _check {
215 :     my $self = shift;
216 :     $self->SUPER::_check;
217 : dpvc 5050 return if $self->context->{flags}{vector_format} ne 'ijk';
218 : dpvc 2726 $self->Error("Vectors must be given in the form 'ai+bj+ck' in this context");
219 :     }
220 :    
221 :     ##############################################
222 :     ##############################################
223 :    
224 : dpvc 5392 package LimitedVector;
225 : dpvc 2726
226 : dpvc 5392 sub Init {
227 :     #
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{LimitedVector} = Parser::Context->getCopy("Vector");
233 : dpvc 5441 $context->{name} = "LimitedVector";
234 : dpvc 5392 $context->operators->set(
235 :     '+' => {class => 'LimitedVector::BOP::add'},
236 :     '-' => {class => 'LimitedVector::BOP::subtract'},
237 :     '*' => {class => 'LimitedVector::BOP::multiply'},
238 :     '* ' => {class => 'LimitedVector::BOP::multiply'},
239 :     ' *' => {class => 'LimitedVector::BOP::multiply'},
240 :     ' ' => {class => 'LimitedVector::BOP::multiply'},
241 :     '/' => {class => 'LimitedVector::BOP::divide'},
242 :     ' /' => {class => 'LimitedVector::BOP::divide'},
243 :     '/ ' => {class => 'LimitedVector::BOP::divide'},
244 :     'u+' => {class => 'LimitedVector::UOP::plus'},
245 :     'u-' => {class => 'LimitedVector::UOP::minus'},
246 :     );
247 :     #
248 :     # Remove these operators and functions
249 :     #
250 :     $context->operators->undefine('_','U','><','.');
251 :     $context->functions->undefine('norm','unit');
252 :     $context->lists->set(
253 :     AbsoluteValue => {class => 'LimitedVector::List::AbsoluteValue'},
254 :     Vector => {class => 'LimitedVector::List::Vector'},
255 :     );
256 :     #
257 :     # Format can be 'coordinate', 'ijk', or 'either'
258 :     #
259 :     $context->flags->set(vector_format => 'either');
260 : dpvc 2726
261 : dpvc 5392 #########################
262 : dpvc 2726
263 : dpvc 5392 $context = $main::context{'LimitedVector-ijk'} = $main::context{LimitedVector}->copy;
264 :     $context->flags->set(vector_format => 'ijk');
265 : dpvc 2726
266 : dpvc 5392 #########################
267 : dpvc 5373
268 : dpvc 5392 $context = $main::context{'LimitedVector-coordinate'} = $main::context{LimitedVector}->copy;
269 :     $context->flags->set(vector_format => 'coordinate');
270 :     $context->constants->undefine('i','j','k');
271 :    
272 :     #########################
273 :    
274 :     main::Context("LimitedVector"); ### FIXME: probably should require author to set this explicitly
275 :     }
276 :    
277 : dpvc 5373 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9