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  /*
25   * @(#)Fact.java 1.00
26   */
27  
28  package zeus.concepts;
29  
30  import java.util.*;
31  import java.io.*;
32  
33  import zeus.util.*;
34  import zeus.concepts.fn.*;
35  
36  /***
37   * The Fact class is key conceptual data structure in ZEUS, since Fact objects
38   * store the information that collectively forms the application ontology.
39   * Each fact consists of a number of attribute-value pairs, which are stored
40   * in the {@link AttributeList} variable. <p>
41   * Fact objects come in two forms:
42   * <ul>
43   * <li> Fact Descriptions - these represent actual entities (always shown prefixed
44   * with an @ symbol).
45   * <li> Fact Variables - these are descriptions of virtual entities that can
46   * be instantiated as Facts (these always shown prefixed with a ? symbol).
47   * </ul> <p>
48   * Facts originate from template descriptions, so they can only be created
49   * from an existing ontology by invoking the {@link OntologyDb#getFact}
50   * method of the agent's {@link OntologyDb}.
51   *
52   *This class is a little case study in how a little knowledge can be a dangerous 
53   *thing. It seems that the concept of checking boolean flags one at a time didn't
54   *appeal to whoever implemented it (DN?) and instead a int based mask system 
55   *has been used to check and set the characteristics of the class. Unfortunately
56   *I suspect that the mask is used in side effects for a number of algorithms 
57   *in the core reasoners, so while I would like to remove this nonsense, I so far
58   *haven't summed up the courage!
59   */
60  
61  public class Fact {
62     public static final String NONVAR = "fact";
63     public static final String VAR    = "var";
64     public static final String V_STR  = "?";
65     public static final char   V_CHR  = '?';
66     public static final String F_STR  = "@";
67     public static final char   F_CHR  = '@';
68     public static final String A_STR  = ".";
69     public static final char   A_CHR  = '.';
70  
71  
72     public static final boolean FACT = false;
73     public static final boolean VARIABLE = true;
74     public static final String  SELF_NAME = "self";
75     public static final String  THIS_NAME = "this";
76     public static final String  THIS = V_STR + THIS_NAME;
77     public static final String  SELF = V_STR + SELF_NAME;
78  
79     public static final String newVar(GenSym genSym) {
80        return genSym.plainId(V_STR+VAR);
81     }
82  
83     protected static String name(boolean isVariable, GenSym genSym) {
84        String s = (isVariable ? VAR : NONVAR);
85        return  genSym.plainId(s);
86  
87     }
88  
89     
90     // one can only wonder at the mind that would think that 
91     // setting binary masks for tests in a Java program 
92     // is a sane idea.
93     // still, I daren't remove it....
94     protected static final int IS_VARIABLE    = 1;
95     protected static final int IS_NEGATION    = 2;
96     protected static final int IS_READ_ONLY   = 4;
97     protected static final int IS_REPLACED    = 8;
98     protected static final int IS_LOCAL       = 16;
99     protected static final int IS_SIDE_EFFECT = 32;
100 
101    transient ValueFunction functor = null;
102    transient String        descp = null;
103 
104    protected String        id;
105    protected String        type;
106    protected int           modifiers;
107    protected AttributeList attr;
108    protected OntologyDb    ontology;
109 
110    public Fact () { 
111     ;
112    }
113 
114    Fact(boolean is_variable, String type, OntologyDb ontology, GenSym genSym) {
115       this.id        = name(is_variable,genSym);
116       this.type      = type;
117       this.modifiers = is_variable ? IS_VARIABLE : 0;
118       this.ontology  = ontology;
119       setFunctor();
120    }
121 
122 
123    public Fact(Fact fact) {
124       this.id        = fact.ID();
125       this.type      = fact.getType();
126       this.modifiers = fact.getModifiers();
127       this.attr      = new AttributeList(fact.getAttributeList());
128       this.ontology  = fact.getOntologyDb();
129       setFunctor();
130    }
131 
132 
133    public Fact(boolean is_variable, Fact fact) {
134       this(fact);
135       setIsVariable(is_variable);
136    }
137 
138 
139    protected Fact(String type, String id, int modifiers,
140                   AttributeList attr, OntologyDb ontology) {
141       this.id        = id;
142       this.type      = type;
143       this.modifiers = modifiers;
144       this.attr      = attr;
145       this.ontology  = ontology;
146       setFunctor();
147    }
148 
149    
150    /*** 
151     *made this accessor public (simon 23/9/02)
152     *with the object of using it to get service description information
153     **/    
154     public OntologyDb getOntologyDb() {
155       return ontology;
156    }
157 
158 
159    /***
160     * Here mode defines whether or not this fact owns the attribute
161     * being edited, where 'true' implies the fact owns the attribute
162     */
163    public TreeNode createAttributeTree(boolean mode) {
164 
165       String name = (mode) ? SELF : getId();
166       return ontology.createAttributeTree(type,name);
167    }
168 
169    // in case you are wondering, which, believe me, I did a lot when I saw this 
170    // I think that what is going on here is an amazingly complex scheme to test
171    // whether some boolean flags are set
172    // it appears to work
173    // I am loath to change it 
174    // but it may be some of the worst code I ever saw.
175    public static boolean isVariable(int x)   { return (x&IS_VARIABLE)    != 0; }
176    public static boolean isNegative(int x)   { return (x&IS_NEGATION)    != 0; }
177    public static boolean isReadOnly(int x)   { return (x&IS_READ_ONLY)   != 0; }
178    public static boolean isLocal(int x)      { return (x&IS_LOCAL)       != 0; }
179    public static boolean isReplaced(int x)   { return (x&IS_REPLACED)    != 0; }
180    public static boolean isSideEffect(int x) { return (x&IS_SIDE_EFFECT) != 0; }
181 
182    public boolean isVariable()   { return isVariable(modifiers);   }
183    public boolean isNegative()   { return isNegative(modifiers);   }
184    public boolean isReadOnly()   { return isReadOnly(modifiers);   }
185    public boolean isLocal()      { return isLocal(modifiers);      }
186    public boolean isReplaced()   { return isReplaced(modifiers);   }
187    public boolean isSideEffect() { return isSideEffect(modifiers); }
188 
189    public String ID()           { return id; }
190    public String getId()        { return descp; }
191    public String getType()      { return type; }
192    public int    getModifiers() { return modifiers; }
193 
194    public void setId(String id) {
195       Assert.notNull(id);
196       this.id = id;
197       setFunctor();
198    }
199 
200    public void setType(String type) {
201       Assert.notNull(type);
202       this.type = type;
203       setFunctor();
204    }
205 
206 
207    public void setModifiers(int modifiers) {
208       this.modifiers = modifiers;
209       setFunctor();
210    }
211 
212    public static int setIsVariable(int x, boolean set) {
213       if ( set )
214          x |= IS_VARIABLE;
215       else
216          x &= ~IS_VARIABLE;
217       return x;
218    }
219 
220    public static int setIsNegative(int x, boolean set) {
221       // if IS_NEGATION then clear IS_READ_ONLY, IS_LOCAL and IS_REPLACED
222       // otherwise clear IS_NEGATION
223       if ( set ) {
224          x &= ~(IS_READ_ONLY|IS_LOCAL|IS_REPLACED);
225          x |= IS_NEGATION;
226       }
227       else
228          x &= ~IS_NEGATION;
229       return x;
230    }
231 
232    public static int setIsReadOnly(int x, boolean set) {
233       // if IS_READ_ONLY then clear IS_NEGATION and IS_REPLACED
234       // otherwise clear IS_READ_ONLY
235       if ( set ) {
236          x &= ~(IS_NEGATION|IS_REPLACED);
237          x |= IS_READ_ONLY;
238       }
239       else
240          x &= ~IS_READ_ONLY;
241       return x;
242    }
243 
244    public static int setIsLocal(int x, boolean set) {
245       // if IS_LOCAL then clear IS_NEGATION
246       // otherwise clear IS_LOCAL
247       if ( set ) {
248          x &= ~IS_NEGATION;
249          x |= IS_LOCAL;
250       }
251       else
252          x &= ~IS_LOCAL;
253       return x;
254    }
255 
256    public static int setIsReplaced(int x, boolean set) {
257       // if IS_REPLACED then clear IS_READ_ONLY and IS_NEGATION
258       // otherwise clear IS_REPLACED
259       if ( set ) {
260          x &= ~(IS_READ_ONLY|IS_NEGATION);
261          x |= IS_REPLACED;
262       }
263       else
264          x &= ~IS_REPLACED;
265       return x;
266    }
267 
268    public static int setIsSideEffect(int x, boolean set) {
269       if ( set )
270          x |= IS_SIDE_EFFECT;
271       else
272          x &= ~IS_SIDE_EFFECT;
273       return x;
274    }
275 
276 
277    public void setIsVariable(boolean set) {
278       modifiers = setIsVariable(modifiers,set);
279       setFunctor();
280    }
281    public void setIsNegative(boolean set) {
282       modifiers = setIsNegative(modifiers,set);
283    }
284    public void setIsReadOnly(boolean set) {
285       modifiers = setIsReadOnly(modifiers,set);
286    }
287    public void setIsLocal(boolean set) {
288       modifiers = setIsLocal(modifiers,set);
289    }
290    public void setIsReplaced(boolean set) {
291       modifiers = setIsReplaced(modifiers,set);
292    }
293    public void setIsSideEffect(boolean set) {
294       modifiers = setIsSideEffect(modifiers,set);
295    }
296 
297    public String[] listAttributes()  {
298       return attr.listAttributes();
299    }
300    public ValueFunction[] listValues()  {
301       return attr.listValues();
302    }
303    public ValueFunction[] variables()  {
304       Vector out = attr.variables();
305       if ( isVariable() && !out.contains(functor()) )
306          out.addElement(functor());
307 
308       ValueFunction[] result = new ValueFunction[out.size()];
309       for(int i = 0; i < result.length; i++ )
310          result[i] = (ValueFunction)out.elementAt(i);
311       return result;
312    }
313    
314    /*** 
315     getAttributeList returns a list of the attributes of the Fact. 
316     This is public in 1.2.1 so that it can be manipulated directly
317     */
318    public AttributeList getAttributeList()  { 
319       return attr;
320    }
321 
322    public String getValue(String attribute) {
323       String value = attr.getValue(attribute);
324       if ( value == null )
325          Core.USER_ERROR("Fact.getValue(): No attribute \'" + attribute +
326            "\' found in fact \'" + this + "\'");
327       return value;
328    }
329    
330    
331    public ValueFunction getFn(String attribute) {
332       ValueFunction value = attr.getFn(attribute);
333       if ( value == null )
334          Core.USER_ERROR("Fact.getValue(): No attribute \'" + attribute +
335            "\' found in fact \'" + this + "\'");
336       return value;
337    }
338 
339    public int getInt(String attribute) {
340       try {
341          PrimitiveNumericFn fn;
342          fn = (PrimitiveNumericFn)attr.getFn(attribute);
343          return fn.intValue();
344       }
345       catch(ClassCastException e) {
346          Core.USER_ERROR("Fact.getInt(\'" + attribute +
347             "\') called for non-ground value \'" + this + "\'");
348          return 0;
349       }
350       catch(NullPointerException e1) {
351          Core.USER_ERROR("Fact.getInt(): No attribute \'" + attribute +
352            "\' found in fact \'" + this + "\'");
353          return 0;
354       }
355    }
356 
357    public double getDouble(String attribute) {
358       try {
359          PrimitiveNumericFn fn;
360          fn = (PrimitiveNumericFn)attr.getFn(attribute);
361          return fn.doubleValue();
362       }
363       catch(ClassCastException e) {
364          Core.USER_ERROR("Fact.getDouble(\'" + attribute +
365             "\') called for non-ground value \'" + this + "\'");
366          return 0;
367       }
368       catch(NullPointerException e1) {
369          Core.USER_ERROR("Fact.getDouble(): No attribute \'" + attribute +
370            "\' found in fact \'" + this + "\'");
371          return 0;
372       }
373    }
374 
375    public long getLong(String attribute) {
376       try {
377          PrimitiveNumericFn fn;
378          fn = (PrimitiveNumericFn)attr.getFn(attribute);
379          return fn.longValue();
380       }
381       catch(ClassCastException e) {
382          Core.USER_ERROR("Fact.getLong(\'" + attribute +
383             "\') called for non-ground value \'" + this + "\'");
384          return 0;
385       }
386       catch(NullPointerException e1) {
387          Core.USER_ERROR("Fact.getLong(): No attribute \'" + attribute +
388            "\' found in fact \'" + this + "\'");
389          return 0;
390       }
391    }
392 
393    public int getNumber() {
394       if ( !isa(OntologyDb.ENTITY) ) return 1;
395 
396       try {
397          PrimitiveNumericFn fn;
398          fn = (PrimitiveNumericFn)attr.getFn(OntologyDb.NUMBER);
399          return fn.intValue();
400       }
401       catch(ClassCastException e) {
402        
403             e.printStackTrace(); 
404           
405          Core.USER_ERROR("getNumber() called for non-ground value \'" +
406             this + "\'");
407          return 0;
408       }
409    }
410 
411    public void setNumber(int x) {
412       if ( isa(OntologyDb.ENTITY) )
413          setValue(OntologyDb.NUMBER,x);
414       else if ( x != 1 )
415          Core.USER_ERROR("setNumber() called for non-" + OntologyDb.ENTITY +
416             " object \'" + this + "\'");
417    }
418    public void setNumber(VarFn var1) {
419       if ( isa(OntologyDb.ENTITY) )
420          setValue(OntologyDb.NUMBER,var1);
421       else
422          Core.USER_ERROR("setNumber() called for non-" + OntologyDb.ENTITY +
423             " object \'" + this + "\'");
424    }
425 
426    public double getNetCost() {
427       if ( isa(OntologyDb.ENTITY) && !isDeterminate(OntologyDb.COST) ) return 0;
428       return getNumber() * getUnitCost();
429    }
430    public double getUnitCost() {
431       if ( !isa(OntologyDb.ENTITY) ) return 0;
432 
433       try {
434          PrimitiveNumericFn fn;
435          fn = (PrimitiveNumericFn)attr.getFn(OntologyDb.COST);
436          return fn.doubleValue();
437       }
438       catch(ClassCastException e) {
439          Core.USER_ERROR("getUnitCost() called for non-ground value \'" +
440             this + "\'");
441          return 0;
442       }
443    }
444    public void setUnitCost(double x) {
445       if ( isa(OntologyDb.ENTITY) )
446          setValue(OntologyDb.COST,x);
447       else
448          Core.USER_ERROR("setUnitCost() called for non-" + OntologyDb.ENTITY +
449             " object \'" + this + "\'");
450    }
451    public void setUnitCost(VarFn var1) {
452       if ( isa(OntologyDb.ENTITY) )
453          setValue(OntologyDb.COST,var1);
454       else
455          Core.USER_ERROR("setUnitCost() called for non-" + OntologyDb.ENTITY +
456          " object \'" + this + "\'");
457    }
458 
459    public VarFn newVar() {
460       return new VarFn(newVar(ontology.GenSym()));
461    }
462 
463    public void setValue(String attribute, int value) {
464       setValue(attribute, new IntFn(value));
465    }
466    public void setValue(String attribute, long value) {
467       setValue(attribute, new IntFn(value));
468    }
469    public void setValue(String attribute, double value) {
470       setValue(attribute, new RealFn(value));
471    }
472    public void setValue(String attribute, boolean value) {
473       setValue(attribute, BoolFn.newBoolFn(value));
474    }
475    public void setValue(String attribute, String value) {
476       ValueFunction fn = ZeusParser.Expression(ontology,value);
477       if ( fn == null )
478          Core.USER_ERROR("Cannot parse value \'" + value +
479             "\' in Fact.setValue()");
480       else
481          setValue(attribute,fn);
482    }
483    public void setValue(String attribute, ValueFunction value) {
484       if ( !ontology.validate(type,attribute,value) )
485          Core.USER_ERROR("Setting value \'" + value + "\' for " +
486             "attribute \'" + attribute + "\' in fact \'" + this + "\'");
487       else
488          attr.setValue(attribute, value);
489    }
490    void setAttributeList(AttributeList List) {
491       Assert.notNull(List);
492       attr = List;
493    }
494 
495    public void setValues(String[] input) {
496       if ( input.length%2 != 0 ) {
497          Core.USER_ERROR("Fact.setValues():: improper input length \"{" +
498             Misc.concat(input) + "}\".");
499          return;
500       }
501 
502       for(int i = 0; i < input.length; i += 2 )
503          setValue(input[i],input[i+1]);
504    }
505  
506  /*
507     public boolean equals (Object obj) { 
508         if ( !(obj instanceof Fact) ) {
509             debug ("not a fact!!!"); 
510             return false;
511             }
512       Fact f = (Fact)obj;
513       if (!isa(f.getType())) { 
514         debug (getId() + " ret false on type"); 
515         return false; }
516       if ( isVariable() || f.isVariable() ){
517          boolean retval = attr.equals(f.getAttributeList());
518          if (retval == false) { 
519             debug (getId() + " ret false in attrtest"); 
520             return false;
521             }
522             else {
523                 debug (getId() + " ret true in attrtest"); 
524                 return true; 
525             }
526                 
527          }
528       else { 
529          boolean retval = descp.equals(f.getId()); 
530          
531         if (retval == false) { 
532             debug (getId() + " ret false in descp test"); 
533             return false;
534             }
535             else {
536                 debug (getId() + " ret true in descp test"); 
537                 return true; 
538             }
539         }
540         
541     }*/
542  
543  /*** 
544         possibly this should return a true if it is equals in an oo sense? 
545             */
546    public boolean equals(Object obj) {
547       debug ("normal equality " + this.toString()); 
548       if ( !(obj instanceof Fact) ) return false;
549       Fact f = (Fact)obj;
550       if ( !type.equals(f.getType()) )
551           return false;
552       if ( isVariable() || f.isVariable() )
553          return attr.equals(f.getAttributeList());
554       else
555          return descp.equals(f.getId());
556    }
557 
558 
559    protected void setFunctor() {
560       descp = isVariable() ? V_STR + id : F_STR + id;
561       functor = isVariable() ? (ValueFunction)(new VarFn(descp))
562                              : (ValueFunction)(new TypeFn(descp));
563    }
564 
565    public boolean isDeterminate() {
566       return isVariable() ? false : attr.isDeterminate();
567    }
568 
569    public boolean isDeterminate(String attribute) {
570       return attr.isDeterminate(attribute);
571    }
572 
573    public String[] objectAttributeNames() {
574       String[] a = attr.listAttributes();
575       String object = getId();
576       for(int i = 0; i < a.length; i++ )
577          a[i] = object + A_STR + a[i];
578       return a;
579    }
580 
581    public String toString() {
582 
583    // test only
584         //System.out.println("SL ::\n" + this.toSL());
585    // end test
586       String s = "(:type " + type + " " +
587                   ":id " + id + " " +
588                    ":modifiers " + modifiers;
589       if ( !attr.isEmpty() )
590          s += " :attributes " + attr.toString();
591       return s + ")";
592    }
593 
594 
595 
596    /***
597         added by Simon on 20/02/02
598         Get the SL value of this fact
599         An abs factory implementation would be better, but I want to have a go at this
600         first before investing too heavily in a final implementation
601         */
602    public String toSL () {
603         String s = "(" +  type+" ";
604         if (!attr.isEmpty())
605                 s +=  attr.toSL();
606                 return s +")";
607    }
608 
609 
610 
611    public String pprint() {
612       return pprint(0);
613    }
614 
615 
616    public String pprint(int sp) {
617       String suffix, prefix;
618       String tabs = Misc.spaces(sp);
619       String eol  = "\n" + tabs + " ";
620 
621       String s = "(:type " + type + eol +
622                   ":id " + id + eol +
623                   ":modifiers " + modifiers + eol;
624 
625       if ( !attr.isEmpty() ) {
626          prefix = ":attributes ";
627          suffix = Misc.spaces(1 + sp + prefix.length());
628          s += prefix + attr.pprint(suffix.length());
629       }
630       return s.trim() + "\n" + tabs + ")";
631    }
632 
633    
634    /*** 
635     *this is a bit of a mess, because we are passing a parameter that is 
636     *used to ppring the fact into DAML format...
637     *header is the front of the parameter, footer is the close tag
638     */
639    public String printDAML (String header,String footer) { 
640        String names [] = attr.getNames();
641        String out = new String ();
642        for (int count = 0;count<names.length; count++) {
643        out += header + "#" + type +":" + names[count] + "=" + attr.getValue(names[count]) + "//\""+footer+"//n\";\n"; 
644        }
645        return out;
646    }
647 
648    public boolean unifiesWith(Fact f, Bindings bindings) {
649       if ( type.equals(f.getType()) ) {
650 
651          if ( !isVariable() && !f.isVariable() && !descp.equals(f.getId()) )
652             return false;
653 
654          Bindings b = new Bindings(bindings);
655          ValueFunction me  = functor();
656          ValueFunction you = f.functor();
657 
658          if ( me.unifiesWith(you,b) == null ||
659               !attr.unifiesWith(f.getAttributeList(),b) )
660             return false;
661 
662          bindings.set(b);
663          return true;
664       }
665       return false;
666    }
667 
668    public boolean unifiesWithChild(Fact f, Bindings bindings) {
669       if ( type.equals(f.getType()) )
670          return unifiesWith(f,bindings);
671 
672       else if ( ontology.isAncestorOf(f.getType(),type) ) {
673          if ( !isVariable() && !f.isVariable() )
674             return false;
675 
676          Bindings b = new Bindings(bindings);
677 
678          if ( !attr.unifiesWith(f.getAttributeList(),b) )
679             return false;
680 
681          bindings.set(b);
682          return true;
683       }
684       return false;
685    }
686 
687    public boolean isa(String ancestor) {
688       return type.equals(ancestor) || ontology.isAncestorOf(type,ancestor);
689    }
690 
691    public ValueFunction functor() {
692       return (ValueFunction) functor;
693    }
694    public boolean resolve(Bindings bindings) {
695       return resolve(new ResolutionContext(),bindings);
696    }
697    public boolean resolve(ResolutionContext context, Bindings bindings) {
698       Object obj = context.put(THIS,this);
699       boolean status = attr.resolve(context,bindings);
700       if ( obj != null ) context.put(THIS,obj);
701       return status;
702    }
703 
704    public boolean disjoin(Fact f) {
705       if ( !type.equals(f.getType()) ) return false;
706       attr.disjoin(f.getAttributeList());
707       return true;
708    }
709 
710    public Fact duplicate(String name, GenSym genSym) {
711       DuplicationTable table = new DuplicationTable(name,genSym);
712       return duplicate(table);
713    }
714 
715    
716    public Fact duplicate(DuplicationTable table) {
717       String id1 = table.getRef(id);
718       AttributeList attr1 = attr.duplicate(table);
719       Fact f1 = new Fact(type,id1,modifiers,attr1,ontology);
720       return f1;
721    }
722 
723     /*** 
724         test to see if any of the values in this fact are mapped to 
725         the valeus in the @param mapper, make a map of attno to attno for all the 
726         attributes so that they can be mapped in the method map
727         */
728     public synchronized String[] buildMap(Fact mapper) { 
729         debug (this.type); 
730         String [] retVal = new String[attr.size()];
731         Enumeration keys = attr.keys(); 
732         AttributeList mapperAttr = mapper.getAttributeList(); 
733         int count = 0; 
734         while (keys.hasMoreElements()){ 
735          Enumeration mapperKeys = mapperAttr.keys(); 
736          String key = (String) keys.nextElement(); 
737          String val = attr.getValue(key); 
738          int count2 = 0; 
739          boolean done = false; 
740          while (mapperKeys.hasMoreElements()&& !done) { 
741             String mkey = (String) mapperKeys.nextElement();
742             String mval = mapperAttr.getValue(mkey); 
743             ValueFunction mVf = mapperAttr.getFn (mkey); 
744             debug ("mVf = " + mVf.toString() + " " + mVf.getClass()); 
745             ValueFunction vf = attr.getFn (key); 
746             debug ("vf = " + vf.toString()); 
747             if (mVf.equals (vf)) { 
748                     debug ("mVf == vf"); 
749             }
750             else {
751                 debug ("mVf != vf"); 
752             }
753             debug ("in buildMap mkey = " + mkey + " mval = " + mval + " val = " + val);  
754             if (mval.equals (val) && val.startsWith("?")) { 
755                 debug ("mapping:" + mval + " = " + val);
756                 retVal[count] = mkey;
757                 done = true; 
758             }
759             else if (val.startsWith(mapper.getId())) {
760                 debug("ID's match!!");
761                 String attrVal = val.substring(mapper.getId().length()+1, val.length()); 
762                 debug ("attrVal == " + attrVal); 
763                 if (!mkey.equals(attrVal)) {
764                         debug (mkey + " != " + attrVal); 
765                         retVal [count] = null;}
766                         else {
767                             debug (mkey + " == " + attrVal); 
768                             retVal [count] = mkey; 
769                             done = true; 
770                         }
771                         }
772             else {
773                 retVal [count] = null; }
774             count2++;
775          }
776          count++;
777         }  
778         return (retVal); 
779     }
780     
781     /***
782         map the values of the attributes in this fact to the values in the 
783         fact mapper. map is an array of ints such that map[1] = 3 indicates 
784         that the attribute value[3] of mapper should be mapped to the value 1 of 
785         this fact
786         */
787     public synchronized void doMap (Fact mapper, String [] tmap) { 
788         Core.DEBUG(1,"in doMap in Fact\n"); 
789         AttributeList mapperAttr = mapper.getAttributeList(); 
790         debug ("attr == " + attr.toString()); 
791         debug ("mapperAttr = " + mapperAttr.toString()); 
792         AttributeList newAttr = attr.duplicate("newAttr", new GenSym("temp")); // was attr
793         
794         debug ("newAttr == " + newAttr.toString()); 
795         Enumeration keys = attr.keys(); 
796         int count = 0; 
797         while (keys.hasMoreElements()){ 
798             String key = (String) keys.nextElement(); 
799             debug("int doMap key = " + key); 
800             ValueFunction val = attr.getFn(key); 
801             if (tmap [count] != null) { 
802                 debug("altering value"); 
803                 newAttr.remove(key); 
804                 debug ("tmap = " + tmap [count]); 
805                 debug("count = "  + String.valueOf(count)); 
806            //     debug ("mapper.getVal(count-1) = " + mapper.getVal(count-1).toString()); 
807                 debug ("mapper.getFn(tmap[count]) = " + mapper.getFn(tmap[count])); 
808                 newAttr.put(key,mapper.getFn(tmap[count])); // simon adds -1 // and removes it - what happens?
809             }
810             else 
811                 newAttr.put (key, val); 
812             count++; 
813         }
814             attr = newAttr;
815                
816         }
817             
818             
819             
820    public synchronized ValueFunction getVal(int pos) { 
821      Enumeration keys = attr.keys(); 
822      int count = 0; 
823      if (pos < attr.size()) { 
824        String key = null; 
825        for (count = 0; count <= pos; count++) { 
826             key = (String)keys.nextElement(); 
827        }
828        debug ("key = " + key); 
829        
830        return  attr.getFn(key); }
831        else 
832        debug (String.valueOf(attr.size())); 
833        return null; 
834      }
835             
836 
837     public void map (Fact toMap) { 
838         String [] mapval = buildMap (toMap); 
839         doMap (toMap, mapval); 
840     }
841 
842 
843     private void debug (String str) { 
844        //System.out.println("fact>> " + str); 
845     }
846 
847 
848     public static void main (String argv[]) { 
849         ;
850      
851         
852     }
853 
854 }