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 - Less is Better formulae
011     * 
012     * sim(c.a,q.a)= (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 McSherryLessIsBetter 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            public McSherryLessIsBetter(double maxAttributeValue, double minAttributeValue) {
026                this.maxValue = maxAttributeValue;
027                this.minValue = minAttributeValue;
028            }
029    
030            /**
031             * Applies the similarity function.
032             * 
033             * @param caseObject is a Number
034             * @param queryObject is a Number
035             * @return result of apply the similarity function.
036             */
037            public double compute(Object caseObject, Object queryObject) throws NoApplicableSimilarityFunctionException{
038                    if ((caseObject == null))
039                            return 0;
040                    if (! ((caseObject instanceof java.lang.Number)||(caseObject instanceof Enum)))
041                            throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), caseObject.getClass());
042    
043                    double caseValue;
044                    double max;
045                    double min;
046                    if(caseObject instanceof Number)
047                    {
048                        Number n1  = (Number) caseObject;
049                        caseValue  = n1.doubleValue();
050                        max = maxValue;
051                        min = minValue;
052                    }
053                    else
054                    {
055                        Enum enum1 = (Enum)caseObject;
056                        caseValue  = enum1.ordinal();
057                        max = caseObject.getClass().getEnumConstants().length;
058                        min = 0;
059                    }
060                    
061                    
062                    
063                    return (max-caseValue) / (max - min);
064                    
065            }
066            
067            /** Applicable to any Number subinstance */
068            public boolean isApplicable(Object o1, Object o2)
069            {
070                    if((o1==null)&&(o2==null))
071                            return true;
072                    else if(o1==null)
073                            return (o2 instanceof Number)||(o2 instanceof Enum);
074                    else if(o2==null)
075                            return (o1 instanceof Number)||(o1 instanceof Enum);
076                    else
077                            return ((o1 instanceof Number)&&(o2 instanceof Number)) ||
078                                    ((o1 instanceof Enum)&&(o2 instanceof Enum));
079            }
080    
081    }