001    /**
002     * Houses10.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.rec10;
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.navigationByProposing.CriticalUserChoice;
029    import jcolibri.extensions.recommendation.navigationByProposing.CritiqueOption;
030    import jcolibri.extensions.recommendation.navigationByProposing.DisplayCasesTableWithCritiquesMethod;
031    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis;
032    import jcolibri.method.retrieve.RetrievalResult;
033    import jcolibri.method.retrieve.DiverseByMedianRetrieval.ExpertClerkMedianScoring;
034    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod;
035    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig;
036    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.NotEqual;
037    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryLess;
038    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMore;
039    import jcolibri.method.retrieve.NNretrieval.NNConfig;
040    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
041    import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
042    import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
043    import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
044    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter;
045    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
046    import jcolibri.method.retrieve.selection.SelectCases;
047    import jcolibri.test.recommenders.housesData.HouseDescription;
048    
049    /**
050     * Conversational (type A) flats recommender using pre-selected cases at one-off preference elicitation, 
051     * Navigation By Proposing strategy and Filtering+NearestNeighbour+selectTopK retrieval.
052     * <br>
053     * This conversational recommender implements the Navigation by Proposing strategy. Instead of obtaining 
054     * the initial query asking to the user, it uses the Expert Clerk Median scoring algorithm to select
055     * k diverse cases that are directly presented to the user in the first iteration. Like other NbP 
056     * recommenders it uses critiques to filter the working set of items and computes the Nearest Neighbour
057     * scoring to obtain the displayed items.
058     * <br>Summary:
059     * <ul>
060     * <li>Type: Conversational A
061     * <li>Case base: houses
062     * <li>One off Preference Elicitation: k diverse cases chosen by ExpertClerkMedianScoring and shown in a table + critiques
063     * <li>Retrieval: Filtering + NN + topKselection
064     * <li>Display: In table with critiques
065     * <li>Iterated Preference Elecitiation: Navigation by Proposing: More Like This.
066     * </ul>
067     * This recommender implements the following template:<br>
068     * <center><img src="../Template10_Cycle.jpg"/></center>
069     * 
070     * <br>Read the documentation of the recommenders extension for details about templates
071     * and recommender strategies: {@link jcolibri.extensions.recommendation}
072     * 
073     * @see jcolibri.method.retrieve.DiverseByMedianRetrieval.ExpertClerkMedianScoring
074     * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod
075     * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod
076     * @see jcolibri.method.retrieve.selection.SelectCases
077     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
078     * @see jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis
079     * 
080     * 
081     * @see jcolibri.test.recommenders.rec6.Houses6
082     * @see jcolibri.test.recommenders.rec9.Houses9
083     * 
084     * @author Juan A. Recio-Garcia
085     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
086     * @version 1.0
087     */
088    public class Houses10 implements StandardCBRApplication
089    {
090        /** Connector object */
091        Connector _connector;
092        /** CaseBase object */
093        CBRCaseBase _caseBase;
094    
095        /** KNN configuration*/
096        NNConfig simConfig;
097        
098        /** Obtain query configuration*/
099        Collection<Attribute> hiddenAtts;
100        /** Obtain query configuration*/
101        Map<Attribute,String> labels;
102        
103        /** Critiques configuration object */
104        Collection<CritiqueOption> critiques;
105        
106        public void configure() throws ExecutionException
107        {
108            // Create a data base connector
109            _connector = new PlainTextConnector();
110            // Init the ddbb connector with the config file
111            _connector.initFromXMLfile(jcolibri.util.FileIO
112                            .findFile("jcolibri/test/recommenders/housesData/plaintextconfig.xml"));
113            // Create a Lineal case base for in-memory organization
114            _caseBase = new LinealCaseBase();
115            
116            //Lets configure the KNN
117            simConfig = new NNConfig();
118            // Set the average() global similarity function for the description of the case
119            simConfig.setDescriptionSimFunction(new Average());
120            simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv"));
121            simConfig.addMapping(new Attribute("beds", HouseDescription.class), new InrecaMoreIsBetter(0.5));
122            simConfig.addMapping(new Attribute("price", HouseDescription.class), new InrecaLessIsBetter(2000, 0.5));
123            simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new Equal());
124            simConfig.addMapping(new Attribute("type", HouseDescription.class), new Equal());
125            simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5));
126    
127    
128            // Obtain query configuration
129            hiddenAtts = new ArrayList<Attribute>();
130            labels = new HashMap<Attribute,String>();
131            labels.put(new Attribute("beds", HouseDescription.class), "Min bedrooms");
132            labels.put(new Attribute("price", HouseDescription.class), "Max price");
133            labels.put(new Attribute("baths", HouseDescription.class), "Min bahtrooms");
134            
135            // Critiques configuration
136            critiques = new ArrayList<CritiqueOption>();
137            critiques.add(new CritiqueOption("More Beds",new Attribute("beds", HouseDescription.class),new QueryLess()));
138            critiques.add(new CritiqueOption("Cheaper",new Attribute("price", HouseDescription.class),new QueryMore()));
139            critiques.add(new CritiqueOption("More Bathrooms",new Attribute("baths", HouseDescription.class),new QueryLess()));
140            critiques.add(new CritiqueOption("Change Area",new Attribute("area", HouseDescription.class),new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal()));
141            critiques.add(new CritiqueOption("Another Area",new Attribute("area", HouseDescription.class),new NotEqual()));
142        }
143    
144        public void cycle(CBRQuery query) throws ExecutionException
145        {   
146            HashMap<Attribute,Double> thresholds = new HashMap<Attribute,Double>();
147            thresholds.put(new Attribute("beds", HouseDescription.class), 2.0);
148            thresholds.put(new Attribute("price", HouseDescription.class), 300.0);
149            thresholds.put(new Attribute("baths", HouseDescription.class), 2.0);
150            thresholds.put(new Attribute("area", HouseDescription.class), 0.99);
151            thresholds.put(new Attribute("type", HouseDescription.class), 0.99);
152            
153            // Retrieve Cases
154            Collection<RetrievalResult> retrievedCases = ExpertClerkMedianScoring.getDiverseByMedian(_caseBase.getCases(), simConfig, thresholds);
155            
156            // Select Cases
157            Collection<CBRCase> selectedCases = SelectCases.selectTopK(retrievedCases, 5);
158            
159            // Display Cases
160            CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, _caseBase.getCases());
161    
162            // Jump to main conversation
163            sequence1(choice.getSelectedCaseAsQuery(), choice.getFilterConfig());
164    
165        }
166        
167        
168        public void sequence1(CBRQuery query, FilterConfig filterConfig)  throws ExecutionException
169        {   
170            // Execute Filter
171            Collection<CBRCase> filtered = FilterBasedRetrievalMethod.filterCases(_caseBase.getCases(), query, filterConfig);
172            
173            // Execute NN
174            Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(filtered, query, simConfig);
175            
176            // Select cases
177            Collection<CBRCase> selectedCases = SelectCases.selectTopK(retrievedCases, 5);
178            
179            // Obtain critizied query
180            CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, _caseBase.getCases());
181            
182            if(ContinueOrFinish.continueOrFinish(choice))
183                sequence2(query,choice);
184            else
185                sequence3(choice, selectedCases);
186        }
187        
188        public void sequence2(CBRQuery query, CriticalUserChoice cuc) throws ExecutionException
189        {
190            // Replace current query with the critizied one
191            MoreLikeThis.moreLikeThis(query, cuc.getSelectedCase());
192            sequence1(query,cuc.getFilterConfig());
193        }
194        
195        public void sequence3(UserChoice choice, Collection<CBRCase> retrievedCases)  throws ExecutionException
196        {
197            if(BuyOrQuit.buyOrQuit(choice))
198                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
199            
200            else
201                System.out.println("Finish - User Quits");
202        }
203    
204        public void postCycle() throws ExecutionException
205        {
206        }
207    
208        public CBRCaseBase preCycle() throws ExecutionException
209        {
210            // Load cases from connector into the case base
211            _caseBase.init(_connector);             
212            // Print the cases
213            java.util.Collection<CBRCase> cases = _caseBase.getCases();
214            for(CBRCase c: cases)
215                    System.out.println(c);
216            return _caseBase;
217        }
218        
219        public static void main(String[] args) {
220            StandardCBRApplication recommender = new Houses10();
221            try
222            {
223                recommender.configure();
224                
225                recommender.preCycle();
226                
227                CBRQuery query = new CBRQuery();
228                
229                HouseDescription hd = new HouseDescription();
230                
231                query.setDescription(hd);
232                
233                recommender.cycle(query);
234                
235                recommender.postCycle();
236                
237            } catch (Exception e)
238            {
239                org.apache.commons.logging.LogFactory.getLog(Houses10.class).error(e);
240                
241            }
242            
243    
244        }
245    
246    }