001    /**
002     * Houses13.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.rec13;
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.UserChoice;
026    import jcolibri.extensions.recommendation.conditionals.BuyOrQuit;
027    import jcolibri.extensions.recommendation.conditionals.ContinueOrFinish;
028    import jcolibri.extensions.recommendation.conditionals.DisplayCasesIfNumber;
029    import jcolibri.extensions.recommendation.navigationByProposing.CriticalUserChoice;
030    import jcolibri.extensions.recommendation.navigationByProposing.CritiqueOption;
031    import jcolibri.extensions.recommendation.navigationByProposing.DisplayCasesTableWithCritiquesMethod;
032    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis;
033    import jcolibri.extensions.recommendation.tabuList.TabuList;
034    import jcolibri.method.gui.formFilling.ObtainQueryWithFormMethod;
035    import jcolibri.method.retrieve.RetrievalResult;
036    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod;
037    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig;
038    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.NotEqual;
039    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryLess;
040    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMore;
041    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMoreOrEqual;
042    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Threshold;
043    import jcolibri.method.retrieve.NNretrieval.NNConfig;
044    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
045    import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
046    import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
047    import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
048    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter;
049    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
050    import jcolibri.method.retrieve.selection.compromiseDriven.CompromiseDrivenSelection;
051    import jcolibri.test.recommenders.housesData.HouseDescription;
052    
053    /**
054     * Conversational (type B) flats recommender using Navigation by Proposing and Filtering + Nearest Neighbour + Compromise Driven Selection.
055     * <br>
056     * This recommender follows the Navigation by Proposing strategy with two important features: it uses Compromise Driven selection after
057     * the NN scoring and it manages a tabu list of prevously displayed items.
058     * <br>
059     * The compromise driven selection method chooses cases according to their compromises with the user's query.
060     * See {@link jcolibri.method.retrieve.selection.compromiseDriven.CompromiseDrivenSelection} for details.
061     * <br>
062     * The tabu list avoids displaying again an item that has been already presented to the user. 
063     * See {@link jcolibri.extensions.recommendation.tabuList.TabuList} for details.
064     * <br>Summary:
065     * <ul>
066     * <li>Type: Conversational B
067     * <li>Case base: houses
068     * <li>One off Preference Elicitation: Form filling (with initial values)
069     * <li>Retrieval: Filtered + KNN + Compromise Driven selection 
070     * <li>Display: In table with critiques
071     * <li>Iterated Preference Elecitiation: Navigation by Proposing: MLT.
072     * </ul>
073     * This recommender implements the following template:<br>
074     * <center><img src="../Template11_Cycle.jpg"/></center>
075     * 
076     * <br>Read the documentation of the recommenders extension for details about templates
077     * and recommender strategies: {@link jcolibri.extensions.recommendation}
078     * 
079     * @see jcolibri.method.gui.formFilling.ObtainQueryWithFormMethod
080     * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod
081     * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod
082     * @see jcolibri.method.retrieve.selection.compromiseDriven.CompromiseDrivenSelection
083     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
084     * @see jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis
085     * 
086     * 
087     * @author Juan A. Recio-Garcia
088     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
089     * @version 1.0
090     */
091    public class Houses13 implements StandardCBRApplication
092    {
093        /** Connector object */
094        Connector _connector;
095        /** CaseBase object */
096        CBRCaseBase _caseBase;
097    
098        /** NN configuration*/
099        NNConfig simConfig;
100        
101        /** Obtain query configuration*/
102        Collection<Attribute> hiddenAtts;
103        /** Obtain query configuration*/
104        Map<Attribute,String> labels;
105        
106        /** Critiques configuration object */
107        Collection<CritiqueOption> critiques;
108        
109        /** CDR configuration */
110        FilterConfig preferences;
111        
112        public void configure() throws ExecutionException
113        {
114            // Create a data base connector
115            _connector = new PlainTextConnector();
116            // Init the ddbb connector with the config file
117            _connector.initFromXMLfile(jcolibri.util.FileIO
118                            .findFile("jcolibri/test/recommenders/housesData/plaintextconfig.xml"));
119            // Create a Lineal case base for in-memory organization
120            _caseBase = new LinealCaseBase();
121            
122            //Lets configure the KNN
123            simConfig = new NNConfig();
124            // Set the average() global similarity function for the description of the case
125            simConfig.setDescriptionSimFunction(new Average());
126            simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv"));
127            simConfig.addMapping(new Attribute("beds", HouseDescription.class), new InrecaMoreIsBetter(0.5));
128            simConfig.addMapping(new Attribute("price", HouseDescription.class), new InrecaLessIsBetter(2000, 0.5));
129            simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new Equal());
130            simConfig.addMapping(new Attribute("type", HouseDescription.class), new Equal());
131            simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5));
132    
133    
134            // Obtain query configuration
135            hiddenAtts = new ArrayList<Attribute>();
136            labels = new HashMap<Attribute,String>();
137            labels.put(new Attribute("beds", HouseDescription.class), "Min bedrooms");
138            labels.put(new Attribute("price", HouseDescription.class), "Approximate price");
139            labels.put(new Attribute("baths", HouseDescription.class), "Min bahtrooms");
140            
141            // Critiques configuration
142            critiques = new ArrayList<CritiqueOption>();
143            critiques.add(new CritiqueOption("More Beds",new Attribute("beds", HouseDescription.class),new QueryLess()));
144            critiques.add(new CritiqueOption("Cheaper",new Attribute("price", HouseDescription.class),new QueryMore()));
145            critiques.add(new CritiqueOption("More Bathrooms",new Attribute("baths", HouseDescription.class),new QueryLess()));
146            critiques.add(new CritiqueOption("Change Area",new Attribute("area", HouseDescription.class),new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal()));
147            critiques.add(new CritiqueOption("Another Area",new Attribute("area", HouseDescription.class),new NotEqual()));
148            
149            preferences = new FilterConfig();
150            preferences.addPredicate(new Attribute("beds", HouseDescription.class), new QueryMoreOrEqual());
151            preferences.addPredicate(new Attribute("price", HouseDescription.class), new Threshold(50));
152            preferences.addPredicate(new Attribute("baths", HouseDescription.class), new QueryMoreOrEqual());
153            preferences.addPredicate(new Attribute("furnished", HouseDescription.class), new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal());
154            preferences.addPredicate(new Attribute("type", HouseDescription.class), new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal());
155            
156        }
157    
158        public void cycle(CBRQuery query) throws ExecutionException
159        {   
160            // Obtain query with form filling
161            ObtainQueryWithFormMethod.obtainQueryWithInitialValues(query, hiddenAtts,labels);
162    
163            // Jump to main conversation
164            sequence1(query, new FilterConfig());
165    
166        }
167        
168        
169        public void sequence1(CBRQuery query, FilterConfig filterConfig)  throws ExecutionException
170        {   
171            // Execute Filter
172            Collection<CBRCase> filtered = FilterBasedRetrievalMethod.filterCases(_caseBase.getCases(), query, filterConfig);
173            
174            // Execute NN
175            Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(filtered, query, simConfig);
176            
177            // Select Cases
178            Collection<CBRCase> selectedCases = CompromiseDrivenSelection.CDR(query, retrievedCases, preferences);
179            
180            // Remove cases in Tabu List
181            selectedCases = TabuList.removeTabuList(selectedCases);
182    
183            if(DisplayCasesIfNumber.displayCasesWithMessage(Integer.MAX_VALUE, 1, selectedCases))
184                sequence2(selectedCases);
185            else
186                System.exit(0);
187            
188        }
189        
190        public void sequence2(Collection<CBRCase> selectedCases) throws ExecutionException
191        {
192            // Obtain critizied query
193            CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, _caseBase.getCases());
194    
195            // Update Tabu list
196            TabuList.updateTabuList(selectedCases);
197            
198            if(ContinueOrFinish.continueOrFinish(choice))
199                sequence3(choice.getSelectedCaseAsQuery(), choice);
200            else
201                sequence4(choice, selectedCases);
202            
203        }
204        
205        public void sequence3(CBRQuery query, CriticalUserChoice cuc) throws ExecutionException
206        {
207            // Replaze current query with the critizied one
208            MoreLikeThis.moreLikeThis(query, cuc.getSelectedCase());
209            
210            sequence1(query, cuc.getFilterConfig());
211        }
212        
213        public void sequence4(UserChoice choice, Collection<CBRCase> retrievedCases)  throws ExecutionException
214        {
215            if(BuyOrQuit.buyOrQuit(choice))
216                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
217            
218            else
219                System.out.println("Finish - User Quits");
220        }
221    
222        public void postCycle() throws ExecutionException
223        {
224        }
225    
226        public CBRCaseBase preCycle() throws ExecutionException
227        {
228            // Load cases from connector into the case base
229            _caseBase.init(_connector);             
230            // Print the cases
231            java.util.Collection<CBRCase> cases = _caseBase.getCases();
232            for(CBRCase c: cases)
233                    System.out.println(c);
234            return _caseBase;
235        }
236        
237        public static void main(String[] args) {
238            StandardCBRApplication recommender = new Houses13();
239            try
240            {
241                recommender.configure();
242                
243                recommender.preCycle();
244                
245                CBRQuery query = new CBRQuery();
246                
247                HouseDescription hd = new HouseDescription();
248                hd.setArea(HouseDescription.Area.Hampstead);
249                hd.setBaths(1);
250                hd.setBeds(HouseDescription.Beds.two);
251                hd.setFurnished(true);
252                hd.setPrice(500);
253                hd.setType(HouseDescription.Type.Flat);
254                query.setDescription(hd);
255                
256                recommender.cycle(query);
257                
258                recommender.postCycle();
259                
260                //System.exit(0);
261            } catch (Exception e)
262            {
263                org.apache.commons.logging.LogFactory.getLog(Houses13.class).error(e);
264                
265            }
266            
267    
268        }
269    
270    }