001    package jcolibri.method.retrieve.NNretrieval.similarity.local;
002    
003    import java.io.BufferedReader;
004    import java.io.InputStream;
005    import java.io.InputStreamReader;
006    import java.util.ArrayList;
007    import java.util.StringTokenizer;
008    
009    import org.apache.commons.logging.LogFactory;
010    
011    import jcolibri.method.retrieve.NNretrieval.similarity.LocalSimilarityFunction;
012    
013    /**
014     * Similarity function that uses a table to obtain the similarity between two values. 
015     * Allowed values are Strings or Enums. The table is read from a text file with the following format:
016     * <ul>
017     * <li>1st line: coma separated n categories
018     * <li>following n lines: n double values separated by comma. 
019     * </ul> 
020     */
021    public class Table implements LocalSimilarityFunction
022    {
023    
024        double matrix[][] = null;
025    
026        ArrayList<String> categories = new ArrayList<String>();
027    
028        public Table(String filename)
029        {
030            try
031            {
032                InputStream is = jcolibri.util.FileIO.openFile(filename);
033                BufferedReader br = null;
034                br = new BufferedReader(new InputStreamReader(is));
035                if (br == null)
036                {
037                    org.apache.commons.logging.LogFactory.getLog(this.getClass()).error("Cannot find file: " + filename);
038                    return;
039                }
040                String line = br.readLine();
041                StringTokenizer st = new StringTokenizer(line, ",");
042                while (st.hasMoreTokens())
043                    categories.add(st.nextToken());
044                int size = categories.size();
045    
046                matrix = new double[size][size];
047    
048                int i = 0;
049                while ((line = br.readLine()) != null)
050                {
051                    st = new StringTokenizer(line, ",");
052                    int j = 0;
053                    while (st.hasMoreTokens())
054                        matrix[i][j++] = Double.parseDouble(st.nextToken());
055                    i++;
056                }
057    
058            } catch (Exception e)
059            {
060                org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e);
061    
062            }
063        }
064    
065        /**
066         * Applies the similarity function.
067         * 
068         * @param caseObject is a String or Enum
069         * @param queryObject is a String or Enum
070         * @return result of apply the similarity function.
071         */
072        public double compute(Object caseObject, Object queryObject) throws jcolibri.exception.NoApplicableSimilarityFunctionException
073        {
074            if ((caseObject == null) || (queryObject == null))
075                    return 0;
076            if (! ((caseObject instanceof java.lang.String)||(caseObject instanceof Enum)))
077                    throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), caseObject.getClass());
078            if (! ((queryObject instanceof java.lang.String)||(queryObject instanceof Enum)))
079                    throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), queryObject.getClass());
080    
081            String caseS;
082            String queryS;
083            if(caseObject instanceof String)
084            {    
085                caseS = (String) caseObject;
086                queryS = (String) queryObject;
087            }else
088            {
089                caseS = ((Enum)caseObject).toString();
090                queryS = ((Enum)queryObject).toString();
091            }
092            if (matrix == null)
093            {
094                LogFactory.getLog(this.getClass()).error("Similarity table empty");
095                return 0;
096            }
097    
098            int pos1 = categories.indexOf(caseS);
099            if (pos1 == -1)
100            {
101                LogFactory.getLog(this.getClass()).error(caseS + " not found in table");
102                return 0;
103            }
104            int pos2 = categories.indexOf(queryS);
105            if (pos2 == -1)
106            {
107                LogFactory.getLog(this.getClass()).error(queryS + " not found in table");
108                return 0;
109            }
110            return matrix[pos1][pos2];
111    
112        }
113    
114        /** Applicable to String or Enum */
115        public boolean isApplicable(Object o1, Object o2)
116        {
117            if((o1==null)&&(o2==null))
118                    return true;
119            else if(o1==null)
120                    return (o2 instanceof String)||(o2 instanceof Enum);
121            else if(o2==null)
122                    return (o1 instanceof String)||(o1 instanceof Enum);
123            else
124                    return ((o1 instanceof String)&&(o2 instanceof String)) ||
125                            ((o1 instanceof Enum)&&(o2 instanceof Enum));
126        }
127    }