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 (or Enums) following 
010     * the INRECA - More is Better formulae
011     * 
012     * sim(c.a,q.a)= if(c.a > q.a) then 1 else  jump * (1- (q.a - c.a) / q.a))
013     * 
014     * jump must be defined by the designer.
015     */
016    public class InrecaMoreIsBetter implements LocalSimilarityFunction {
017    
018            double jump;
019    
020            /**
021             * Constructor.
022             */
023            public InrecaMoreIsBetter(double jumpSimilarity) {
024                this.jump = jumpSimilarity;
025            }
026    
027            /**
028             * Applies the similarity function.
029             * 
030             * @param caseObject is a Number
031             * @param queryObject is a Number
032             * @return result of apply the similarity function.
033             */
034            public double compute(Object caseObject, Object queryObject) throws NoApplicableSimilarityFunctionException{
035                    if ((caseObject == null) || (queryObject == null))
036                            return 0;
037                    if (! ((caseObject instanceof java.lang.Number)||(caseObject instanceof Enum)))
038                            throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), caseObject.getClass());
039                    if (! ((queryObject instanceof java.lang.Number)||(queryObject instanceof Enum)))
040                            throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), queryObject.getClass());
041    
042                    double caseValue;
043                    double queryValue;
044    
045                    if(caseObject instanceof Number)
046                    {
047                        Number n1  = (Number) caseObject;
048                        Number n2  = (Number) queryObject;
049                        caseValue  = n1.doubleValue();
050                        queryValue = n2.doubleValue();
051                    }
052                    else
053                    {
054                        Enum enum1 = (Enum)caseObject;
055                        Enum enum2 = (Enum)queryObject;
056                        caseValue  = enum1.ordinal();
057                        queryValue = enum2.ordinal();
058                    }
059                    
060                    if(caseValue >= queryValue)
061                        return 1;
062                    
063                    else return jump * (1- ((queryValue - caseValue) / queryValue) );
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    }