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

View of /trunk/pg/macros/parserImplicitPlane.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5556 - (download) (as text) (annotate)
Thu Oct 4 16:40:49 2007 UTC (12 years, 3 months ago) by sh002i
File size: 7482 byte(s)
added standard copyright/license header

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork2/lib/WeBWorK.pm,v 1.100 2007/08/13 22:59:53 sh002i Exp $
    5 #
    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 =head1 NAME
   18 
   19 parserImplicitPlane.pl - Implement implicit planes.
   20 
   21 =head1 DESCRIPTION
   22 
   23 This is a Parser class that implements implicit planes as
   24 a subclass of the Formula class.  The standard ->cmp routine
   25 will work for this, provided we define the compare() function
   26 needed by the overloaded ==.  We assign the special precedence
   27 so that overloaded operations will be promoted to the ones below.
   28 
   29 Use ImplicitPlane(point,vector), ImplicitPlane(point,number) or
   30 ImplicitPlane(formula) to create an ImplicitPlane object.
   31 The first form uses the point as a point on the plane and the
   32 vector as the normal for the plane.  The second form uses the point
   33 as the coefficients of the variables and the number as the value
   34 that the formula must equal.  The third form uses the formula
   35 directly.
   36 
   37 The number of variables in the Context determines the dimension of
   38 the "plane" being defined.  If there are only two, the formula
   39 produces an implicit line, but if there are four variables, it will
   40 be a hyperplane in four-space.  You can specify the variables you
   41 want to use by supplying an additional parameter, which is a
   42 reference to an array of variable names.
   43 
   44 Usage examples:
   45 
   46   $P = ImplicitPlane(Point(1,0,2),Vector(-1,1,3)); #  -x+y+3z = 5
   47   $P = ImplicitPlane([1,0,2],[-1,1,3]);            #  -x+y+3z = 5
   48   $P = ImplicitPlane([1,0,2],4);                   #  x+2z = 4
   49   $P = ImplicitPlane("x+2y-z=5");
   50 
   51   Context()->variables->are(x=>'Real',y=>'Real',z=>'Real',w=>'Real');
   52   $P = ImplicitPlane([1,0,2,-1],10);               # w+2y-z = 10 (alphabetical order)
   53   $P = ImplicitPlane([3,-1,2,4],5,['x','y','z','w']);  # 3x-y+2z+4w = 5
   54   $P = ImplicitPlane([3,-1,2],5,['y','z','w']);  # 3y-z+2w = 5
   55 
   56 Then use
   57 
   58   ANS($P->cmp);
   59 
   60 to get the answer checker for $P.
   61 
   62 =cut
   63 
   64 loadMacros('MathObjects.pl');
   65 
   66 sub _parserImplicitPlane_init {ImplicitPlane::Init()}; # don't reload this file
   67 
   68 ##################################################
   69 #
   70 #  Define the subclass of Formula
   71 #
   72 package ImplicitPlane;
   73 our @ISA = qw(Value::Formula);
   74 
   75 sub Init {
   76   my $context = $main::context{ImplicitPlane} = Parser::Context->getCopy("Vector");
   77   $context->{name} = "ImplicitPlane";
   78   $context->{precedence}{ImplicitPlane} = $context->{precedence}{special};
   79   #$context->{value}{Equality} = "ImplicitPlane::equality";
   80   Parser::BOP::equality->Allow($context);
   81   $context->operators->set('=' => {class => 'ImplicitPlane::equality'});
   82 
   83   main::Context("ImplicitPlane");  ### FIXME:  probably should require authors to set this explicitly
   84 
   85   main::PG_restricted_eval('sub ImplicitPlane {ImplicitPlane->new(@_)}');
   86 }
   87 
   88 sub new {
   89   my $self = shift; my $class = ref($self) || $self;
   90   my $context = (Value::isContext($_[0]) ? shift : $self->context);
   91   return shift if scalar(@_) == 1 && ref($_[0]) eq 'ImplicitPlane';
   92   $_[0] = $context->Package("Point")->new($context,$_[0]) if ref($_[0]) eq 'ARRAY';
   93   $_[1] = $context->Package("Vector")->new($context,$_[1]) if ref($_[1]) eq 'ARRAY';
   94 
   95   my ($p,$N,$plane,$vars,$d,$type); $type = 'plane';
   96   if (scalar(@_) >= 2 && Value::classMatch($_[0],'Point','Vector') &&
   97       Value::classMatch($_[1],'Vector') || Value::isRealNumber($_[1])) {
   98     #
   99     # Make a plane from a point and a vector,
  100     # or from a list of coefficients and the constant
  101     #
  102     $p = shift; $N = shift;
  103     if (Value::classMatch($N,'Vector')) {
  104       $d = $p.$N;
  105     } else {
  106       $d = $context->Package("Real")->make($context,$N);
  107       $N = $context->Package("Vector")->new($context,$p);
  108     }
  109     $vars = shift || [$context->variables->names];
  110     $vars = [$vars] unless ref($vars) eq 'ARRAY';
  111     $type = 'line' if scalar(@{$vars}) == 2;
  112     my @terms = (); my $i = 0;
  113     foreach my $x (@{$vars}) {push @terms, $N->{data}[$i++]->string.$x}
  114     $plane = $context->Package("Formula")->new(join(' + ',@terms).' = '.$d->string)->reduce(@_);
  115   } else {
  116     $formula = $context->Package("Formula");
  117     #
  118     #  Determine the normal vector and d value from the equation
  119     #
  120     $plane = shift;
  121     $plane = $formula->new($context,$plane) unless Value::isValue($plane);
  122     $vars = shift || [$context->variables->names];
  123     $vars = [$vars] unless ref($vars) eq 'ARRAY';
  124     $type = 'line' if scalar(@{$vars}) == 2;
  125     Value::Error("Your formula doesn't look like an implicit %s",$type)
  126       unless $plane->type eq 'Equality';
  127     #
  128     #  Find the coefficients of the formula
  129     #
  130     my $f = ($formula->new($context,$plane->{tree}{lop}) -
  131        $formula->new($context,$plane->{tree}{rop}))->reduce;
  132     my $F = $f->perlFunction(undef,[@{$vars}]);
  133     my @v = split('','0' x scalar(@{$vars}));
  134     $d = -&$F(@v); my @coeff = (@v);
  135     foreach my $i (0..scalar(@v)-1)
  136       {$v[$i] = 1; $coeff[$i] = &$F(@v) + $d; $v[$i] = 0}
  137     #
  138     #  Check that the student's formula really is what we thought
  139     #
  140     $N = Value::Vector->new([@coeff]);
  141     $plane = ImplicitPlane->new($N,$d,$vars,'-x=-y'=>0,'-x=n'=>0);
  142     Value::Error("Your formula isn't a linear one")
  143       unless ($formula->new($plane->{tree}{lop}) -
  144               $formula->new($plane->{tree}{rop})) == $f;
  145     $plane = $plane->reduce;
  146   }
  147   Value::Error("The equation of a %s must be non-zero somewhere",$type)
  148     if ($N->norm == 0);
  149   $plane->{d} = $d; $plane->{N} = $N; $plane->{implicit} = $type;
  150   return bless $plane, $class;
  151 }
  152 
  153 #
  154 #  We already know the vectors are non-zero, so check
  155 #  if the equations are multiples of each other.
  156 #
  157 sub compare {
  158   my ($self,$l,$r) = Value::checkOpOrder(@_);
  159   $r = new ImplicitPlane($r);# if ref($r) ne ref($self);
  160   my ($lN,$ld) = ($l->{N},$l->{d});
  161   my ($rN,$rd) = ($r->{N},$r->{d});
  162   if ($rd == 0 || $ld == 0) {
  163     return $rd <=> $ld unless $ld == $rd;
  164     return $lN <=> $rN unless (areParallel $lN $rN);
  165     return 0;
  166   }
  167   return $rd*$lN <=> $ld*$rN;
  168 }
  169 
  170 sub cmp_class {'an Implicit '.(shift->{implicit})};
  171 sub showClass {shift->cmp_class};
  172 
  173 sub cmp_defaults{(
  174   Value::Real::cmp_defaults(shift),
  175   ignoreInfinity => 0,    # report infinity as an error
  176 )}
  177 
  178 #
  179 #  Only compare two equalities
  180 #
  181 sub typeMatch {
  182   my $self = shift; my $other = shift; my $ans = shift;
  183   return ref($other) && $other->type eq 'Equality' unless ref($self);
  184   return ref($other) && $self->type eq $other->type;
  185 }
  186 
  187 #
  188 #  We subclass BOP::equality so that we can give a warning about
  189 #  things like 1 = 3
  190 #
  191 package ImplicitPlane::equality;
  192 our @ISA = qw(Parser::BOP::equality);
  193 
  194 sub _check {
  195   my $self = shift;
  196   $self->SUPER::_check;
  197   $self->Error("An implicit equation can't be constant on both sides")
  198     if $self->{lop}{isConstant} && $self->{rop}{isConstant};
  199 }
  200 
  201 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9