001    /**
002     * Houses11.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.rec11;
010    
011    import java.util.Collection;
012    import java.util.HashMap;
013    import jcolibri.casebase.LinealCaseBase;
014    import jcolibri.cbraplications.StandardCBRApplication;
015    import jcolibri.cbrcore.Attribute;
016    import jcolibri.cbrcore.CBRCase;
017    import jcolibri.cbrcore.CBRCaseBase;
018    import jcolibri.cbrcore.CBRQuery;
019    import jcolibri.cbrcore.Connector;
020    import jcolibri.connector.PlainTextConnector;
021    import jcolibri.exception.ExecutionException;
022    import jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod;
023    import jcolibri.extensions.recommendation.casesDisplay.UserChoice;
024    import jcolibri.extensions.recommendation.conditionals.BuyOrQuit;
025    import jcolibri.extensions.recommendation.conditionals.ContinueOrFinish;
026    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.LessLikeThis;
027    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreAndLessLikeThis;
028    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis;
029    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.PartialMoreLikeThis;
030    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.WeightedMoreLikeThis;
031    import jcolibri.method.retrieve.RetrievalResult;
032    import jcolibri.method.retrieve.DiverseByMedianRetrieval.ExpertClerkMedianScoring;
033    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod;
034    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig;
035    import jcolibri.method.retrieve.NNretrieval.NNConfig;
036    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
037    import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
038    import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
039    import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
040    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter;
041    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
042    import jcolibri.method.retrieve.selection.SelectCases;
043    import jcolibri.test.recommenders.housesData.HouseDescription;
044    
045    /**
046     * Conversational (type A) flats recommender using pre-selected cases at one-off preference elicitation, 
047     * Navigation By Proposing and Filtering+NearestNeighbour+selectTopK retrieval.
048     * <br>
049     * This recommender follows the Navigation by Proposing strategy and shows the behaviour of several methods
050     * that solve the <i>Iterated Preference Elecitiation</i> task that defines how to modify the user preferences.
051     * There are several methods to obtain a new query from the user selections and critiques: 
052     * <ul>
053     *  <li>More Like This ({@link jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis})
054     *  <li>partial More Like This ({@link jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.PartialMoreLikeThis})
055     *  <li>weighted More Like ({@link jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.WeightedMoreLikeThis})
056     *  <li>Less Like This ({@link jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.LessLikeThis})
057     *  <li>More Like This + Less Like This ({@link jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreAndLessLikeThis})
058     * <ul>
059     * Modifying the code, the Iterated Preference Elecitiation strategy can be defined before running the example.
060     * <br>Summary:
061     * <ul>
062     * <li>Type: Conversational A
063     * <li>Case base: houses
064     * <li>One off Preference Elicitation: k diverse cases chosen by ExpertClerkMedianScoring and shown in a table + critiques
065     * <li>Retrieval: Filtering + NN + topKselection
066     * <li>Display: In table with find something similar option
067     * <li>Iterated Preference Elecitiation: Navigation by Proposing: by default MLT+LLT. Modifying the code, the replace query strategy can be defined before running the example.
068     * </ul>
069     * This recommender implements the following template:<br>
070     * <center><img src="../Template10_Cycle.jpg"/></center>
071     *  
072     * <br>Read the documentation of the recommenders extension for details about templates
073     * and recommender strategies: {@link jcolibri.extensions.recommendation}
074     * 
075     * @see jcolibri.method.retrieve.DiverseByMedianRetrieval.ExpertClerkMedianScoring
076     * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod
077     * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod
078     * @see jcolibri.method.retrieve.selection.SelectCases
079     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
080     * 
081     * 
082     * @author Juan A. Recio-Garcia
083     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
084     * @version 1.0
085     */
086    public class Houses11 implements StandardCBRApplication
087    {
088        enum QueryElicitationStrategy {MLT, pMLT, wMLT, LLT, MLT_LLT};
089        
090        private QueryElicitationStrategy strategy;
091        
092        /** Connector object */
093        Connector _connector;
094        /** CaseBase object */
095        CBRCaseBase _caseBase;
096    
097        /** KNN configuration*/
098        NNConfig simConfig;
099        /** Filter configuration */
100        FilterConfig filterConfig;
101    
102    
103        
104        public void configure() throws ExecutionException
105        {
106            // Create a data base connector
107            _connector = new PlainTextConnector();
108            // Init the ddbb connector with the config file
109            _connector.initFromXMLfile(jcolibri.util.FileIO
110                            .findFile("jcolibri/test/recommenders/housesData/plaintextconfig.xml"));
111            // Create a Lineal case base for in-memory organization
112            _caseBase = new LinealCaseBase();
113            
114            //Lets configure the KNN
115            simConfig = new NNConfig();
116            // Set the average() global similarity function for the description of the case
117            simConfig.setDescriptionSimFunction(new Average());
118            simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv"));
119            simConfig.addMapping(new Attribute("beds", HouseDescription.class), new InrecaMoreIsBetter(0.5));
120            simConfig.addMapping(new Attribute("price", HouseDescription.class), new InrecaLessIsBetter(2000, 0.5));
121            simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new Equal());
122            simConfig.addMapping(new Attribute("type", HouseDescription.class), new Equal());
123            simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5));
124    
125            // Filter configuration
126            filterConfig = new FilterConfig();
127            
128            /*// UNCOMMENT THIS CODE TO DEFINE THE ITERATED PREFERENCE ELECITATION BEFORE RUNNING THE EXAMPLE
129             Object[] possibleValues = QueryElicitationStrategy.values();
130             strategy = (QueryElicitationStrategy)JOptionPane.showInputDialog(null,
131                         "Choose one strategy for the example", "Choose strategy",
132                         JOptionPane.INFORMATION_MESSAGE, null,
133                         possibleValues, possibleValues[0]);
134            */ 
135            strategy = QueryElicitationStrategy.MLT_LLT;
136        }
137    
138        public void cycle(CBRQuery query) throws ExecutionException
139        {   
140            HashMap<Attribute,Double> thresholds = new HashMap<Attribute,Double>();
141            thresholds.put(new Attribute("beds", HouseDescription.class), 2.0);
142            thresholds.put(new Attribute("price", HouseDescription.class), 300.0);
143            thresholds.put(new Attribute("baths", HouseDescription.class), 2.0);
144            thresholds.put(new Attribute("area", HouseDescription.class), 0.99);
145            thresholds.put(new Attribute("type", HouseDescription.class), 0.99);
146            
147            // Retrieve Cases
148            Collection<RetrievalResult> retrievedCases = ExpertClerkMedianScoring.getDiverseByMedian(_caseBase.getCases(), simConfig, thresholds);
149            
150            // Select Cases
151            Collection<CBRCase> selectedCases = SelectCases.selectTopK(retrievedCases, 5);
152                    
153            UserChoice choice = DisplayCasesTableMethod.displayCasesInTableSelectCase(selectedCases); 
154    
155            // Jump to main conversation
156            sequence1(choice.getSelectedCaseAsQuery());
157    
158        }
159        
160        
161        public void sequence1(CBRQuery query)  throws ExecutionException
162        {   
163            // Execute Filter
164            Collection<CBRCase> filtered = FilterBasedRetrievalMethod.filterCases(_caseBase.getCases(), query, filterConfig);
165            
166            // Execute NN
167            Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(filtered, query, simConfig);
168            
169            // Select cases
170            Collection<CBRCase> selectedCases = SelectCases.selectTopK(retrievedCases, 10);
171            
172            System.out.println("Retrieved cases");
173            for(CBRCase c: selectedCases)
174                System.out.println(c);
175            
176            // Obtain case
177            UserChoice choice = DisplayCasesTableMethod.displayCasesInTableSelectCase(selectedCases);
178            
179            if(ContinueOrFinish.continueOrFinish(choice))
180                sequence2(query,choice,selectedCases);
181            else
182                sequence3(choice, selectedCases);
183        }
184        
185        public void sequence2(CBRQuery query, UserChoice uc, Collection<CBRCase> proposedCases) throws ExecutionException
186        {
187            if(strategy == QueryElicitationStrategy.MLT)
188                MoreLikeThis.moreLikeThis(query, uc.getSelectedCase());
189            else if(strategy == QueryElicitationStrategy.pMLT)
190                PartialMoreLikeThis.partialMoreLikeThis(query, uc.getSelectedCase(), proposedCases);
191            else if(strategy == QueryElicitationStrategy.wMLT)
192                WeightedMoreLikeThis.weightedMoreLikeThis(query, uc.getSelectedCase(), proposedCases, simConfig);
193            else if(strategy == QueryElicitationStrategy.LLT)
194                LessLikeThis.lessLikeThis(query, uc.getSelectedCase(), proposedCases, filterConfig);
195            else if(strategy == QueryElicitationStrategy.MLT_LLT)
196                MoreAndLessLikeThis.moreAndLessLikeThis(query, uc.getSelectedCase(), proposedCases, filterConfig);
197             
198            sequence1(query);
199        }
200        
201        public void sequence3(UserChoice choice, Collection<CBRCase> retrievedCases)  throws ExecutionException
202        {
203            if(BuyOrQuit.buyOrQuit(choice))
204                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
205            
206            else
207                System.out.println("Finish - User Quits");
208        }
209    
210        public void postCycle() throws ExecutionException
211        {
212        }
213    
214        public CBRCaseBase preCycle() throws ExecutionException
215        {
216            // Load cases from connector into the case base
217            _caseBase.init(_connector);             
218            // Print the cases
219            java.util.Collection<CBRCase> cases = _caseBase.getCases();
220            for(CBRCase c: cases)
221                    System.out.println(c);
222            return _caseBase;
223        }
224        
225        public static void main(String[] args) {
226            StandardCBRApplication recommender = new Houses11();
227            try
228            {
229                recommender.configure();
230                
231                recommender.preCycle();
232                
233                CBRQuery query = new CBRQuery();
234                
235                HouseDescription hd = new HouseDescription();
236                
237                query.setDescription(hd);
238                
239                recommender.cycle(query);
240                
241                recommender.postCycle();
242                
243                //System.exit(0);
244            } catch (Exception e)
245            {
246                org.apache.commons.logging.LogFactory.getLog(Houses11.class).error(e);
247                
248            }
249            
250    
251        }
252    
253    }