[system] / trunk / pg / macros / contextInequalities.pl Repository: Repository Listing bbplugincoursesdistsnplrochestersystemwww

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

Sat Sep 8 21:44:43 2007 UTC (12 years, 5 months ago) by dpvc
File size: 24105 byte(s)
No longer need to change the order of the data, since
Value::Interval->make() now handles the alternative order.


    1 loadMacros("MathObjects.pl");
2
3 sub _contextInequalities_init {Inequalities::Init()}
4
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  #
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");
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->Error("Inequalities combined by '%s' must both use the same variable",$self->{bop}) 279 unless$self->{lop}{varName} eq $self->{rop}{varName}; 280$self->{type} = Value::Type("Interval",2);
281   $self->{varName} =$self->{lop}{varName};
282   $self->{isInequality} = 1; 283 } 284 285 sub _eval {$_[1]->intersect($_[2])} 286 287 ################################################## 288 # 289 # Implements the "or" operation as set union 290 # 291 package Inequalities::BOP::or; 292 our @ISA = ("Parser::BOP"); 293 294 sub _check { 295 my$self = shift;
296   $self->Error("The operands of '%s' must be inequalities",$self->{bop})
297     unless $self->{lop}{isInequality} &&$self->{rop}{isInequality};
298   $self->Error("Inequalities combined by '%s' must both use the same variable",$self->{bop})
299     unless $self->{lop}{varName} eq$self->{rop}{varName};
300   $self->{type} = Value::Type("Interval",2); 301$self->{varName} = $self->{lop}{varName}; 302$self->{isInequality} = 1;
303 }
304
305 sub _eval {$_[1] +$_[2]}
306
307 ##################################################
308 #
309 #  Subclass of Parser::Variable that records whether
310 #  this variable has already been seen in the formula
311 #  (so that it can be removed from the formula's
312 #  variable list when used in an inequality.)
313 #
314 package Inequalities::Variable;
315 our @ISA = ("Parser::Variable");
316
317 sub new {
318   my $self = shift; my$equation = shift; my $name = shift; 319 my$isNew = !defined $equation->{variables}{$name};
320   my $n =$self->SUPER::new($equation,$name,@_);
321   $n->{isNew} =$isNew;
322   return $n; 323 } 324 325 ################################################## 326 # 327 # A special class usd for the variables in 328 # inequalities, since they are not really 329 # variables for the formula. (They don't need 330 # to be subtituted or given values when the 331 # formula is evaluated, and so on.) These are 332 # really just placeholders, here. 333 # 334 package Inequalities::DummyVariable; 335 our @ISA = ("Parser::Item"); 336 337 sub new { 338 my$self = shift; my $class = ref($self) || $self; 339 my ($equation,$name,$ref) = @_;
340   my $def =$equation->{context}{variables}{$name}; 341 bless {name =>$name, ref => $ref, def =>$def, equation => $equation},$class;
342 }
343
344 sub eval {shift};
345
346 sub string {(shift)->{name}}
347
348 sub TeX {
349   my $self = shift; my$name = $self->{name}; 350 return$self->{def}{TeX} if defined $self->{def}{TeX}; 351$name = $1.'_{'.$2.'}' if ($name =~ m/^([^_]+)_?(\d+)$/);
352   return $name; 353 } 354 355 sub perl { 356 my$self = shift;
357   return $self->{def}{perl} if defined$self->{def}{perl};
358   return '$'.$self->{name};
359 }
360
361 ##################################################
362 #
363 #  Give an error when U is used.
364 #
365 package Inequalities::BOP::union;
366 our @ISA = ("Parser::BOP::union");
367
368 sub _check {
369   my $self = shift; 370$self->Error("You can't take unions of inequalities")
371     if $self->{lop}{isInequality} ||$self->{rop}{isInequality};
372   $self->SUPER::_check(@_); 373$self->Error("Unions are not allowed in this context");
374 }
375
376 ##################################################
377 #
378 #  Don't allow sums and differences of inequalities
379 #
382
383 sub _check {
384   my $self = shift; 385$self->SUPER::_check(@_);
386   $self->Error("Can't add inequalities (do you mean to use 'or'?)") 387 if$self->{lop}{isInequality} || $self->{rop}{isInequality}; 388 } 389 390 ################################################## 391 # 392 # Don't allow sums and differences of inequalities 393 # 394 package Inequalities::BOP::subtract; 395 our @ISA = ("Parser::BOP::subtract"); 396 397 sub _check { 398 my$self = shift;
399   $self->SUPER::_check(@_); 400$self->Error("Can't subtract inequalities")
401     if $self->{lop}{isInequality} ||$self->{rop}{isInequality};
402 }
403
404 ##################################################
405 #
406 #  For the Inequalities-Only context, report
407 #  an error for Intervals, Sets or Union notation.
408 #
409 package Inequalities::List::notAllowed;
410 our @ISA = ("Parser::List::List");
411
412 sub _check {(shift)->Error("You are not allowed to use intervals or sets in this context")}
413
414
415 ##################################################
416 ##################################################
417 #
418 #  Subclasses of the Interval, Set, and Union classes
419 #  that stringify as inequalities
420 #
421
422 #
423 #  Some common routines to all three classes
424 #
425 package Inequalities::common;
426
427 #
428 #  Turn the object back into its usual Value version
429 #
430 sub demote {
431   my $self = shift; my$context = $self->context; 432 my$other = shift; $other =$self unless defined $other; 433 return$other unless Value::classMatch($other,"Inequality"); 434$context->Package($other->type)->make($context,$other->makeData); 435 } 436 437 # 438 # Needed to get Interval data in the right order for make(), 439 # and demote all the items in a Union 440 # 441 sub makeData {(shift)->value} 442 443 # 444 # Recursively mark Intervals and Sets in a Union as Inequalities 445 # 446 sub updateParts {} 447 448 # 449 # Demote the operands to normal Value objects and 450 # perform the action, then remake the result into 451 # an Inequality again. 452 # 453 sub apply { 454 my$self = shift; my $context =$self->context;
455   my $method = shift; my$other = shift;
456   $context->Package("Inequality")->new($context,
457     $self->demote->$method($self->demote($other),@_),
458     $self->{varName}); 459 } 460 461 sub add {(shift)->apply("add",@_)} 462 sub sub {(shift)->apply("sub",@_)} 463 sub reduce {(shift)->apply("reduce",@_)} 464 sub intersect {(shift)->apply("intersect",@_)} 465 466 # 467 # The name to use for error messages in answer checkers 468 # 469 sub class {"Inequality"} 470 sub cmp_class {"an Inequality"} 471 sub showClass {"an Inequality"} 472 sub typeRef { 473 my$self = shift;
474   return Value::Type($self->type,$self->length, $Value::Type{number}); 475 } 476 477 # 478 # Get the precedence based on the type rather than the class. 479 # 480 sub precedence { 481 my$self = shift; my $precedence =$self->context->{precedence};
482   return $precedence->{$self->type}-$precedence->{Interval}+$precedence->{$self->class}; 483 } 484 485 # 486 # Produce better error messages for inequalities 487 # 488 sub cmp_checkUnionReduce { 489 my$self = shift; my $student = shift; my$ans = shift; my $nth = shift || ''; 490 if (Value::classMatch($student,"Inequality")) {
491     return unless $ans->{studentsMustReduceUnions} && 492$ans->{showUnionReduceWarnings} &&
493                   !$ans->{isPreview} && !Value::isFormula($student);
494     my ($result,$error) = $student->isReduced; 495 return unless$error;
496     return {
497       "overlaps" => "Your$nth answer contains overlapping inequalities", 498 "overlaps in sets" => "Your$nth answer contains equalities that are already included elsewhere",
499       "uncombined intervals" => "Your$nth answer can be simplified by combining some inequalities", 500 # shouldn't get the following ones from inequalities 501 "uncombined sets" => "", 502 "repeated elements in set" => "", 503 "repeated elements" => "", 504 }->{$error};
505   } else {
506     return unless Value::can($student,"isReduced"); 507 return Value::cmp_checkUnionReduce($self,$student,$ans,$nth,@_) 508 } 509 } 510 511 512 ################################################## 513 514 package Inequalities::Interval; 515 our @ISA = ("Inequalities::common", "Value::Interval"); 516 517 sub type {"Interval"} 518 519 sub string { 520 my$self = shift;
521   my ($a,$b,$open,$close) = $self->value; 522 my$x = $self->{varName} || ($self->context->variables->names)[0];
523   $x =$context->{variables}{$x}{string} if defined$context->{variables}{$x}{string}; 524 my$left  = ($open eq '(' ? ' < ' : ' <= '); 525 my$right = ($close eq ')' ? ' < ' : ' <= '); 526 my$inequality = "";
527   $inequality .=$a->string.$left unless$self->{leftInfinite};
528   $inequality .=$x;
529   $inequality .=$right.$b->string unless$self->{rightInfinite};
530   $inequality = "-infinity <$x < infinity" if $inequality eq$x;
531   return $inequality; 532 } 533 534 sub TeX { 535 my$self = shift;
536   my ($a,$b,$open,$close) = $self->value; 537 my$context = $self->context; 538 my$x = $self->{varName} || ($context->variables->names)[0];
539   $x =$context->{variables}{$x}{TeX} if defined$context->{variables}{$x}{TeX}; 540$x =~ s/^([^_]+)_?(\d+)$/$1_{$2}/; 541 my$left  = ($open eq '(' ? ' < ' : ' \le '); 542 my$right = ($close eq ')' ? ' < ' : ' \le '); 543 my$inequality = "";
544   $inequality .=$a->string.$left unless$self->{leftInfinite};
545   $inequality .=$x;
546   $inequality .=$right.$b->string unless$self->{rightInfinite};
547   $inequality = "-\\infty <$x < \\infty " if $inequality eq$x;
548   return $inequality; 549 } 550 551 ################################################## 552 553 package Inequalities::Union; 554 our @ISA = ("Inequalities::common", "Value::Union"); 555 556 sub type {"Union"} 557 558 # 559 # Mark all the parts of the union as inequalities 560 # 561 sub updateParts { 562 my$self = shift;
563   foreach my $I (@{$self->{data}}) {
564     $I->{varName} =$self->{varName};
565     $I->{reduceSets} =$I->{"is".$I->type} = 1; 566 bless$I, $self->Package("Inequality".$I->type);
567     $I->updateParts; 568 } 569 } 570 571 # 572 # Update the intervals and sets when a new union is made 573 # 574 sub make { 575 my$self = (shift)->SUPER::make(@_);
576   $self->updateParts; 577 return$self;
578 }
579
580 #
581 #  Demote all the items in the union
582 #
583 sub makeData {
584   my $self = shift; my @U = (); 585 foreach my$I (@{$self->{data}}) {push(@U,$I->demote)}
586   return @U;
587 }
588
589 sub string {
590   my $self = shift; 591 my$equation = shift; shift; shift; my $prec = shift; 592 my$op = ($equation->{context} ||$self->context)->{operators}{'or'};
593   my @intervals = ();
594   foreach my $x (@{$self->data}) {
595     $x->{format} =$self->{format} if defined $self->{format}; 596 push(@intervals,$x->string($equation)) 597 } 598 my$string = join($op->{string} || ' or ',@intervals); 599$string = '('.$string.')' if defined($prec) && $prec > ($op->{precedence} || 1.5);
600   return $string; 601 } 602 603 sub TeX { 604 my$self = shift;
605   my $equation = shift; shift; shift; my$prec = shift;
606   my $op = ($equation->{context} || $self->context)->{operators}{'or'}; 607 my @intervals = (); 608 foreach my$x (@{$self->data}) {push(@intervals,$x->TeX($equation))} 609 my$TeX = join($op->{TeX} ||$op->{string} || '\hbox{ or }',@intervals);
610   $TeX = '\left('.$TeX.'\right)' if defined($prec) &&$prec > ($op->{precedence} || 1.5); 611 return$TeX;
612 }
613
614 ##################################################
615
616 package Inequalities::Set;
617 our @ISA = ("Inequalities::common", "Value::Set");
618
619 sub type {"Set"}
620
621 sub string {
622   my $self = shift; my$equation = shift;
623   my $x =$self->{varName} || ($self->context->variables->names)[0]; 624$x = $context->{variables}{$x}{string} if defined $context->{variables}{$x}{string};
625   my @coords = ();
626   foreach my $a (@{$self->data}) {
627     if (Value::isValue($a)) { 628$a->{format} = $self->{format} if defined$self->{format};
629       push(@coords,$x.' = '.$a->string($equation)); 630 } else { 631 push(@coords,$x.' = '.$a); 632 } 633 } 634 return$self->getFlag('noneWord') unless scalar(@coords);
635   return join(" or ",@coords);
636 }
637
638 sub TeX {
639   my $self = shift; my$equation = shift;
640   my $x =$self->{varName} || ($self->context->variables->names)[0]; 641$x = $context->{variables}{$x}{TeX} if defined $context->{variables}{$x}{TeX};
642   $x =~ s/^([^_]+)_?(\d+)$/$1_{$2}/;
643   my @coords = ();
644   foreach my $a (@{$self->data}) {
645     if (Value::isValue($a)) { 646$a->{format} = $self->{format} if defined$self->{format};
647       push(@coords,$x.' = '.$a->TeX($equation)); 648 } else { 649 push(@coords,$x.' = '.$a); 650 } 651 } 652 return '\hbox{'.$self->getFlag('noneWord').'}' unless scalar(@coords);
653   return join('\hbox{ or }',@coords);
654 }
655
656 ##################################################
657 #
658 #  A class for making inequalities by hand
659 #
660 package Inequalities::Inequality;
661 our @ISA = ('Value');
662
663 sub new {
664   my $self = shift; my$class = ref($self) ||$self;
665   my $context = (Value::isContext($_[0]) ? shift : $self->context); 666 my$S = shift; my $x = shift; 667$S = Value::makeValue($S,context=>$context);
668   if (Value::classMatch($S,"Inequality")) { 669 if (defined($x)) {$S->{varName} =$x; $S->updateParts} 670 return$S;
671   }
672   $x = ($self->context->variables->names)[0] unless $x; 673$S = bless $S->inContext($context), $self->Package("Inequality".$S->type);
674   $S->{varName} =$x; $S->{reduceSets} =$S->{"is".$S->Type} = 1; 675$S->updateParts;
676   return $S; 677 } 678 679 ################################################## 680 # 681 # Allow Interval() to coerce types to Value::Interval 682 # 683 package Inequalities::MakeInterval; 684 our @ISA = ("Value::Interval"); 685 686 sub new { 687 my$self = shift;
688   $self =$self->SUPER::new(@_);
689   $self =$self->demote if $self->classMatch("Inequality"); 690 return$self;
691 }
692
693 ##################################################
694 #
695 #  Mark this as a list of inequalities (if it is)
696 #
697 package Inequalities::List;
698 our @ISA = ("Value::List");
699
700 sub new {
701   my $self = (shift)->SUPER::new(@_); 702 return$self unless $self->{type} =~ m/^(unknown|Interval|Set|Union)$/;
703   foreach my $x (@{$self->{data}}) {return $self unless Value::classMatch($x,'Inequality')}
704   $self->{type} = 'Inequality'; 705 return$self;
706 }
707
708 package Inequalities::List::List;
709 our @ISA = ("Parser::List::List");
710
711 sub _check {
712   my $self = shift;$self->SUPER::_check(@_);
713   if ($self->canBeInUnion) { 714 # 715 # Convert lists that look like intervals into intervals 716 # and then check if they are OK. 717 # 718 bless$self, $self->context->{lists}{Interval}{class}; 719$self->{type} = $Value::Type{interval}; 720$self->{parens} = $self->context->{parens}{interval}; 721$self->_check;
722   } else {
723     my $entryType =$self->typeRef->{entryType};
724     return unless $entryType->{name} =~ m/^(unknown|Interval|Set|Union)$/;
725     foreach my $x (@{$self->{coords}}) {return unless $x->{isInequality}}; 726$entryType->{name} = "Inequality";
727   }
728 }
729
730 ##################################################
731
732 1;