001    /**
002     * Houses5.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.rec5;
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.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod;
030    import jcolibri.extensions.recommendation.navigationByAsking.SimilarityInfluence;
031    import jcolibri.method.retrieve.RetrievalResult;
032    import jcolibri.method.retrieve.NNretrieval.NNConfig;
033    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
034    import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
035    import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
036    import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
037    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter;
038    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
039    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.McSherryMoreIsBetter;
040    import jcolibri.method.retrieve.selection.SelectCases;
041    import jcolibri.test.recommenders.housesData.HouseDescription;
042    
043    /**
044     * Conversational (type A) flats recommender using Navigation by Asking and KNN retrieval.
045     * <br>
046     * This recommender combines Navigation by Asking and Nearest Neighbour retrieval.
047     * To select the attribute asked to the user, it applies the Similarity Influence method.
048     * Then, the NN scoring method is executed and the retrieved items are presented to the
049     * user. If the user does not find the desired item, the system asks again for the value
050     * of another attribute.
051     * <br>
052     * Note!: the Similarity influence method runs very slowly. To speed up the execution, only
053     * 200 items are loaded.
054     * <br>Summary:
055     * <ul>
056     * <li>Type: Conversational A
057     * <li>Case base: houses
058     * <li>One off Preference Elicitation: Navigation by Asking using Similarity Influence (note: that method is very slow)
059     * <li>Retrieval: NN + topKselection
060     * <li>Display: In table
061     * <li>Iterated Preference Elecitiation: Navigation by Asking using Similarity Influence (note: that method is very slow)
062     * </ul>
063     * This recommender implements the following template:<br>
064     * <center><img src="../Template5_Cycle.jpg"/></center>
065     * 
066     * <br>Read the documentation of the recommenders extension for details about templates
067     * and recommender strategies: {@link jcolibri.extensions.recommendation}
068     * 
069     * @see jcolibri.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod
070     * @see jcolibri.extensions.recommendation.navigationByAsking.SimilarityInfluence
071     * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod
072     * @see jcolibri.method.retrieve.selection.SelectCases
073     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
074     * 
075     * @author Juan A. Recio-Garcia
076     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
077     * @version 1.0
078     */
079    public class Houses5 implements StandardCBRApplication
080    {
081        /** Connector object */
082        Connector _connector;
083        /** CaseBase object */
084        CBRCaseBase _caseBase;
085    
086        /** NN configuration*/
087        NNConfig simConfig;
088     
089        /** Obtain query configuration*/
090        Collection<Attribute> hiddenAtts;
091        /** Obtain query configuration*/
092        Map<Attribute,String> labels;
093        
094        //MODIFICATION TO SPEED UP THE EXECUTION
095        Collection<CBRCase> workingCases;
096        
097        public void configure() throws ExecutionException
098        {
099            // Create a data base connector
100            _connector = new PlainTextConnector();
101            // Init the ddbb connector with the config file
102            _connector.initFromXMLfile(jcolibri.util.FileIO
103                            .findFile("jcolibri/test/recommenders/housesData/plaintextconfig.xml"));
104            // Create a Lineal case base for in-memory organization
105            _caseBase = new LinealCaseBase();
106            
107            //Lets configure the KNN
108            simConfig = new NNConfig();
109            // Set the average() global similarity function for the description of the case
110            simConfig.setDescriptionSimFunction(new Average());
111            simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv"));
112            simConfig.addMapping(new Attribute("beds", HouseDescription.class), new McSherryMoreIsBetter(0,0));
113            simConfig.addMapping(new Attribute("price", HouseDescription.class), new InrecaLessIsBetter(2000, 0.5));
114            simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new Equal());
115            simConfig.addMapping(new Attribute("type", HouseDescription.class), new Equal());
116            simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5));
117    
118            
119            // Configure obtain query method
120            hiddenAtts = new ArrayList<Attribute>();
121            hiddenAtts.add(new Attribute("beds", HouseDescription.class));
122            labels = new HashMap<Attribute,String>();
123            labels.put(new Attribute("price", HouseDescription.class), "Max price");
124            labels.put(new Attribute("baths", HouseDescription.class), "Min bahtrooms");
125    
126        }
127    
128        public void cycle(CBRQuery query) throws ExecutionException
129        {   
130            // Select attribute using SimVar
131            Collection<CBRCase> loadedCases = _caseBase.getCases();
132            
133            // MODIFICATION TO SPEED UP THE EXECUTION
134            workingCases = new ArrayList<CBRCase>();
135            java.util.Iterator<CBRCase> iter = loadedCases.iterator();
136            for(int i=0; i<200; i++)
137                workingCases.add(iter.next());
138            // MODIFICATION END
139            
140            Attribute att = SimilarityInfluence.getMoreSimVarAttribute(workingCases,query, simConfig, true);
141    
142            // Obtain attribute value
143            ObtainQueryWithAttributeQuestionMethod.obtainQueryWithAttributeQuestion(query, att, labels, workingCases);
144    
145            // Go to main conversation cycle
146            sequence1(query);
147    
148        }
149        
150        
151        public void sequence1(CBRQuery query)  throws ExecutionException
152        {   
153            // Execute KNN
154            // MODIFICATION TO SPEED UP THE EXECUTION. Use _caseBase.getCases() insead working cases
155            // to use the whole case base.
156            Collection<RetrievalResult> eval = NNScoringMethod.evaluateSimilarity(workingCases, query, simConfig);
157            
158            // Select cases
159            Collection<CBRCase> retrievedCases = SelectCases.selectTopK(eval, 5);
160            
161            // Display cases
162            UserChoice choice = DisplayCasesTableMethod.displayCasesInTableEditQuery(retrievedCases);       
163    
164            if(ContinueOrFinish.continueOrFinish(choice))
165                sequence2(query);
166            else
167                sequence3(choice, retrievedCases);
168        }
169        
170        public void sequence2(CBRQuery query) throws ExecutionException
171        {
172            // Select attribute using SimVar
173            
174            // MODIFICATION TO SPEED UP THE EXECUTION. Use _caseBase.getCases() insead working cases
175            // to use the whole case base.
176            //Collection<CBRCase> workingCases = _caseBase.getCases();
177            
178            Attribute att = SimilarityInfluence.getMoreSimVarAttribute(workingCases,query, simConfig, true);
179    
180            // Obtain attribute value
181            ObtainQueryWithAttributeQuestionMethod.obtainQueryWithAttributeQuestion(query, att, labels, workingCases);
182    
183            // Go to main conversation cycle
184            sequence1(query);
185        }
186        
187        public void sequence3(UserChoice choice, Collection<CBRCase> retrievedCases)  throws ExecutionException
188        {
189            if(BuyOrQuit.buyOrQuit(choice))
190                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
191            
192            else
193                System.out.println("Finish - User Quits");
194        }
195    
196        public void postCycle() throws ExecutionException
197        {
198        }
199    
200        public CBRCaseBase preCycle() throws ExecutionException
201        {
202            // Load cases from connector into the case base
203            _caseBase.init(_connector);             
204            // Print the cases
205            java.util.Collection<CBRCase> cases = _caseBase.getCases();
206            for(CBRCase c: cases)
207                    System.out.println(c);
208            return _caseBase;
209        }
210        
211        public static void main(String[] args) {
212            
213            //SwingProgressBar shows the progress
214            jcolibri.util.ProgressController.clear();
215            jcolibri.util.ProgressController.register(new jcolibri.test.main.SwingProgressBar(), SimilarityInfluence.class);
216    
217            
218            StandardCBRApplication recommender = new Houses5();
219            try
220            {
221                recommender.configure();
222                
223                recommender.preCycle();
224                
225                CBRQuery query = new CBRQuery();
226                
227                HouseDescription hd = new HouseDescription();
228                
229                query.setDescription(hd);
230                
231                recommender.cycle(query);
232                
233                recommender.postCycle();
234                
235                //System.exit(0);
236            } catch (Exception e)
237            {
238                org.apache.commons.logging.LogFactory.getLog(Houses5.class).error(e);
239                
240            }
241            
242    
243        }
244    
245    }