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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5551 - (download) (as text) (annotate)
Tue Oct 2 20:48:05 2007 UTC (12 years, 2 months ago) by sh002i
File size: 23891 byte(s)
improved formatting for docs -- these were in pod sections but were all
formatted as verbatim sections, and i moved them into normal paragraphs,
lists, etc. should make things more readable from the web.

    1 =head1 NAME
    2 
    3 Context("Inequalities"), Context("Inequalities-Only") - Provides contexts that
    4 allow intervals to be specified as inequalities.
    5 
    6 =head1 DESCRIPTION
    7 
    8 Implements contexts that provides for inequalities that produce
    9 the cooresponding Interval, Set or Union MathObjects.  There are
   10 two such contexts:  Context("Inequalities"), in which both
   11 intervals and inequalities are defined, and Context("Inequalities-Only"),
   12 which allows only inequalities as a means of producing intervals.
   13 
   14 =head1 USAGE
   15 
   16     loadMacros("contextInequalities.pl");
   17 
   18     Context("Inequalities");
   19     $S1 = Compute("1 < x <= 4");
   20     $S2 = Inequality("(1,4]");     # force interval to be inequality
   21 
   22     Context("Inequalities-Only");
   23     $S1 = Compute("1 < x <= 4");
   24     $S2 = Inequality("(1,4]");     # generates an error
   25 
   26     $S3 = Compute("x < -2 or x > 2");  # forms a Union
   27     $S4 = Compute("x = 1");            # forms a Set
   28 
   29 You can set the "noneWord" flag to specify the string to
   30 use when the inequalities specify the empty set.  By default,
   31 it is "NONE", but you can change it to other strings.  Be sure
   32 that you use a string that is defined in the Context, however,
   33 if you expect the student to be able to enter it.  For example
   34 
   35     Context("Inequalities");
   36     Context()->constants->add(EmptySet => Set());
   37     Context()->flags->set(noneWord=>"EmptySet");
   38 
   39 creates an empty set as a named constant and uses that name.
   40 
   41 Inequalities and interval notation both can coexist side by
   42 side, but you may wish to convert from one to the other.
   43 Use Inequality() to convert from an Interval, Set or Union
   44 to an Inequality, and use Interval(), Set(), or Union() to
   45 convert from an Inequality object to one in interval notation.
   46 For example:
   47 
   48     $I0 = Compute("(1,2]");            # the interval (1,2]
   49     $I1 = Inequality($I);              # the inequality 1 < x <= 2
   50 
   51     $I0 = Compute("1 < x <= 2");       # the inequality 1 < x <= 2
   52     $I1 = Interval($I0);               # the interval (1,2]
   53 
   54 Note that ineqaulities and inervals can be compared and combined
   55 regardless of the format, so $I0 == $I1 is true in either example
   56 above.
   57 
   58 =cut
   59 
   60 loadMacros("MathObjects.pl");
   61 
   62 sub _contextInequalities_init {Inequalities::Init()}
   63 
   64 package Inequalities;
   65 
   66 #
   67 #  Sets up the two inequality contexts
   68 #
   69 sub Init {
   70   my $context = $main::context{Inequalities} = Parser::Context->getCopy("Interval");
   71   $context->{name} = "Inequalities";
   72   $context->operators->add(
   73      '<'  => {precedence => .5, associativity => 'left', type => 'bin', string => ' < ',
   74               class => 'Inequalities::BOP::inequality', eval => 'evalLessThan', combine => 1},
   75 
   76      '>'  => {precedence => .5, associativity => 'left', type => 'bin', string => ' > ',
   77               class => 'Inequalities::BOP::inequality', eval => 'evalGreaterThan', combine => 1},
   78 
   79      '<=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' <= ', TeX => '\le ',
   80               class => 'Inequalities::BOP::inequality', eval => 'evalLessThanOrEqualTo', combine => 1},
   81 
   82      '>=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' >= ', TeX => '\ge ',
   83               class => 'Inequalities::BOP::inequality', eval => 'evalGreaterThanOrEqualTo', combine => 1},
   84 
   85      '='  => {precedence => .5, associativity => 'left', type => 'bin', string => ' = ',
   86               class => 'Inequalities::BOP::inequality', eval => 'evalEqualTo'},
   87 
   88      '!=' => {precedence => .5, associativity => 'left', type => 'bin', string => ' != ', TeX => '\ne ',
   89               class => 'Inequalities::BOP::inequality', eval => 'evalNotEqualTo'},
   90 
   91      'and' => {precedence => .45, associateivity => 'left', type => 'bin', string => " and ",
   92          TeX => '\hbox{ and }', class => 'Inequalities::BOP::and'},
   93 
   94      'or' => {precedence => .4, associateivity => 'left', type => 'bin', string => " or ",
   95         TeX => '\hbox{ or }', class => 'Inequalities::BOP::or'},
   96   );
   97   $context->operators->set(
   98      '+' => {class => "Inequalities::BOP::add"},
   99      '-' => {class => "Inequalities::BOP::subtract"},
  100   );
  101   $context->parens->set("(" => {type => "List", formIntervla => ']'});  # trap these later
  102   $context->parens->set("[" => {type => "List", formIntervla => ')'});  # trap these later
  103   $context->strings->remove("NONE");
  104   $context->constants->add(NONE=>Value::Set->new());
  105   $context->flags->set(noneWord => 'NONE');
  106   $context->{parser}{Variable} = "Inequalities::Variable";
  107   $context->{value}{'Interval()'} = "Inequalities::MakeInterval";
  108   $context->{value}{Inequality} = "Inequalities::Inequality";
  109   $context->{value}{InequalityInterval} = "Inequalities::Interval";
  110   $context->{value}{InequalityUnion} = "Inequalities::Union";
  111   $context->{value}{InequalitySet} = "Inequalities::Set";
  112   $context->{value}{List} = "Inequalities::List";
  113   $context->{precedence}{Inequality} = $context->{precedence}{special};
  114   $context->lists->set(List => {class => 'Inequalities::List::List'});
  115 
  116   #
  117   #  Disable interval notation in "Inequalities-Only" context
  118   #
  119   $context = $main::context{"Inequalities-Only"} = $context->copy;
  120   $context->lists->set(
  121     Interval => {class => 'Inequalities::List::notAllowed'},
  122     Set      => {class => 'Inequalities::List::notAllowed'},
  123     Union    => {class => 'Inequalities::List::notAllowed'},
  124   );
  125   $context->operators->set('U' => {class => 'Inequalities::BOP::union'});
  126   $context->constants->remove('R');
  127 
  128   #
  129   #  Define the Inequality() constructor
  130   #
  131   main::PG_restricted_eval('sub Inequality {Value->Package("Inequality")->new(@_)}');
  132 
  133   return;
  134 }
  135 
  136 
  137 ##################################################
  138 #
  139 #  General BOP that handles the inequalities.
  140 #  The difference comes in the _eval() method,
  141 #  which tells what each computes.
  142 #
  143 package Inequalities::BOP::inequality;
  144 our @ISA = ("Parser::BOP");
  145 
  146 #
  147 #  Check that the inequality is formed between a variable and a number,
  148 #  or between a number and another compatible inequality.  Otherwise,
  149 #  give an error.
  150 #
  151 #  varPos and numPos tell which of lop or rop is the variable and which
  152 #  the number.  varName is the variable involved in the inequality.
  153 #
  154 sub _check {
  155   my $self = shift;
  156   $self->{type} = $Value::Type{interval};
  157   $self->{isInequality} = 1;
  158   ($self->{varPos},$self->{numPos}) =
  159     ($self->{lop}->class eq 'Variable' || $self->{lop}{isInequality} ? ('lop','rop') : ('rop','lop'));
  160   my ($v,$n) = ($self->{$self->{varPos}},$self->{$self->{numPos}});
  161   if (($n->isNumber || $n->{isInfinite}) && $n->{isConstant}) {
  162     if ($v->class eq 'Variable') {
  163       $self->{varName} = $v->{name};
  164       delete $self->{equation}{variables}{$v->{name}} if $v->{isNew};
  165       $self->{$self->{varPos}} = Inequalities::DummyVariable->new($self->{equation},$v->{name},$v->{ref});
  166       return;
  167     }
  168     if ($self->{def}{combine} && $v->{isInequality}) {
  169       my $bop = substr($self->{bop},0,1); my $ebop = $bop."=";
  170       if (($v->{bop} eq $bop || $v->{bop} eq $ebop) && $v->{varPos} eq $self->{numPos}) {
  171   $self->{varName} = $v->{varName};
  172   return;
  173       }
  174     }
  175   }
  176   $self->Error("'%s' should have a variable on one side and a number on the other",$self->{bop})
  177     unless $v->{isInequality} && $v->{varPos} eq $self->{numPos};
  178   $self->Error("'%s' can't be combined with '%s'",$v->{bop},$self->{bop});
  179 }
  180 
  181 #
  182 #  Generate the interval for the given type of inequality.
  183 #  If it is a combined inequality, intersect with the other
  184 #  one to get the final set.
  185 #
  186 sub _eval {
  187   my $self = shift; my ($a,$b) = @_;
  188   my $eval = $self->{def}{eval};
  189   my $I = $self->Package("Inequality")->new($self->context,$self->$eval(@_),$self->{varName});
  190   return $I->intersect($a) if Value::isValue($a) && $a->type eq 'Interval';
  191   return $I->intersect($b) if Value::isValue($b) && $b->type eq 'Interval';
  192   return $I;
  193 }
  194 
  195 sub evalLessThan {
  196   my ($self,$a,$b) = @_; my $context = $self->context;
  197   my $I = Value::Infinity->new($context);
  198   return $self->Package("Interval")->new($context,'(',-$I,$b,')') if $self->{varPos} eq 'lop';
  199   return $self->Package("Interval")->new($context,'(',$a,$I,')');
  200 }
  201 
  202 sub evalGreaterThan {
  203   my ($self,$a,$b) = @_; my $context = $self->context;
  204   my $I = Value::Infinity->new;
  205   return $self->Package("Interval")->new($context,'(',$b,$I,')') if $self->{varPos} eq 'lop';
  206   return $self->Package("Interval")->new($context,'(',-$I,$a,')');
  207 }
  208 
  209 sub evalLessThanOrEqualTo {
  210   my ($self,$a,$b) = @_; my $context = $self->context;
  211   my $I = Value::Infinity->new;
  212   return $self->Package("Interval")->new($context,'(',-$I,$b,']') if $self->{varPos} eq 'lop';
  213   return $self->Package("Interval")->new($context,'[',$a,$I,')');
  214 }
  215 
  216 sub evalGreaterThanOrEqualTo {
  217   my ($self,$a,$b) = @_; my $context = $self->context;
  218   my $I = Value::Infinity->new;
  219   return $self->Package("Interval")->new($context,'[',$b,$I,')') if $self->{varPos} eq 'lop';
  220   return $self->Package("Interval")->new($context,'(',-$I,$a,']');
  221 }
  222 
  223 sub evalEqualTo {
  224   my ($self,$a,$b) = @_; my $context = $self->context;
  225   my $x = ($self->{varPos} eq 'lop' ? $b : $a);
  226   return $self->Package("Set")->new($context,$x);
  227 }
  228 
  229 sub evalNotEqualTo {
  230   my ($self,$a,$b) = @_; my $context = $self->context;
  231   my $x = ($self->{varPos} eq 'lop' ? $b : $a);
  232   my $I = Value::Infinity->new;
  233   return $self->Package("Union")->new($context,
  234             $self->Package("Interval")->new($context,'(',-$I,$x,')'),
  235             $self->Package("Interval")->new($context,'(',$x,$I,')')
  236          );
  237 }
  238 
  239 #
  240 #  Inequalities have dummy variables that are not really
  241 #  variables of a formula.
  242 
  243 sub getVariables {{}}
  244 
  245 #
  246 #  Avoid unwanted parentheses from the standard routines.
  247 #
  248 sub string {
  249   my ($self,$precedence) = @_;
  250   my $string; my $bop = $self->{def};
  251 
  252   $string = $self->{lop}->string($bop->{precedence}).
  253             $bop->{string}.
  254             $self->{rop}->string($bop->{precedence});
  255 
  256   return $string;
  257 }
  258 
  259 sub TeX {
  260   my ($self,$precedence) = @_;
  261   my $TeX; my $bop = $self->{def};
  262 
  263   $TeX = $self->{lop}->TeX($bop->{precedence}).
  264          (defined($bop->{TeX}) ? $bop->{TeX} : $bop->{string}) .
  265          $self->{rop}->TeX($bop->{precedence});
  266 
  267   return $TeX;
  268 }
  269 
  270 ##################################################
  271 #
  272 #  Implements the "and" operation as set intersection
  273 #
  274 package Inequalities::BOP::and;
  275 our @ISA = ("Parser::BOP");
  276 
  277 sub _check {
  278   my $self = shift;
  279   $self->Error("The operands of '%s' must be inequalities",$self->{bop})
  280     unless $self->{lop}{isInequality} && $self->{rop}{isInequality};
  281   $self->Error("Inequalities combined by '%s' must both use the same variable",$self->{bop})
  282     unless $self->{lop}{varName} eq $self->{rop}{varName};
  283   $self->{type} = Value::Type("Interval",2);
  284   $self->{varName} = $self->{lop}{varName};
  285   $self->{isInequality} = 1;
  286 }
  287 
  288 sub _eval {$_[1]->intersect($_[2])}
  289 
  290 ##################################################
  291 #
  292 #  Implements the "or" operation as set union
  293 #
  294 package Inequalities::BOP::or;
  295 our @ISA = ("Parser::BOP");
  296 
  297 sub _check {
  298   my $self = shift;
  299   $self->Error("The operands of '%s' must be inequalities",$self->{bop})
  300     unless $self->{lop}{isInequality} && $self->{rop}{isInequality};
  301   $self->Error("Inequalities combined by '%s' must both use the same variable",$self->{bop})
  302     unless $self->{lop}{varName} eq $self->{rop}{varName};
  303   $self->{type} = Value::Type("Interval",2);
  304   $self->{varName} = $self->{lop}{varName};
  305   $self->{isInequality} = 1;
  306 }
  307 
  308 sub _eval {$_[1] + $_[2]}
  309 
  310 ##################################################
  311 #
  312 #  Subclass of Parser::Variable that records whether
  313 #  this variable has already been seen in the formula
  314 #  (so that it can be removed from the formula's
  315 #  variable list when used in an inequality.)
  316 #
  317 package Inequalities::Variable;
  318 our @ISA = ("Parser::Variable");
  319 
  320 sub new {
  321   my $self = shift; my $equation = shift; my $name = shift;
  322   my $isNew = !defined $equation->{variables}{$name};
  323   my $n = $self->SUPER::new($equation,$name,@_);
  324   $n->{isNew} = $isNew;
  325   return $n;
  326 }
  327 
  328 ##################################################
  329 #
  330 #  A special class usd for the variables in
  331 #  inequalities, since they are not really
  332 #  variables for the formula.  (They don't need
  333 #  to be subtituted or given values when the
  334 #  formula is evaluated, and so on.)  These are
  335 #  really just placeholders, here.
  336 #
  337 package Inequalities::DummyVariable;
  338 our @ISA = ("Parser::Item");
  339 
  340 sub new {
  341   my $self = shift; my $class = ref($self) || $self;
  342   my ($equation,$name,$ref) = @_;
  343   my $def = $equation->{context}{variables}{$name};
  344   bless {name => $name, ref => $ref, def => $def, equation => $equation}, $class;
  345 }
  346 
  347 sub eval {shift};
  348 
  349 sub string {(shift)->{name}}
  350 
  351 sub TeX {
  352   my $self = shift; my $name = $self->{name};
  353   return $self->{def}{TeX} if defined $self->{def}{TeX};
  354   $name = $1.'_{'.$2.'}' if ($name =~ m/^([^_]+)_?(\d+)$/);
  355   return $name;
  356 }
  357 
  358 sub perl {
  359   my $self = shift;
  360   return $self->{def}{perl} if defined $self->{def}{perl};
  361   return '$'.$self->{name};
  362 }
  363 
  364 ##################################################
  365 #
  366 #  Give an error when U is used.
  367 #
  368 package Inequalities::BOP::union;
  369 our @ISA = ("Parser::BOP::union");
  370 
  371 sub _check {
  372   my $self = shift;
  373   $self->Error("You can't take unions of inequalities")
  374     if $self->{lop}{isInequality} || $self->{rop}{isInequality};
  375   $self->SUPER::_check(@_);
  376   $self->Error("Unions are not allowed in this context");
  377 }
  378 
  379 ##################################################
  380 #
  381 #  Don't allow sums and differences of inequalities
  382 #
  383 package Inequalities::BOP::add;
  384 our @ISA = ("Parser::BOP::add");
  385 
  386 sub _check {
  387   my $self = shift;
  388   $self->SUPER::_check(@_);
  389   $self->Error("Can't add inequalities (do you mean to use 'or'?)")
  390     if $self->{lop}{isInequality} || $self->{rop}{isInequality};
  391 }
  392 
  393 ##################################################
  394 #
  395 #  Don't allow sums and differences of inequalities
  396 #
  397 package Inequalities::BOP::subtract;
  398 our @ISA = ("Parser::BOP::subtract");
  399 
  400 sub _check {
  401   my $self = shift;
  402   $self->SUPER::_check(@_);
  403   $self->Error("Can't subtract inequalities")
  404     if $self->{lop}{isInequality} || $self->{rop}{isInequality};
  405 }
  406 
  407 ##################################################
  408 #
  409 #  For the Inequalities-Only context, report
  410 #  an error for Intervals, Sets or Union notation.
  411 #
  412 package Inequalities::List::notAllowed;
  413 our @ISA = ("Parser::List::List");
  414 
  415 sub _check {(shift)->Error("You are not allowed to use intervals or sets in this context")}
  416 
  417 
  418 ##################################################
  419 ##################################################
  420 #
  421 #  Subclasses of the Interval, Set, and Union classes
  422 #  that stringify as inequalities
  423 #
  424 
  425 #
  426 #  Some common routines to all three classes
  427 #
  428 package Inequalities::common;
  429 
  430 #
  431 #  Turn the object back into its usual Value version
  432 #
  433 sub demote {
  434   my $self = shift;  my $context = $self->context;
  435   my $other = shift; $other = $self unless defined $other;
  436   return $other unless Value::classMatch($other,"Inequality");
  437   $context->Package($other->type)->make($context,$other->makeData);
  438 }
  439 
  440 #
  441 #  Needed to get Interval data in the right order for make(),
  442 #  and demote all the items in a Union
  443 #
  444 sub makeData {(shift)->value}
  445 
  446 #
  447 #  Recursively mark Intervals and Sets in a Union as Inequalities
  448 #
  449 sub updateParts {}
  450 
  451 #
  452 #  Demote the operands to normal Value objects and
  453 #  perform the action, then remake the result into
  454 #  an Inequality again.
  455 #
  456 sub apply {
  457   my $self = shift; my $context = $self->context;
  458   my $method = shift;  my $other = shift;
  459   $context->Package("Inequality")->new($context,
  460     $self->demote->$method($self->demote($other),@_),
  461     $self->{varName});
  462 }
  463 
  464 sub add {(shift)->apply("add",@_)}
  465 sub sub {(shift)->apply("sub",@_)}
  466 sub reduce {(shift)->apply("reduce",@_)}
  467 sub intersect {(shift)->apply("intersect",@_)}
  468 
  469 #
  470 #  The name to use for error messages in answer checkers
  471 #
  472 sub class {"Inequality"}
  473 sub cmp_class {"an Inequality"}
  474 sub showClass {"an Inequality"}
  475 sub typeRef {
  476   my $self = shift;
  477   return Value::Type($self->type, $self->length, $Value::Type{number});
  478 }
  479 
  480 #
  481 #  Get the precedence based on the type rather than the class.
  482 #
  483 sub precedence {
  484   my $self = shift; my $precedence = $self->context->{precedence};
  485   return $precedence->{$self->type}-$precedence->{Interval}+$precedence->{$self->class};
  486 }
  487 
  488 #
  489 #  Produce better error messages for inequalities
  490 #
  491 sub cmp_checkUnionReduce {
  492   my $self = shift; my $student = shift; my $ans = shift; my $nth = shift || '';
  493   if (Value::classMatch($student,"Inequality")) {
  494     return unless $ans->{studentsMustReduceUnions} &&
  495                   $ans->{showUnionReduceWarnings} &&
  496                   !$ans->{isPreview} && !Value::isFormula($student);
  497     my ($result,$error) = $student->isReduced;
  498     return unless $error;
  499     return {
  500       "overlaps" => "Your$nth answer contains overlapping inequalities",
  501       "overlaps in sets" => "Your$nth answer contains equalities that are already included elsewhere",
  502       "uncombined intervals" => "Your$nth answer can be simplified by combining some inequalities",
  503       #  shouldn't get the following ones from inequalities
  504       "uncombined sets" => "",
  505       "repeated elements in set" => "",
  506       "repeated elements" => "",
  507     }->{$error};
  508   } else {
  509     return unless Value::can($student,"isReduced");
  510     return Value::cmp_checkUnionReduce($self,$student,$ans,$nth,@_)
  511   }
  512 }
  513 
  514 
  515 ##################################################
  516 
  517 package Inequalities::Interval;
  518 our @ISA = ("Inequalities::common", "Value::Interval");
  519 
  520 sub type {"Interval"}
  521 
  522 sub string {
  523   my $self = shift;
  524   my ($a,$b,$open,$close) = $self->value;
  525   my $x = $self->{varName} || ($self->context->variables->names)[0];
  526   $x = $context->{variables}{$x}{string} if defined $context->{variables}{$x}{string};
  527   my $left  = ($open  eq '(' ? ' < ' : ' <= ');
  528   my $right = ($close eq ')' ? ' < ' : ' <= ');
  529   my $inequality = "";
  530   $inequality .= $a->string.$left unless $self->{leftInfinite};
  531   $inequality .= $x;
  532   $inequality .= $right.$b->string unless $self->{rightInfinite};
  533   $inequality = "-infinity < $x < infinity" if $inequality eq $x;
  534   return $inequality;
  535 }
  536 
  537 sub TeX {
  538   my $self = shift;
  539   my ($a,$b,$open,$close) = $self->value;
  540   my $context = $self->context;
  541   my $x = $self->{varName} || ($context->variables->names)[0];
  542   $x = $context->{variables}{$x}{TeX} if defined $context->{variables}{$x}{TeX};
  543   $x =~ s/^([^_]+)_?(\d+)$/$1_{$2}/;
  544   my $left  = ($open  eq '(' ? ' < ' : ' \le ');
  545   my $right = ($close eq ')' ? ' < ' : ' \le ');
  546   my $inequality = "";
  547   $inequality .= $a->string.$left unless $self->{leftInfinite};
  548   $inequality .= $x;
  549   $inequality .= $right.$b->string unless $self->{rightInfinite};
  550   $inequality = "-\\infty < $x < \\infty " if $inequality eq $x;
  551   return $inequality;
  552 }
  553 
  554 ##################################################
  555 
  556 package Inequalities::Union;
  557 our @ISA = ("Inequalities::common", "Value::Union");
  558 
  559 sub type {"Union"}
  560 
  561 #
  562 #  Mark all the parts of the union as inequalities
  563 #
  564 sub updateParts {
  565   my $self = shift;
  566   foreach my $I (@{$self->{data}}) {
  567     $I->{varName} = $self->{varName};
  568     $I->{reduceSets} = $I->{"is".$I->type} = 1;
  569     bless $I, $self->Package("Inequality".$I->type);
  570     $I->updateParts;
  571   }
  572 }
  573 
  574 #
  575 #  Update the intervals and sets when a new union is made
  576 #
  577 sub make {
  578   my $self = (shift)->SUPER::make(@_);
  579   $self->updateParts;
  580   return $self;
  581 }
  582 
  583 #
  584 #  Demote all the items in the union
  585 #
  586 sub makeData {
  587   my $self = shift; my @U = ();
  588   foreach my $I (@{$self->{data}}) {push(@U,$I->demote)}
  589   return @U;
  590 }
  591 
  592 sub string {
  593   my $self = shift;
  594   my $equation = shift; shift; shift; my $prec = shift;
  595   my $op = ($equation->{context} || $self->context)->{operators}{'or'};
  596   my @intervals = ();
  597   foreach my $x (@{$self->data}) {
  598     $x->{format} = $self->{format} if defined $self->{format};
  599     push(@intervals,$x->string($equation))
  600   }
  601   my $string = join($op->{string} || ' or ',@intervals);
  602   $string = '('.$string.')' if defined($prec) && $prec > ($op->{precedence} || 1.5);
  603   return $string;
  604 }
  605 
  606 sub TeX {
  607   my $self = shift;
  608   my $equation = shift; shift; shift; my $prec = shift;
  609   my $op = ($equation->{context} || $self->context)->{operators}{'or'};
  610   my @intervals = ();
  611   foreach my $x (@{$self->data}) {push(@intervals,$x->TeX($equation))}
  612   my $TeX = join($op->{TeX} || $op->{string} || '\hbox{ or }',@intervals);
  613   $TeX = '\left('.$TeX.'\right)' if defined($prec) && $prec > ($op->{precedence} || 1.5);
  614   return $TeX;
  615 }
  616 
  617 ##################################################
  618 
  619 package Inequalities::Set;
  620 our @ISA = ("Inequalities::common", "Value::Set");
  621 
  622 sub type {"Set"}
  623 
  624 sub string {
  625   my $self = shift;  my $equation = shift;
  626   my $x = $self->{varName} || ($self->context->variables->names)[0];
  627   $x = $context->{variables}{$x}{string} if defined $context->{variables}{$x}{string};
  628   my @coords = ();
  629   foreach my $a (@{$self->data}) {
  630     if (Value::isValue($a)) {
  631       $a->{format} = $self->{format} if defined $self->{format};
  632       push(@coords,$x.' = '.$a->string($equation));
  633     } else {
  634       push(@coords,$x.' = '.$a);
  635     }
  636   }
  637   return $self->getFlag('noneWord') unless scalar(@coords);
  638   return join(" or ",@coords);
  639 }
  640 
  641 sub TeX {
  642   my $self = shift;  my $equation = shift;
  643   my $x = $self->{varName} || ($self->context->variables->names)[0];
  644   $x = $context->{variables}{$x}{TeX} if defined $context->{variables}{$x}{TeX};
  645   $x =~ s/^([^_]+)_?(\d+)$/$1_{$2}/;
  646   my @coords = ();
  647   foreach my $a (@{$self->data}) {
  648     if (Value::isValue($a)) {
  649       $a->{format} = $self->{format} if defined $self->{format};
  650       push(@coords,$x.' = '.$a->TeX($equation));
  651     } else {
  652       push(@coords,$x.' = '.$a);
  653     }
  654   }
  655   return '\hbox{'.$self->getFlag('noneWord').'}' unless scalar(@coords);
  656   return join('\hbox{ or }',@coords);
  657 }
  658 
  659 ##################################################
  660 #
  661 #  A class for making inequalities by hand
  662 #
  663 package Inequalities::Inequality;
  664 our @ISA = ('Value');
  665 
  666 sub new {
  667   my $self = shift; my $class = ref($self) || $self;
  668   my $context = (Value::isContext($_[0]) ? shift : $self->context);
  669   my $S = shift; my $x = shift;
  670   $S = Value::makeValue($S,context=>$context);
  671   if (Value::classMatch($S,"Inequality")) {
  672     if (defined($x)) {$S->{varName} = $x; $S->updateParts}
  673     return $S;
  674   }
  675   $x = ($context->variables->names)[0] unless $x;
  676   $S = bless $S->inContext($context), $context->Package("Inequality".$S->type);
  677   $S->{varName} = $x; $S->{reduceSets} = $S->{"is".$S->Type} = 1;
  678   $S->updateParts;
  679   return $S;
  680 }
  681 
  682 ##################################################
  683 #
  684 #  Allow Interval() to coerce types to Value::Interval
  685 #
  686 package Inequalities::MakeInterval;
  687 our @ISA = ("Value::Interval");
  688 
  689 sub new {
  690   my $self = shift;
  691   $self = $self->SUPER::new(@_);
  692   $self = $self->demote if $self->classMatch("Inequality");
  693   return $self;
  694 }
  695 
  696 ##################################################
  697 #
  698 #  Mark this as a list of inequalities (if it is)
  699 #
  700 package Inequalities::List;
  701 our @ISA = ("Value::List");
  702 
  703 sub new {
  704   my $self = (shift)->SUPER::new(@_);
  705   return $self unless $self->{type} =~ m/^(unknown|Interval|Set|Union)$/;
  706   foreach my $x (@{$self->{data}}) {return $self unless Value::classMatch($x,'Inequality')}
  707   $self->{type} = 'Inequality';
  708   return $self;
  709 }
  710 
  711 package Inequalities::List::List;
  712 our @ISA = ("Parser::List::List");
  713 
  714 sub _check {
  715   my $self = shift; $self->SUPER::_check(@_);
  716   if ($self->canBeInUnion) {
  717     #
  718     #  Convert lists that look like intervals into intervals
  719     #  and then check if they are OK.
  720     #
  721     bless $self, $self->context->{lists}{Interval}{class};
  722     $self->{type} = $Value::Type{interval};
  723     $self->{parens} = $self->context->{parens}{interval};
  724     $self->_check;
  725   } else {
  726     my $entryType = $self->typeRef->{entryType};
  727     return unless $entryType->{name} =~ m/^(unknown|Interval|Set|Union)$/;
  728     foreach my $x (@{$self->{coords}}) {return unless $x->{isInequality}};
  729     $entryType->{name} = "Inequality";
  730   }
  731 }
  732 
  733 ##################################################
  734 
  735 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9