001    package jcolibri.method.maintenance.solvesFunctions;
002    
003    import java.util.Collection;
004    import java.util.Iterator;
005    import java.util.LinkedList;
006    
007    import jcolibri.cbrcore.CBRCase;
008    import jcolibri.extensions.classification.ClassificationSolution;
009    import jcolibri.method.maintenance.SolvesFunction;
010    import jcolibri.method.retrieve.RetrievalResult;
011    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
012    import jcolibri.method.retrieve.selection.SelectCases;
013    import jcolibri.method.reuse.classification.KNNClassificationConfig;
014    import jcolibri.method.reuse.classification.KNNClassificationMethod;
015    import jcolibri.method.revise.classification.BasicClassificationOracle;
016    import jcolibri.method.revise.classification.ClassificationOracle;
017    
018    /**
019     * Provides the solves function that Sarah-Jane Delaney uses
020     * in her case-base editing (CBE) algorithms which will 
021     * decide which cases solve a query. 
022     * 
023     * @author Lisa Cummins
024     * @author Derek Bridge
025     * 22/05/07
026     */
027    public class CBESolvesFunction extends SolvesFunction
028    {
029            /**
030             * Sets the cases that either solve q or contribute to its 
031             * misclassification.
032             * A case solves a query if the query is correctly classified
033             * by its nearest neighbours and the solution of the case
034             * agrees with the solution of the query. 
035             * A case misclassifies a query if the query is incorrectly
036             * classified by its nearest neighbours and the solution of the
037             * case disagrees with the solution of the query. 
038             * 
039             * @param q the query
040             * @param cases from which to find the cases which solve
041             * and classify the query. These include the query itself. 
042             * @param knnConfig the similarity configuration
043             */
044            public void setCasesThatSolveAndMisclassifyQ(CBRCase q, Collection<CBRCase> cases, KNNClassificationConfig knnConfig)
045            {
046                    solveQ = new LinkedList<CBRCase>(); //It will always contain at least the query itself
047                    misclassifyQ = null;
048                    
049                    /* q is regarded to solve itself regardless of whether it is
050                     * correctly or incorrectly classified by its nearest neighbours
051                     * and so we add it to its solveQ set.
052                     */  
053                    solveQ.add(q);
054                    
055                    /* Because q is included in the cases, we retrieve k+1 neighbours and then 
056                     * either remove q, or, if q is not contained in the retrieved cases, we  
057                     * remove the last case of those retrieved
058                     */
059                    knnConfig.setK(knnConfig.getK()+1);
060                    Collection<RetrievalResult> knnResults = NNScoringMethod.evaluateSimilarity(cases, q, knnConfig);
061                    Collection<CBRCase> knn = SelectCases.selectTopK(knnResults, knnConfig.getK());
062                    knnConfig.setK(knnConfig.getK()-1); 
063                    RetrievalResult result = null;
064                    boolean qFound = false;
065                    
066                    for(Iterator<RetrievalResult> cIter = knnResults.iterator(); cIter.hasNext() && !qFound; )
067                    {       result = cIter.next();
068                            if(result.get_case().equals(q))
069                            {       knnResults.remove(result);                          
070                                    qFound = true;
071                            }
072                    }
073                    if(!qFound)
074                    {       knn.remove(result);
075                    }
076                    try 
077                    {       KNNClassificationMethod classifier = ((KNNClassificationConfig)knnConfig).getClassificationMethod();
078                            ClassificationSolution predictedSolution = classifier.getPredictedSolution(knnResults);
079            
080                            ClassificationOracle oracle = new BasicClassificationOracle();
081                            boolean correct = oracle.isCorrectPrediction(predictedSolution, q);
082                            if(correct)
083                            {       for(RetrievalResult res: knnResults)
084                                    {       CBRCase c = res.get_case();
085                                            if(oracle.isCorrectPrediction((ClassificationSolution)c.getSolution(), q))
086                                            {       solveQ.add(c);
087                                            }
088                                    }
089                            }
090                            else
091                            {       misclassifyQ = new LinkedList<CBRCase>();
092                                    for(RetrievalResult res: knnResults)
093                                    {       CBRCase c = res.get_case();
094                                            if(!oracle.isCorrectPrediction((ClassificationSolution)c.getSolution(), q))
095                                            {       misclassifyQ.add(c);
096                                            }
097                                    }
098                                    
099                            }
100                    } catch(ClassCastException cce)
101                    {       org.apache.commons.logging.LogFactory.getLog(CBESolvesFunction.class).error(cce);
102                            System.exit(0);
103                    }
104    
105            }
106    }