001    package jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders;
002    
003    import jcolibri.exception.NoApplicableSimilarityFunctionException;
004    import jcolibri.method.retrieve.NNretrieval.similarity.LocalSimilarityFunction;
005    
006    
007    
008    /**
009     * This function returns the similarity of two numbers following 
010     * the McSherry - More is Better formulae
011     * 
012     * sim(c.a,q.a)= 1 - ((max(a) - c.a) / (max(a)-min(a)))
013     * 
014     * min(a) and max(a) must be defined by the designer. q.a is not taken into account.
015     */
016    public class McSherryMoreIsBetter implements LocalSimilarityFunction {
017    
018            /** InrecaLessIsBetter. */
019            double maxValue;
020            double minValue;
021    
022            /**
023             * Constructor. max and min values are ignored for enum types.
024             * 
025             */
026            
027            public McSherryMoreIsBetter(double maxAttributeValue, double minAttributeValue) {
028                this.maxValue = maxAttributeValue;
029                this.minValue = minAttributeValue;
030            }
031    
032            /**
033             * Applies the similarity function.
034             * 
035             * @param caseObject is a Number
036             * @param queryObject is a Number
037             * @return result of apply the similarity function.
038             */
039            public double compute(Object caseObject, Object queryObject) throws NoApplicableSimilarityFunctionException{
040                    if ((caseObject == null))
041                            return 0;
042                    if (! ((caseObject instanceof java.lang.Number)||(caseObject instanceof Enum)))
043                            throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), caseObject.getClass());
044    
045                    double caseValue;
046                    double max;
047                    double min;
048                    if(caseObject instanceof Number)
049                    {
050                        Number n1  = (Number) caseObject;
051                        caseValue  = n1.doubleValue();
052                        max = maxValue;
053                        min = minValue;
054                    }
055                    else
056                    {
057                        Enum enum1 = (Enum)caseObject;
058                        caseValue  = enum1.ordinal();
059                        max = caseObject.getClass().getEnumConstants().length;
060                        min = 0;
061                    }
062                    
063                    
064                    return 1 - ( (max-caseValue) / (max - min) );
065                    
066            }
067            
068            /** Applicable to any Number subinstance */
069            public boolean isApplicable(Object o1, Object o2)
070            {
071                    if((o1==null)&&(o2==null))
072                            return true;
073                    else if(o1==null)
074                            return (o2 instanceof Number)||(o2 instanceof Enum);
075                    else if(o2==null)
076                            return (o1 instanceof Number)||(o1 instanceof Enum);
077                    else
078                            return ((o1 instanceof Number)&&(o2 instanceof Number)) ||
079                                    ((o1 instanceof Enum)&&(o2 instanceof Enum));
080            }
081    
082    }