001    /**
002     * Houses8.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.rec8;
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.askingAndProposing.AskingAndProposingPreferenceElicitation;
026    import jcolibri.extensions.recommendation.askingAndProposing.DisplayCasesIfNumberAndChangeNavigation;
027    import jcolibri.extensions.recommendation.casesDisplay.UserChoice;
028    import jcolibri.extensions.recommendation.conditionals.BuyOrQuit;
029    import jcolibri.extensions.recommendation.conditionals.ContinueOrFinish;
030    import jcolibri.extensions.recommendation.navigationByAsking.InformationGain;
031    import jcolibri.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod;
032    import jcolibri.extensions.recommendation.navigationByAsking.SelectAttributeMethod;
033    import jcolibri.extensions.recommendation.navigationByProposing.CriticalUserChoice;
034    import jcolibri.extensions.recommendation.navigationByProposing.CritiqueOption;
035    import jcolibri.extensions.recommendation.navigationByProposing.DisplayCasesTableWithCritiquesMethod;
036    import jcolibri.method.retrieve.RetrievalResult;
037    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod;
038    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig;
039    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal;
040    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.NotEqual;
041    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryLess;
042    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMore;
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.EnumDistance;
047    import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
048    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
049    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.McSherryMoreIsBetter;
050    import jcolibri.method.retrieve.selection.diversity.BoundedGreedySelection;
051    import jcolibri.test.recommenders.rec8.housesData.HouseDescription;
052    
053    /**
054     * Conversational (type B) flats recommender using both Navigation by Asking and Navigation by Proposing.
055     * <br>
056     * This example reproduces the behaviour of the ExpertClerk system. It works as a Navigation by Asking system until the number
057     * of cases is small enough and then it changes to Navigation by Proposing.
058     * <p>See:
059     * <p>
060     * H. Shimazu. ExpertClerk: A Conversational Case-Based Reasoning Tool for 
061     * Developing Salesclerk Agents in E-Commerce Webshops. Artif. Intell. Rev., 
062     * 18(3-4):223-244, 2002.
063     * <p>
064     * <br>Summary:
065     * <ul>
066     * <li>Type: Conversational B.
067     * <li>Case base: houses2 (price moved to the solution and priceRange in the description).
068     * <li>One off Preference Elicitation: Navigation by Asking using Information Gain.
069     * <li>Retrieval: Filter-Based
070     * <li>Display Condition: number of cases. If the number of cases is less than a value it changes the Iterated Preference Elicitation to NbP
071     * <li>Display: In table with critiques. (Cases are only shown in NbP mode)
072     * <li>Iterated Preference Elicitation: Depends on the mode. The method AskingAndProposingPreferenceElicitation selects an attribute 
073     * using InformationGain in NbA mode or simply replaces current query with the critizied one in NbP.
074     * </ul>
075     * This recommender implements the following template:<br>
076     * <center><img src="../Template8_Cycle.jpg"/></center>
077     * 
078     * <br>Read the documentation of the recommenders extension for details about templates
079     * and recommender strategies: {@link jcolibri.extensions.recommendation}
080     * 
081     * @see jcolibri.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod
082     * @see jcolibri.extensions.recommendation.navigationByAsking.InformationGain
083     * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod
084     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
085     * @see jcolibri.extensions.recommendation.askingAndProposing.DisplayCasesIfNumberAndChangeNavigation
086     * @see jcolibri.method.retrieve.selection.diversity.BoundedGreedySelection
087     * 
088     * @author Juan A. Recio-Garcia
089     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
090     * @version 1.0
091     */
092    public class Houses8 implements StandardCBRApplication
093    {
094        /** Connector object */
095        Connector _connector;
096        /** CaseBase object */
097        CBRCaseBase _caseBase;
098    
099        FilterConfig filterConfig;  
100        NNConfig simConfig;
101        SelectAttributeMethod selectAttributeMethod;
102        Collection<CritiqueOption> critiques;
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/rec8/housesData/plaintextconfig.xml"));
111            // Create a Lineal case base for in-memory organization
112            _caseBase = new LinealCaseBase();
113            
114    
115            filterConfig = new FilterConfig();
116            filterConfig.addPredicate(new Attribute("area", HouseDescription.class), new Equal());
117            filterConfig.addPredicate(new Attribute("beds", HouseDescription.class), new Equal());
118            filterConfig.addPredicate(new Attribute("priceRange", HouseDescription.class), new Equal());
119            filterConfig.addPredicate(new Attribute("furnished", HouseDescription.class), new Equal());
120            filterConfig.addPredicate(new Attribute("type", HouseDescription.class), new Equal());
121            filterConfig.addPredicate(new Attribute("baths", HouseDescription.class), new Equal());
122    
123            //Lets configure the KNN
124            simConfig = new NNConfig();
125            // Set the average() global similarity function for the description of the case
126            simConfig.setDescriptionSimFunction(new Average());
127            simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv"));
128            simConfig.addMapping(new Attribute("beds", HouseDescription.class), new McSherryMoreIsBetter(0,0));
129            simConfig.addMapping(new Attribute("priceRange", HouseDescription.class), new EnumDistance());
130            simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new jcolibri.method.retrieve.NNretrieval.similarity.local.Equal());
131            simConfig.addMapping(new Attribute("type", HouseDescription.class), new jcolibri.method.retrieve.NNretrieval.similarity.local.Equal());
132            simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5));
133            
134            selectAttributeMethod = new InformationGain(_caseBase.getCases()); 
135            
136            
137            critiques = new ArrayList<CritiqueOption>();
138            critiques.add(new CritiqueOption("More Beds",new Attribute("beds", HouseDescription.class),new QueryLess()));
139            critiques.add(new CritiqueOption("Cheaper",new Attribute("priceRange", HouseDescription.class),new QueryMore()));
140            critiques.add(new CritiqueOption("More Bathrooms",new Attribute("baths", HouseDescription.class),new QueryLess()));
141            critiques.add(new CritiqueOption("Change Area",new Attribute("area", HouseDescription.class),new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal()));
142            critiques.add(new CritiqueOption("Another Area",new Attribute("area", HouseDescription.class),new NotEqual()));
143            
144            
145        }
146    
147        public void cycle(CBRQuery query) throws ExecutionException
148        {   
149            Attribute att = selectAttributeMethod.getAttribute(_caseBase.getCases(), query);
150            
151            Map<Attribute,String> labels = new HashMap<Attribute,String>();
152            ObtainQueryWithAttributeQuestionMethod.obtainQueryWithAttributeQuestion(query, att, labels, _caseBase.getCases());
153    
154            sequence1(query, _caseBase.getCases(), filterConfig);
155    
156        }
157        
158        
159        public void sequence1(CBRQuery query, Collection<CBRCase> cases, FilterConfig fc)  throws ExecutionException
160        {
161            Collection<CBRCase> workingCases =  FilterBasedRetrievalMethod.filterCases(cases, query, fc);
162            
163            if(DisplayCasesIfNumberAndChangeNavigation.displayCasesIfNumberAndChangeNavigation(50, workingCases))
164                sequence2(query, workingCases);
165            else
166                sequence3(query, workingCases, null);
167        }
168        
169        public void sequence2(CBRQuery query, Collection<CBRCase> workingCases)  throws ExecutionException
170        {
171            Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(workingCases, query, simConfig);
172            
173            Collection<CBRCase> selectedCases = BoundedGreedySelection.boundedGreddySelection(retrievedCases, query, simConfig,3,3);
174            
175            CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, workingCases);
176    
177            if(ContinueOrFinish.continueOrFinish(choice))
178                sequence3(query,workingCases, choice);
179            else
180                sequence4(choice, workingCases);
181        }
182        
183        public void sequence3(CBRQuery query, Collection<CBRCase> workingCases, CriticalUserChoice choice)  throws ExecutionException
184        {
185            AskingAndProposingPreferenceElicitation.doPreferenceElicitation(query, workingCases, selectAttributeMethod, choice);
186            if(choice != null)
187                sequence1(query, workingCases, choice.getFilterConfig());
188            else
189                sequence1(query, workingCases, filterConfig);
190        }
191        
192        public void sequence4(UserChoice choice, Collection<CBRCase> workingCases)  throws ExecutionException
193        {
194            if(BuyOrQuit.buyOrQuit(choice))
195                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
196            
197            else
198                System.out.println("Finish - User Quits");
199        }
200    
201        public void postCycle() throws ExecutionException
202        {
203        }
204    
205        public CBRCaseBase preCycle() throws ExecutionException
206        {
207            // Load cases from connector into the case base
208            _caseBase.init(_connector);             
209            // Print the cases
210            java.util.Collection<CBRCase> cases = _caseBase.getCases();
211            for(CBRCase c: cases)
212                    System.out.println(c);
213            return _caseBase;
214        }
215        
216        public static void main(String[] args) {
217            StandardCBRApplication recommender = new Houses8();
218            try
219            {
220                recommender.configure();
221                
222                recommender.preCycle();
223                
224                CBRQuery query = new CBRQuery();
225                
226                HouseDescription hd = new HouseDescription();
227                //hd.setArea("Hampstead");
228                //hd.setBaths(1);
229                //hd.setBeds(HouseDescription.Beds.two);
230                //hd.setFurnished(true);
231                //hd.setPrice(500);
232                //hd.setType(HouseDescription.Type.Flat);
233                
234                query.setDescription(hd);
235                
236                recommender.cycle(query);
237                
238                //System.exit(0);
239            } catch (Exception e)
240            {
241                org.apache.commons.logging.LogFactory.getLog(Houses8.class).error(e);
242                
243            }
244            
245    
246        }
247    
248    }