[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 5443 - (download) (as text) (annotate)
Wed Aug 29 00:03:27 2007 UTC (12 years, 5 months ago) by dpvc
File size: 23944 byte(s)
Make the TeX output for <= be \le rather than <=

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9