View Javadoc

1   /*
2   * The contents of this file are subject to the BT "ZEUS" Open Source 
3   * Licence (L77741), Version 1.0 (the "Licence"); you may not use this file 
4   * except in compliance with the Licence. You may obtain a copy of the Licence
5   * from $ZEUS_INSTALL/licence.html or alternatively from
6   * http://www.labs.bt.com/projects/agents/zeus/licence.htm
7   * 
8   * Except as stated in Clause 7 of the Licence, software distributed under the
9   * Licence is distributed WITHOUT WARRANTY OF ANY KIND, either express or 
10  * implied. See the Licence for the specific language governing rights and 
11  * limitations under the Licence.
12  * 
13  * The Original Code is within the package zeus.*.
14  * The Initial Developer of the Original Code is British Telecommunications
15  * public limited company, whose registered office is at 81 Newgate Street, 
16  * London, EC1A 7AJ, England. Portions created by British Telecommunications 
17  * public limited company are Copyright 1996-9. All Rights Reserved.
18  * 
19  * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20  */
21  
22  
23  
24  package zeus.concepts.fn;
25  
26  import java.util.*;
27  import zeus.util.*;
28  import zeus.concepts.*;
29  
30  /*** 
31      note: changed some accesses for 1.2.1 so that I could infer contents for 
32      precondition unification bug fixes
33     */
34  public class ConstraintFn extends ValueFunction {
35     static final int LE = 0;
36     static final int LT = 1;
37     static final int GE = 2;
38     static final int GT = 3;
39     static final int UN = 4;
40     static final int NE = 5;
41  
42     public static final String[] operators = {
43        "<=", "<", ">=", ">", "~", "!="
44     };
45  
46     public ValueFunction arg = null;
47     protected int op = -1;
48  
49     public ConstraintFn(String operator, ValueFunction arg) {
50        super(CONS,7);
51        op = Misc.whichPosition(operator,operators);
52        if ( op == -1 )
53           throw new IllegalArgumentException("Unknown operator \'" + operator +
54              "\' in constraint expression");
55  
56        this.arg = arg;
57        switch(op) {
58           case LE:
59           case GE:
60           case LT:
61           case GT:
62                switch(arg.getID()) {
63                   case ID:
64                   case LVAR:
65                   case FIELD:
66                   case ARITH:
67                   case FUNC:
68                   case INT:
69                   case REAL:
70                   case DATE:
71                   case TIME:
72                   case METH:
73                        break;
74  
75                   default:
76                      throw new IllegalArgumentException("Illegal operand in \'" +
77                         this + "\'");
78                }
79                break;
80  
81           case UN:
82           case NE:
83                break;
84  
85           default:
86                throw new IllegalArgumentException("Illegal operand in \'" +
87                   this + "\'");
88        }
89     }
90     
91     
92     public String toString() {
93        String out = operators[op] + arg;
94        return out;
95     }
96     
97     
98     public int getOperator() {
99        return op;
100    }
101    
102    
103    Object getArg(int position) {
104       if ( position != 0 )
105          throw new ArrayIndexOutOfBoundsException(position);
106       return arg;
107    }
108    
109    
110    public boolean references(ValueFunction var) {
111       return arg.references(var);
112    }
113    
114    
115    public Vector variables() {
116       return arg.variables();
117    }
118    
119    
120    public boolean isDeterminate() {
121       return arg.isDeterminate();
122    }
123    
124    
125    public ValueFunction resolve(ResolutionContext c, Bindings b) {
126       ValueFunction x = arg.resolve(c,b);
127       return (new ConstraintFn(operators[op],x)).evaluationFn();
128    }
129    
130    
131    public ValueFunction duplicate(DuplicationTable table) {
132       return new ConstraintFn(operators[op],arg.duplicate(table));
133    }
134    
135    
136    public ValueFunction mirror() {
137       return new ConstraintFn(operators[op],arg.mirror());
138    }
139    
140    
141    ValueFunction normalize() {
142       ValueFunction a = arg.normalize();
143       switch(op) {
144          case LE:
145          case GE:
146          case LT:
147          case GT:
148               switch(a.getID()) {
149                  case ID:
150                  case LVAR:
151                  case FIELD:
152                  case ARITH:
153                  case FUNC:
154                  case INT:
155                  case REAL:
156                  case DATE:
157                  case TIME:
158                  case METH:
159                       return new ConstraintFn(operators[op],a);
160 
161                  default:
162                       throw new IllegalArgumentException("Illegal operand in \'" + this + "\'");
163               }
164 
165          case UN:
166          case NE:
167               switch(a.getID()) {
168                  case ID:
169                  case TYPE:
170                  case FIELD:
171                  case FUNC:
172                  case IMPLY:
173                  case ELSE:
174                  case LOR:
175                  case LAND:
176                  case COMP:
177                  case BOOL:
178                  case INT:
179                  case REAL:
180                  case DATE:
181                  case TIME:
182                  case ARITH:
183                  case METH:
184                       return new ConstraintFn(operators[op],a);
185 
186                  case LNOT:
187                       return (ValueFunction)a.getArg();
188 
189                  case CONS:
190                       switch(((ConstraintFn)a).getOperator()) {
191                          case LE:
192                               return new ConstraintFn(operators[GT],
193                                  (ValueFunction)a.getArg());
194                          case GE:
195                               return new ConstraintFn(operators[LT],
196                                  (ValueFunction)a.getArg());
197                          case LT:
198                               return new ConstraintFn(operators[GE],
199                                  (ValueFunction)a.getArg());
200                          case GT:
201                               return new ConstraintFn(operators[LE],
202                                  (ValueFunction)a.getArg());
203 
204                          case NE:
205                          case UN:
206                               return (ValueFunction)a.getArg();
207 
208                          default:
209                               throw new IllegalArgumentException("Illegal operand in \'" + this + "\'");
210 
211                       }
212 
213                  case OR:
214                       ValueFunction x = (ValueFunction)a.getArg(0);
215                       ValueFunction y = (ValueFunction)a.getArg(1);
216                       x = (new ConstraintFn(operators[NE],x)).normalize();
217                       y = (new ConstraintFn(operators[NE],y)).normalize();
218                       return new AndFn(x,y);
219                  case AND:
220                       return new ConstraintFn(operators[op],a);
221 
222                  case LVAR:
223                       return new ConstraintFn(operators[op],a);
224 
225                  default:
226                       throw new IllegalArgumentException("Illegal operand in \'" + this + "\'");
227 
228               }
229 
230          default:
231               throw new IllegalArgumentException("Illegal operand in \'" + this + "\'");
232 
233       }
234    }
235    
236    
237    public boolean equals(Object any) {
238       if ( !(any instanceof ConstraintFn) ) return false;
239       ConstraintFn fn = (ConstraintFn)any;
240       return arg.equals(fn.getArg());
241    }
242    
243    
244    ValueFunction unify(ValueFunction fn, Bindings b) {
245 
246       if ( !isDeterminate() || !fn.isDeterminate() )
247          return new AndFn(this,fn);
248 
249       ValueFunction u = evaluationFn();
250       ValueFunction v = fn.evaluationFn();
251       int x = u.baseID();
252       int y = v.baseID();
253 
254       if ( x == INT || x == REAL ) {
255          if ( y != INT && y != REAL )
256             throw new IllegalArgumentException("Illegal operand in \'" +
257                this + "\'");
258       }
259       else if ( x != y ) {
260          throw new IllegalArgumentException("Illegal operand in \'" +
261             this + "\'");
262       }
263 
264       switch(op) {
265          case LE:
266          case GE:
267          case LT:
268          case GT:
269               switch(v.getID()) {
270                  case ID:
271                  case DATE:
272                  case TIME:
273                  case INT:
274                  case REAL:
275                       return compare((ConstraintFn)u,(PrimitiveFn)v);
276 
277                  case CONS:
278                       return checkRange((ConstraintFn)u,(ConstraintFn)v);
279 
280                  default:
281                     throw new IllegalArgumentException("Illegal operand in \'" +
282                        this + "\'");
283               }
284 
285          case UN:
286          case NE:
287               switch(v.getID()) {
288                  // The commented types should all resolve to primitives
289                  // case LVAR:
290                  // case FIELD:
291                  // case ARITH:
292                  // case IMPLY:
293                  // case ELSE:
294                  // case LOR:
295                  // case LAND:
296                  // case LNOT:
297                  // case COMP:
298                  // case FUNC:
299                  // case METH:
300                  // case CONSB:
301 
302                  case ID:
303                  case TYPE:
304                  case AND:
305                  case OR:
306                  case DATE:
307                  case TIME:
308                  case BOOL:
309                  case INT:
310                  case REAL:
311                  case VECT:
312                       if (((ValueFunction)u.getArg()).unifiesWith(v,b) == null)
313                          return v;
314                       else
315                          return null;
316 
317                  case CONS:
318                     switch(((ConstraintFn)v).getOperator()) {
319                        case UN:
320                        case NE:
321                             if ( u.equals(v) )
322                                return u;
323                             else
324                                return new AndFn(u,v);
325 
326                        default:
327                           return checkRange((ConstraintFn)u,(ConstraintFn)v);
328                     }
329               }
330               break;
331 
332          default:
333               throw new IllegalArgumentException("Illegal operand in \'" +
334                  this + "\'");
335       }
336       return null;
337    }
338    
339    
340    public int baseID() {
341       // must be called when Fn is known to be determinate
342       return arg.baseID();
343    }
344 
345 
346 
347    static ValueFunction compare(ConstraintFn a, PrimitiveFn b) {
348       PrimitiveFn x = (PrimitiveFn)a.getArg();
349       switch(a.getOperator()) {
350          case LE:
351 // System.err.println("Compare LE " + a + " and " + b);
352               if ( b.less(x) || b.equals(x) )
353                  return (ValueFunction)b;
354               else
355                  return null;
356 
357          case GE:
358 // System.err.println("Compare GE " + a + " and " + b);
359               if ( x.less(b) || x.equals(b) )
360                  return (ValueFunction)b;
361               else
362                  return null;
363 
364          case LT:
365 // System.err.println("Compare LT " + a + " and " + b);
366               if ( b.less(x) )
367                  return (ValueFunction)b;
368               else
369                  return null;
370          case GT:
371 // System.err.println("Compare GT " + a + " and " + b);
372               if ( x.less(b) )
373                  return (ValueFunction)b;
374               else
375                  return null;
376          default:
377 // System.err.println("Compare DEFAULT " + a + " and " + b);
378               Assert.notNull(null);
379               return null;
380       }
381    }
382 
383 
384    static ValueFunction checkRange(ConstraintFn a, ConstraintFn b) {
385 // System.err.println("CheckRange " + a + " and " + b);
386       if ( a.getOperator() > b.getOperator() )
387          return checkRange(b,a);
388 
389       PrimitiveFn x = (PrimitiveFn) a.getArg();
390       PrimitiveFn y = (PrimitiveFn) b.getArg();
391 
392       switch( a.getOperator() ) {
393          case LE:
394 // System.err.println("CheckRange LE " + a + " and " + b);
395               switch( b.getOperator() ) {
396                  case LE:
397                       return ( x.less(y) ? a : b );
398 
399                  case LT:
400                       if ( x.equals(y) )
401                          return null;
402                       else if ( x.less(y) )
403                          return a;
404                       else
405                          return b;
406 
407                  case GE:
408                       if ( x.equals(y) )
409                          return (ValueFunction)x;
410                       else if ( y.less(x) )
411                          return new AndFn(a,b);
412                       else
413                          return null;
414 
415                  case GT:
416                       if ( y.less(x) )
417                          return new AndFn(a,b);
418                       else
419                          return null;
420 
421                  case UN:
422                  case NE:
423                       if ( x.equals(y) )
424                          return new ConstraintFn(operators[LT],(ValueFunction)x);
425                       else if ( x.less(y) )
426                          return a;
427                       else
428                          return new AndFn(a,b);
429               }
430               break;
431 
432          case LT:
433 // System.err.println("CheckRange LT " + a + " and " + b);
434               switch( b.getOperator() ) {
435                  // case LE: already done
436                  case LT:
437                       return ( x.less(y) ? a : b );
438 
439                  case GE:
440                  case GT:
441                       if ( y.less(x) )
442                          return new AndFn(a,b);
443                       else
444                          return null;
445 
446                  case UN:
447                  case NE:
448                       if ( y.less(x) )
449                          return new AndFn(a,b);
450                       else
451                          return a;
452               }
453               break;
454 
455          case GE:
456 // System.err.println("CheckRange GE " + a + " and " + b);
457               switch( b.getOperator() ) {
458                  // case LE: already done
459                  // case LT: already done
460                  case GE:
461                       return (x.less(y) ? (ValueFunction)y : (ValueFunction)x);
462 
463                  case GT:
464                       if ( x.equals(y) )
465                          return null;
466                       else if ( x.less(y) )
467                          return b;
468                       else
469                          return a;
470 
471                  case UN:
472                  case NE:
473                       if ( x.equals(y) )
474                          return new ConstraintFn(operators[GT],(ValueFunction)x);
475                       else if ( x.less(y) )
476                          return new AndFn(a,b);
477                       else
478                          return a;
479               }
480               break;
481 
482          case GT:
483 // System.err.println("CheckRange GT " + a + " and " + b);
484               switch( b.getOperator() ) {
485                  // case LE:
486                  // case LT:
487                  // case GE:
488                  case GT:
489                       return ( x.less(y) ? b : a );
490 
491                  case UN:
492                  case NE:
493                       if ( x.less(y) )
494                          return new AndFn(a,b);
495                       else
496                          return a;
497               }
498               break;
499 
500          case UN:
501          case NE:
502 // System.err.println("CheckRange NE " + a + " and " + b);
503               switch( b.getOperator() ) {
504                  // case LE:
505                  // case LT:
506                  // case GE:
507                  // case GT:
508                  case UN:
509                  case NE:
510                       return ( x.equals(y) ? (ValueFunction)a
511                                            : (ValueFunction)(new AndFn(a,b)) );
512               }
513               break;
514       }
515       Assert.notNull(null); // should never get here
516       return null;
517    }
518 
519 }