001    /**
002     * Houses2.java
003     * jCOLIBRI2 framework. 
004     * @author Juan A. Recio-García.
005     * GAIA - Group for Artificial Intelligence Applications
006     * http://gaia.fdi.ucm.es
007     * 23/10/2007
008     */
009    package jcolibri.test.recommenders.rec2;
010    
011    import java.util.ArrayList;
012    import java.util.Collection;
013    import java.util.HashMap;
014    import java.util.Map;
015    
016    import jcolibri.casebase.LinealCaseBase;
017    import jcolibri.cbraplications.StandardCBRApplication;
018    import jcolibri.cbrcore.Attribute;
019    import jcolibri.cbrcore.CBRCase;
020    import jcolibri.cbrcore.CBRCaseBase;
021    import jcolibri.cbrcore.CBRQuery;
022    import jcolibri.cbrcore.Connector;
023    import jcolibri.connector.PlainTextConnector;
024    import jcolibri.exception.ExecutionException;
025    import jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod;
026    import jcolibri.extensions.recommendation.casesDisplay.UserChoice;
027    import jcolibri.extensions.recommendation.conditionals.BuyOrQuit;
028    import jcolibri.extensions.recommendation.conditionals.ContinueOrFinish;
029    import jcolibri.method.gui.formFilling.ObtainQueryWithFormMethod;
030    import jcolibri.method.retrieve.RetrievalResult;
031    import jcolibri.method.retrieve.NNretrieval.NNConfig;
032    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
033    import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
034    import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
035    import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
036    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter;
037    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
038    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.McSherryMoreIsBetter;
039    import jcolibri.method.retrieve.selection.SelectCases;
040    import jcolibri.test.recommenders.housesData.HouseDescription;
041    
042    /**
043     * Conversational (type A) flats recommender using form-filling, Nearest Neighbour retrieval and top k selection .
044     * <br>
045     * This recommender obtains the user preferences using a form. Then it computes 
046     * Nearest Neighbour scoring to obtain the most similar cases. 
047     * If the user does not find the desired item, he/she can refine the requirements
048     * using again a form. The form contains initial values and some attributes are
049     * hidden (defined by the designer).
050     * <br>Summary:
051     * <ul>
052     * <li>Type: Conversational A
053     * <li>Case base: houses
054     * <li>One off Preference Elicitation: Form Filling with initial values, hidden attributes and custom labels
055     * <li>Retrieval: Nearest Neighbour + topKselection
056     * <li>Display: In table
057     * <li>Iterated Preference Elecitiation: Form Filling with initial values, hidden attributes and custom labels
058     * </ul>
059     * This recommender implements the following template:<br>
060     * <center><img src="../Template2_Cycle.jpg"/></center>
061     * 
062     * <br>Read the documentation of the recommenders extension for details about templates
063     * and recommender strategies: {@link jcolibri.extensions.recommendation}
064     * 
065     * @see jcolibri.method.gui.formFilling.ObtainQueryWithFormMethod
066     * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod
067     * @see jcolibri.method.retrieve.selection.SelectCases
068     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
069     * 
070     * @author Juan A. Recio-Garcia
071     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
072     * @version 1.0
073     */
074    public class Houses2 implements StandardCBRApplication
075    {
076        /** Connector object */
077        Connector _connector;
078        /** CaseBase object */
079        CBRCaseBase _caseBase;
080    
081        /** KNN Config */
082        NNConfig simConfig;
083        
084        /** Configuration objects for obtain query */
085        Collection<Attribute> hiddenAtts;
086        /** Configuration objects for obtain query */
087        Map<Attribute,String> labels;
088        
089        public void configure() throws ExecutionException
090        {
091            // Create a data base connector
092            _connector = new PlainTextConnector();
093            // Init the ddbb connector with the config file
094            _connector.initFromXMLfile(jcolibri.util.FileIO
095                            .findFile("jcolibri/test/recommenders/housesData/plaintextconfig.xml"));
096            // Create a Lineal case base for in-memory organization
097            _caseBase = new LinealCaseBase();
098    
099            //Configure the KNN
100            simConfig = new NNConfig();
101            // Set the average() global similarity function for the description of the case
102            simConfig.setDescriptionSimFunction(new Average());
103            simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv"));
104            simConfig.addMapping(new Attribute("beds", HouseDescription.class), new McSherryMoreIsBetter(0,0));
105            simConfig.addMapping(new Attribute("price", HouseDescription.class), new InrecaLessIsBetter(2000, 0.5));
106            simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new Equal());
107            simConfig.addMapping(new Attribute("type", HouseDescription.class), new Equal());
108            simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5));
109    
110            
111            // Configuration objects for obtain query
112            hiddenAtts = new ArrayList<Attribute>();
113            hiddenAtts.add(new Attribute("beds", HouseDescription.class));
114            labels = new HashMap<Attribute,String>();
115            labels.put(new Attribute("price", HouseDescription.class), "Max price");
116            labels.put(new Attribute("baths", HouseDescription.class), "Min bahtrooms");
117        }
118    
119        public void cycle(CBRQuery query) throws ExecutionException
120        {   
121            //Obtain the query
122            ObtainQueryWithFormMethod.obtainQueryWithInitialValues(query,hiddenAtts,labels);
123    
124            //Jump to converstaion cycle
125            sequence1(query);
126        }
127        
128        
129        public void sequence1(CBRQuery query)
130        {
131            // Execute KNN
132            Collection<RetrievalResult> eval = NNScoringMethod.evaluateSimilarity(_caseBase.getCases(), query, simConfig);
133            
134            // Select cases
135            Collection<CBRCase> retrievedCases = SelectCases.selectTopK(eval, 5);
136            
137            // Display cases
138            UserChoice choice = DisplayCasesTableMethod.displayCasesInTableEditQuery(retrievedCases);       
139    
140            // Continue or Finish
141            if(ContinueOrFinish.continueOrFinish(choice))
142                sequence2(query);
143            else
144                sequence3(choice, retrievedCases);
145        }
146        
147        public void sequence2(CBRQuery query)
148        {
149            // Obtain query again
150            ObtainQueryWithFormMethod.obtainQueryWithInitialValues(query,hiddenAtts,labels);
151            
152            // Jump to conversation cycle
153            sequence1(query);
154        }
155        
156        
157        public void sequence3(UserChoice choice, Collection<CBRCase> retrievedCases)
158        {
159            // Finishing: buy or quit
160            if(BuyOrQuit.buyOrQuit(choice))
161                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
162            
163            else
164                System.out.println("Finish - User Quits");
165        }
166    
167        public void postCycle() throws ExecutionException
168        {
169        }
170    
171        public CBRCaseBase preCycle() throws ExecutionException
172        {
173            // Load cases from connector into the case base
174            _caseBase.init(_connector);             
175            // Print the cases
176            java.util.Collection<CBRCase> cases = _caseBase.getCases();
177            for(CBRCase c: cases)
178                    System.out.println(c);
179            return _caseBase;
180        }
181        
182        public static void main(String[] args) {
183            StandardCBRApplication recommender = new Houses2();
184            try
185            {
186                recommender.configure();
187                
188                recommender.preCycle();
189                
190                CBRQuery query = new CBRQuery();
191                
192                HouseDescription hd = new HouseDescription();
193                hd.setArea(HouseDescription.Area.Hampstead);
194                hd.setBaths(1);
195                hd.setBeds(HouseDescription.Beds.two);
196                hd.setFurnished(true);
197                hd.setPrice(500);
198                hd.setType(HouseDescription.Type.Flat);
199                
200                query.setDescription(hd);
201                
202                recommender.cycle(query);
203                
204                recommender.postCycle();
205                
206                //System.exit(0);
207            } catch (Exception e)
208            {
209                org.apache.commons.logging.LogFactory.getLog(Houses2.class).error(e);
210                
211            }
212            
213    
214        }
215    
216    }