001    /**
002     * Houses4.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.rec4;
010    
011    import java.util.Collection;
012    import java.util.HashMap;
013    import java.util.Map;
014    
015    import jcolibri.casebase.LinealCaseBase;
016    import jcolibri.cbraplications.StandardCBRApplication;
017    import jcolibri.cbrcore.Attribute;
018    import jcolibri.cbrcore.CBRCase;
019    import jcolibri.cbrcore.CBRCaseBase;
020    import jcolibri.cbrcore.CBRQuery;
021    import jcolibri.cbrcore.Connector;
022    import jcolibri.connector.PlainTextConnector;
023    import jcolibri.exception.ExecutionException;
024    import jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod;
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.navigationByAsking.InformationGain;
030    import jcolibri.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod;
031    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod;
032    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig;
033    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal;
034    import jcolibri.test.recommenders.rec4.housesData.HouseDescription;
035    
036    /**
037     * Conversational (type B) flats recommender using Navigation by Asking and Filter retrieval.
038     * <br>
039     * This recommender applies the Navigation by Asking strategy to obtain the user requirements. 
040     * This strategy selects an attribute of the items to be asked to the user each iteration. Depending on
041     * the values of these attributes a retrieval set is obtained using filtering. 
042     * If the retrieval set is small enough it is presented to the user. If it is too big or
043     * the user does not find the desired item, the recommender uses again the Navigation by
044     * Asking strategy to improve the user requirements.
045     * <br>Summary:
046     * <ul>
047     * <li>Type: Conversational B.
048     * <li>Case base: houses2 (price moved to the solution and priceRange in the description).
049     * <li>One off Preference Elicitation: Navigation by Asking using Information Gain.
050     * <li>Retrieval: Filter (in NbA only Equal() predicates are allowed).
051     * <li>Display Condition: number of cases (not showing messages).
052     * <li>Display: In table. "Edit Query" enabled if there are more attributes to ask.
053     * <li>Iterated Preference Elicitation: Navigation by Asking using Information Gain.
054     * </ul>
055     * This recommender implements the following template:<br>
056     * <center><img src="../Template4_Cycle.jpg"/></center>
057     * 
058     * <br>Read the documentation of the recommenders extension for details about templates
059     * and recommender strategies: {@link jcolibri.extensions.recommendation}
060     * 
061     * @see jcolibri.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod
062     * @see jcolibri.extensions.recommendation.navigationByAsking.InformationGain
063     * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod
064     * @see jcolibri.extensions.recommendation.conditionals.DisplayCasesIfNumber
065     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
066     * 
067     * @author Juan A. Recio-Garcia
068     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
069     * @version 1.0
070     */
071    public class Houses4 implements StandardCBRApplication
072    {
073        /** Connector object */
074        Connector _connector;
075        /** CaseBase object */
076        CBRCaseBase _caseBase;
077    
078        /** Configuration object for Filter based retrieval */
079        FilterConfig filterConfig;
080        /** Configuration object for Attribute Question */
081        Map<Attribute,String> labels;
082            
083        public void configure() throws ExecutionException
084        {
085            // Create a data base connector
086            _connector = new PlainTextConnector();
087            // Init the ddbb connector with the config file
088            _connector.initFromXMLfile(jcolibri.util.FileIO
089                            .findFile("jcolibri/test/recommenders/rec4/housesData/plaintextconfig.xml"));
090            // Create a Lineal case base for in-memory organization
091            _caseBase = new LinealCaseBase();
092            
093            //Configure the Filter
094            filterConfig = new FilterConfig();
095            filterConfig.addPredicate(new Attribute("area", HouseDescription.class), new Equal());
096            filterConfig.addPredicate(new Attribute("beds", HouseDescription.class), new Equal());
097            filterConfig.addPredicate(new Attribute("priceRange", HouseDescription.class), new Equal());
098            filterConfig.addPredicate(new Attribute("furnished", HouseDescription.class), new Equal());
099            filterConfig.addPredicate(new Attribute("type", HouseDescription.class), new Equal());
100            filterConfig.addPredicate(new Attribute("baths", HouseDescription.class), new Equal());
101            
102            //Configure labels for attribute question
103            labels = new HashMap<Attribute,String>();
104        }
105    
106        public void cycle(CBRQuery query) throws ExecutionException
107        {   
108            // Select attribute
109            Collection<CBRCase> workingCases = _caseBase.getCases();
110            Attribute att = InformationGain.getMoreIGattribute(workingCases,true, _caseBase.getCases());
111            // If there are not more attributes to ask, the method resturn null.
112            // And the ObtainQueryWithAttributeQuestion method receives that null and shows nothing.
113            // In that case, ObtainQueryWithAttributeQuestion returns false;
114            
115            // Ask for the attribute
116            boolean _continue = ObtainQueryWithAttributeQuestionMethod.obtainQueryWithAttributeQuestion(query, att, labels, workingCases);
117    
118            sequence1(query, _continue);
119        }
120        
121        
122        public void sequence1(CBRQuery query, boolean _continue)  throws ExecutionException
123        {
124            // Retrieve cases
125            Collection<CBRCase> workingCases = FilterBasedRetrievalMethod.filterCases(_caseBase.getCases(), query, filterConfig);
126            
127            // Display?
128            if(DisplayCasesIfNumber.displayCases(50, 1, workingCases,false))
129                sequence2(query, workingCases, _continue);
130            else
131                sequence3(query, workingCases);
132            
133    
134        }
135        
136        public void sequence2(CBRQuery query, Collection<CBRCase> workingCases, boolean _continue)  throws ExecutionException
137        {
138            // Display in cases. The chosen method depends on the AttributeSelection algorithm.
139            UserChoice choice;
140            if(_continue)
141                choice = DisplayCasesTableMethod.displayCasesInTableEditQuery(workingCases);        
142            else
143                choice = DisplayCasesTableMethod.displayCasesInTableBasic(workingCases);    
144            
145    
146            if(ContinueOrFinish.continueOrFinish(choice))
147                sequence3(query,workingCases);
148            else
149                sequence4(choice, workingCases);
150        }
151        
152        public void sequence3(CBRQuery query, Collection<CBRCase> workingCases)  throws ExecutionException
153        {
154            //Select attribute
155            Attribute att = InformationGain.getMoreIGattribute(workingCases,false, _caseBase.getCases());
156            
157            //Ask attribute
158            boolean _continue = ObtainQueryWithAttributeQuestionMethod.obtainQueryWithAttributeQuestion(query, att, labels,workingCases);
159    
160            sequence1(query, _continue);
161        }
162        
163        public void sequence4(UserChoice choice, Collection<CBRCase> workingCases)  throws ExecutionException
164        {
165            if(BuyOrQuit.buyOrQuit(choice))
166                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
167            
168            else
169                System.out.println("Finish - User Quits");
170        }
171    
172        public void postCycle() throws ExecutionException
173        {
174        }
175    
176        public CBRCaseBase preCycle() throws ExecutionException
177        {
178            // Load cases from connector into the case base
179            _caseBase.init(_connector);             
180            // Print the cases
181            java.util.Collection<CBRCase> cases = _caseBase.getCases();
182            for(CBRCase c: cases)
183                    System.out.println(c);
184            return _caseBase;
185        }
186        
187        public static void main(String[] args) {
188            StandardCBRApplication recommender = new Houses4();
189            try
190            {
191                recommender.configure();
192                
193                recommender.preCycle();
194                
195                CBRQuery query = new CBRQuery();
196                
197                HouseDescription hd = new HouseDescription();
198                
199                query.setDescription(hd);
200                
201                recommender.cycle(query);
202                
203                recommender.postCycle();
204                
205                //System.exit(0);
206            } catch (Exception e)
207            {
208                org.apache.commons.logging.LogFactory.getLog(Houses4.class).error(e);
209                
210            }
211            
212    
213        }
214    
215    }