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 - Less is Better formulae 011 * 012 * sim(c.a,q.a)= if(c.a < q.a) then 1 else jump * (max(a) - c.a) / (max(a) - q.a) 013 * 014 * jump and max(a) must be defined by the designer. 015 */ 016 public class InrecaLessIsBetter implements LocalSimilarityFunction { 017 018 019 double maxValue; 020 double jump; 021 022 /** 023 * Constructor. max value is ignored for enum types. 024 */ 025 public InrecaLessIsBetter(double maxAttributeValue, double jumpSimilarity) { 026 this.maxValue = maxAttributeValue; 027 this.jump = jumpSimilarity; 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) || (queryObject == 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 if (! ((queryObject instanceof java.lang.Number)||(queryObject instanceof Enum))) 043 throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), queryObject.getClass()); 044 045 double caseValue; 046 double queryValue; 047 double max; 048 if(caseObject instanceof Number) 049 { 050 Number n1 = (Number) caseObject; 051 Number n2 = (Number) queryObject; 052 caseValue = n1.doubleValue(); 053 queryValue = n2.doubleValue(); 054 max = maxValue; 055 } 056 else 057 { 058 Enum enum1 = (Enum)caseObject; 059 Enum enum2 = (Enum)queryObject; 060 caseValue = enum1.ordinal(); 061 queryValue = enum2.ordinal(); 062 max = caseObject.getClass().getEnumConstants().length; 063 } 064 065 if(caseValue <= queryValue) 066 return 1; 067 if(caseValue>=maxValue) 068 return 0; 069 070 else return jump * (max-caseValue) / (max - queryValue); 071 072 } 073 074 /** Applicable to any Number subinstance */ 075 public boolean isApplicable(Object o1, Object o2) 076 { 077 if((o1==null)&&(o2==null)) 078 return true; 079 else if(o1==null) 080 return (o2 instanceof Number)||(o2 instanceof Enum); 081 else if(o2==null) 082 return (o1 instanceof Number)||(o1 instanceof Enum); 083 else 084 return ((o1 instanceof Number)&&(o2 instanceof Number)) || 085 ((o1 instanceof Enum)&&(o2 instanceof Enum)); 086 } 087 088 }