Parent Directory
|
Revision Log
Revision 2727 - (view) (download) (as text)
| 1 : | dpvc | 2727 | loadMacros('Parser.pl'); |
| 2 : | |||
| 3 : | sub _parserImplicitPlane_init {}; # don't reload this file | ||
| 4 : | |||
| 5 : | ###################################################################### | ||
| 6 : | # | ||
| 7 : | # This is a Parser class that implements implicit planes as | ||
| 8 : | # a subclass of the Formula class. The standard ->cmp routine | ||
| 9 : | # will work for this, provided we define the compare() function | ||
| 10 : | # needed by the overloaded ==. We assign the special precedence | ||
| 11 : | # so that overloaded operations will be promoted to the ones below. | ||
| 12 : | # | ||
| 13 : | # | ||
| 14 : | # Use ImplicitPlane(point,vector), ImplicitPlane(point,number) or | ||
| 15 : | # ImplicitPlane(formula) to create an ImplicitPlane object. | ||
| 16 : | # The first form uses the point as a point on the plane and the | ||
| 17 : | # vector as the normal for the plane. The second form uses the point | ||
| 18 : | # as the coefficients of the variables and the number as the value | ||
| 19 : | # that the formula must equal. The third form uses the formula | ||
| 20 : | # directly. | ||
| 21 : | # | ||
| 22 : | # The number of variables in the Context determines the dimension of | ||
| 23 : | # the "plane" being defined. If there are only two, the formula | ||
| 24 : | # produces an implicit line, but if there are four variables, it will | ||
| 25 : | # be a hyperplane in four-space. You can specify the variables you | ||
| 26 : | # want to use by supplying an additional parameter, which is a | ||
| 27 : | # reference to an array of variable names. | ||
| 28 : | # | ||
| 29 : | # | ||
| 30 : | # Usage examples: | ||
| 31 : | # | ||
| 32 : | # $P = ImplicitPlane(Point(1,0,2),Vector(-1,1,3)); # -x+y+3z = 5 | ||
| 33 : | # $P = ImplicitPlane([1,0,2],[-1,1,3]); # -x+y+3z = 5 | ||
| 34 : | # $P = ImplicitPlane([1,0,2],4); # x+2z = 4 | ||
| 35 : | # $P = ImplicitPlane("x+2y-z=5"); | ||
| 36 : | # | ||
| 37 : | # Context()->variables->are(x=>'Real',y=>'Real',z=>'Real',w=>'Real'); | ||
| 38 : | # $P = ImplicitPlane([1,0,2,-1],10); # w+2y-z = 10 (alphabetical order) | ||
| 39 : | # $P = ImplicitPlane([3,-1,2,4],5,['x','y','z','w']); # 3x-y+2z+4w = 5 | ||
| 40 : | # $P = ImplicitPlane([3,-1,2],5,['y','z','w']); # 3y-z+2w = 5 | ||
| 41 : | # | ||
| 42 : | # Then use | ||
| 43 : | # | ||
| 44 : | # ANS($P->cmp); | ||
| 45 : | # | ||
| 46 : | # to get the answer checker for $P. | ||
| 47 : | # | ||
| 48 : | |||
| 49 : | # | ||
| 50 : | # Create a context for implicit planes and activate it | ||
| 51 : | # | ||
| 52 : | $context{ImplicitPlane} = Context("Vector")->copy(); | ||
| 53 : | $context{ImplicitPlane}->{precedence}{ImplicitPlane} = Context()->{precedence}{special}; | ||
| 54 : | Context("ImplicitPlane"); | ||
| 55 : | # | ||
| 56 : | # allow equalities in formulas | ||
| 57 : | # | ||
| 58 : | Parser::BOP::equality::Allow; | ||
| 59 : | |||
| 60 : | # | ||
| 61 : | # Syntactic sugar for creating implicit planes | ||
| 62 : | # | ||
| 63 : | sub ImplicitPlane {ImplicitPlane->new(@_)} | ||
| 64 : | |||
| 65 : | # | ||
| 66 : | # Define the subclass of Formula | ||
| 67 : | # | ||
| 68 : | package ImplicitPlane; | ||
| 69 : | our @ISA = qw(Value::Formula); | ||
| 70 : | |||
| 71 : | sub new { | ||
| 72 : | my $self = shift; my $class = ref($self) || $self; | ||
| 73 : | return shift if scalar(@_) == 1 && ref($_[0]) eq $class; | ||
| 74 : | $_[0] = Value::Point->new($_[0]) if ref($_[0]) eq 'ARRAY'; | ||
| 75 : | $_[1] = Value::Vector->new($_[1]) if ref($_[1]) eq 'ARRAY'; | ||
| 76 : | |||
| 77 : | my ($p,$N,$plane,$vars,$d,$type); $type = 'plane'; | ||
| 78 : | if (scalar(@_) >= 2 && Value::class($_[0]) =~ m/^(Point|Vector)/ && | ||
| 79 : | Value::class($_[1]) eq 'Vector' || Value::isRealNumber($_[1])) { | ||
| 80 : | # | ||
| 81 : | # Make a plane from a point and a vector, | ||
| 82 : | # or from a list of coefficients and the constant | ||
| 83 : | # | ||
| 84 : | $p = shift; $N = shift; | ||
| 85 : | if (Value::class($N) eq 'Vector') {$d = $p.$N} | ||
| 86 : | else {$d = Value::Real->make($N); $N = Value::Vector->new($p)} | ||
| 87 : | $vars = shift || [$$Value::context->variables->names]; | ||
| 88 : | $vars = [$vars] unless ref($vars) eq 'ARRAY'; | ||
| 89 : | $type = 'line' if scalar(@{$vars}) == 2; | ||
| 90 : | my @terms = (); my $i = 0; | ||
| 91 : | foreach my $x (@{$vars}) {push @terms, $N->{data}[$i++]->string.$x} | ||
| 92 : | $plane = Value::Formula->new(join(' + ',@terms).' = '.$d->string)->reduce; | ||
| 93 : | } else { | ||
| 94 : | # | ||
| 95 : | # Determine the normal vector and d value from the equation | ||
| 96 : | # | ||
| 97 : | $plane = shift; | ||
| 98 : | $plane = Value::Formula->new($plane) unless Value::isValue($plane); | ||
| 99 : | $vars = shift || [$$Value::context->variables->names]; | ||
| 100 : | $vars = [$vars] unless ref($vars) eq 'ARRAY'; | ||
| 101 : | $type = 'line' if scalar(@{$vars}) == 2; | ||
| 102 : | Value::Error("Your formula doesn't look like an implicit $type") | ||
| 103 : | unless $plane->type eq 'Equality'; | ||
| 104 : | # | ||
| 105 : | # Find the coefficients of the formula | ||
| 106 : | # | ||
| 107 : | my $f = Value::Formula->new($plane->{tree}{lop}) - | ||
| 108 : | Value::Formula->new($plane->{tree}{rop}); | ||
| 109 : | my $F = $f->perlFunction(undef,[@{$vars}]); | ||
| 110 : | my @v = split('','0' x scalar(@{$vars})); | ||
| 111 : | $d = -&$F(@v); my @coeff = (@v); | ||
| 112 : | foreach my $i (0..scalar(@v)-1) | ||
| 113 : | {$v[$i] = 1; $coeff[$i] = &$F(@v) + $d; $v[$i] = 0} | ||
| 114 : | # | ||
| 115 : | # Check that the student's formula really is what we thought | ||
| 116 : | # | ||
| 117 : | $N = Value::Vector->new([@coeff]); | ||
| 118 : | $plane = ImplicitPlane->new($N,$d,$vars); | ||
| 119 : | Value::Error("Your formula isn't a linear one") | ||
| 120 : | unless (Value::Formula->new($plane->{tree}{lop}) - | ||
| 121 : | Value::Formula->new($plane->{tree}{rop})) == $f; | ||
| 122 : | } | ||
| 123 : | Value::Error("The equation of a $type must be non-zero somewhere") | ||
| 124 : | if ($N->norm == 0); | ||
| 125 : | $plane->{d} = $d; $plane->{N} = $N; $plane->{implicit} = $type; | ||
| 126 : | $plane->{isValue} = $plane->{isFormula} = 1; | ||
| 127 : | return bless $plane, $class; | ||
| 128 : | } | ||
| 129 : | |||
| 130 : | # | ||
| 131 : | # We already know the vectors are none zero, so check | ||
| 132 : | # if the equations are multiples of each other. | ||
| 133 : | # | ||
| 134 : | sub compare { | ||
| 135 : | my ($l,$r,$flag) = @_; | ||
| 136 : | $r = ImplicitPlane->new($r); | ||
| 137 : | if ($flag) {my $tmp = $l; $l = $r; $r = $tmp} | ||
| 138 : | my ($lN,$ld) = ($l->{N},$l->{d}); | ||
| 139 : | my ($rN,$rd) = ($r->{N},$r->{d}); | ||
| 140 : | return $rd*$lN <=> $ld*$rN; | ||
| 141 : | } | ||
| 142 : | |||
| 143 : | sub cmp_class {'an Implicit '.(shift->{implicit})}; | ||
| 144 : | |||
| 145 : | sub cmp_defaults{( | ||
| 146 : | shift->SUPER::cmp_defaults, | ||
| 147 : | ignoreInfinity => 0, # report infinity as an error | ||
| 148 : | )} | ||
| 149 : | |||
| 150 : | # | ||
| 151 : | # Only compare two equalities | ||
| 152 : | # | ||
| 153 : | sub typeMatch { | ||
| 154 : | my $self = shift; my $other = shift; my $ans = shift; | ||
| 155 : | return ref($other) && $self->type eq $other->type; | ||
| 156 : | } | ||
| 157 : | |||
| 158 : | 1; |
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |