001/**
002 * Copyright (C) 2007 - 2016, Jens Lehmann
003 *
004 * This file is part of DL-Learner.
005 *
006 * DL-Learner is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation; either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * DL-Learner is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.dllearner.algorithms.qtl.operations.nbr.strategy;
020
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026import java.util.Map.Entry;
027import java.util.Random;
028
029import org.apache.log4j.Logger;
030import org.dllearner.algorithms.qtl.QueryTreeUtils;
031import org.dllearner.algorithms.qtl.datastructures.impl.RDFResourceTree;
032
033import org.apache.jena.graph.Node;
034import com.jamonapi.Monitor;
035import com.jamonapi.MonitorFactory;
036
037/**
038 * 
039 * @author Lorenz Bühmann
040 *
041 */
042public class GreedyNBRStrategy implements NBRStrategy{
043        
044        private static final Logger logger = Logger.getLogger(GreedyNBRStrategy.class);
045        
046        private int maxEqualEdgesFromRoot = 3;
047        
048        private Random random;
049        
050        private boolean useWeakGeneralisation = true;
051        
052        public GreedyNBRStrategy(){
053                random = new Random();
054        }
055
056        @Override
057        public RDFResourceTree computeNBR(RDFResourceTree posExampleTree,
058                        List<RDFResourceTree> negExampleTrees) {
059                if(logger.isInfoEnabled()){
060                        logger.info("Making NBR...");
061                }
062                logger.info("LGG:\n" + QueryTreeUtils.toSPARQLQueryString(posExampleTree));
063                Monitor mon = MonitorFactory.getTimeMonitor("NBR");
064                mon.start();
065                
066                RDFResourceTree nbr = new RDFResourceTree(posExampleTree);
067                Map<RDFResourceTree, List<Integer>> matrix = new HashMap<>();
068                
069                for(int i = 0; i < negExampleTrees.size(); i++){
070                        checkTree(matrix, nbr, negExampleTrees.get(i), i);
071                }
072                
073                
074                int negTreeSize = negExampleTrees.size();
075                Map<RDFResourceTree, Double> rowValues = new HashMap<>();
076                double value;
077                for(Entry<RDFResourceTree, List<Integer>> entry : matrix.entrySet()){
078                        value = (sum(entry.getValue())+1.0)/(negTreeSize+2.0);
079                        rowValues.put(entry.getKey(), value);
080                }
081
082                
083                List<RDFResourceTree> candidates2Remove = new ArrayList<>();
084                if(useWeakGeneralisation){
085                        for(Entry<RDFResourceTree, Double> entry : rowValues.entrySet()){
086                                if(random.nextDouble() < entry.getValue()){
087                                        candidates2Remove.add(entry.getKey());
088                                }
089                        }
090                        useWeakGeneralisation = false;
091                } else {
092                        for(Entry<RDFResourceTree, Double> entry : rowValues.entrySet()){
093                                if(random.nextDouble() < (1 - entry.getValue())){
094                                        candidates2Remove.add(entry.getKey());
095                                }
096                        }
097                }
098                
099//              RDFResourceTree parent;
100//              for(RDFResourceTree leaf : new ArrayList<RDFResourceTree>(nbr.getLeafs())){
101//                      parent = leaf.getParent();
102//                      if(candidates2Remove.contains(leaf)){
103//                              if(logger.isInfoEnabled()){
104//                                      logger.info("Removing edge [" + 
105//                                                      leaf.getParent().getUserObject() + "--" + leaf.getParent().getEdge(leaf) + "-->" + leaf.getUserObject() + "]");
106//                              }
107//                              leaf.getParent().removeChild((QueryTreeImpl<N>) leaf);
108//                              if(logger.isInfoEnabled()){
109//                                      logger.info("Checking if removal leads to cover a negative tree...");
110//                              }
111//                              if(coversNegativeTree(nbr, negExampleTrees)){
112//                                      parent.addChild((QueryTreeImpl<N>) leaf);
113//                                      if(logger.isInfoEnabled()){
114//                                              logger.info("Removal of the edge leads to cover a negative tree. Undoing removal.");
115//                                      }
116//                              }
117//                      }
118//              }
119                RDFResourceTree parent;
120                for(RDFResourceTree candidate : candidates2Remove){
121                        if(candidate.isRoot())continue;
122                        parent = candidate.getParent();
123                        parent.removeChild(candidate);
124                        if(logger.isInfoEnabled()){
125                                logger.info("Checking if removal leads to coverage of a negative tree...");
126                        }
127                        if(coversNegativeTree(nbr, negExampleTrees)){
128                                parent.addChild(candidate);
129                                if(logger.isInfoEnabled()){
130                                        logger.info("Removal of the edge leads to coverage of a negative tree. Undoing removal.");
131                                }
132                        }
133                }
134                
135//              removeLeafs(nbr, candidates2Remove);
136                removeEqualEdgesFromRoot(nbr);
137                
138                mon.stop();
139                
140                return nbr;
141        }
142        
143        private void generaliseWeak(){
144                
145        }
146        
147        private void generaliseStrong(){
148                
149        }
150        
151        private boolean coversNegativeTree(RDFResourceTree posTree, List<RDFResourceTree> negTrees){
152                for(RDFResourceTree negTree : negTrees){
153                        if(QueryTreeUtils.isSubsumedBy(negTree, posTree)){
154                                return true;
155                        }
156                }
157                return false;
158        }
159        
160        private void removeLeafs(RDFResourceTree nbr, List<RDFResourceTree> candidates2Remove){
161                for(RDFResourceTree leaf : new ArrayList<>(nbr.getLeafs())){
162                        if(candidates2Remove.contains(leaf)){
163                                logger.info("REMOVE " + leaf);
164                                leaf.getParent().removeChild(leaf);
165                        }
166                }
167        }
168        
169        private void removeEqualEdgesFromRoot(RDFResourceTree tree){
170                List<RDFResourceTree> children;
171                int childCount = 1;
172                for(Node edge : tree.getEdges()){
173                        children = tree.getChildren(edge);
174                        childCount = children.size();
175                        while(childCount > maxEqualEdgesFromRoot){
176                                tree.removeChild(children.get(childCount-1));
177                                childCount--;
178                        }
179                }
180                
181        }
182        
183        
184        private String printTreeWithValues(RDFResourceTree tree, Map<RDFResourceTree, List<Integer>> matrix){
185                int depth = QueryTreeUtils.getDepth(tree);
186        StringBuilder sb = new StringBuilder();
187        if(tree.isRoot()){
188                sb.append("TREE\n\n");
189        }
190//        ren = ren.replace("\n", "\n" + sb);
191        sb.append(tree.getData()).append("(").append(matrix.get(tree)).append(")");
192        sb.append("\n");
193        for (RDFResourceTree child : tree.getChildren()) {
194            for (int i = 0; i < depth; i++) {
195                sb.append("\t");
196            }
197            Node edge = tree.getEdgeToChild(child);
198            if (edge != null) {
199                sb.append("  ");
200                sb.append(edge);
201                sb.append(" ---> ");
202            }
203            sb.append(printTreeWithValues(child, matrix));
204        }
205        return sb.toString();
206        }
207        
208        private int sum(List<Integer> list){
209                int sum = 0;
210                for(Integer i : list){
211                        sum += i;
212                }
213                return sum;
214        }
215
216        @Override
217        public List<RDFResourceTree> computeNBRs(RDFResourceTree posExampleTree,
218                        List<RDFResourceTree> negExampleTrees) {
219                return Collections.singletonList(computeNBR(posExampleTree, negExampleTrees));
220        }
221        
222//      private void checkTree(Map<RDFResourceTree, List<Integer>> matrix, RDFResourceTree posTree, RDFResourceTree negTree, int index){
223//              int entry;
224//              if(!posTree.getUserObject().equals("?") && !posTree.getUserObject().equals(negTree.getUserObject())){
225//                      entry = 1;
226//              } else {
227//                      entry = 1;
228//                      for(Object edge : posTree.getEdges()){
229//                              for(RDFResourceTree child1 : posTree.getChildren(edge)){
230//                                      for(RDFResourceTree child2 : negTree.getChildren(edge)){
231//                                              if(!posTree.getUserObject().equals("?") && child1.getUserObject().equals(child2.getUserObject())){
232//                                                      entry = 0;break;
233//                                              }
234//                                              if(posTree.getUserObject().equals("?")){
235//                                                      checkTree(matrix, child1, child2, index);
236//                                              }
237//                                      }
238//                              }
239//                      }
240//                      Object edge;
241//                      for(RDFResourceTree child1 : posTree.getChildren()){
242//                      edge = posTree.getEdge(child1);
243//                      for(RDFResourceTree child2 : negTree.getChildren(edge)){
244//                              
245//                      }
246//                      
247//              }
248//              }
249//              setMatrixEntry(matrix, posTree, index, entry);
250//              if(entry == 1){
251//                      for(RDFResourceTree child : posTree.getChildrenClosure()){
252//                              setMatrixEntry(matrix, child, index, 0);
253//                      }
254//              }
255//      }
256        
257        private void checkTree(Map<RDFResourceTree, List<Integer>> matrix, RDFResourceTree posTree, RDFResourceTree negTree, int index){
258                int entry = 1;
259                for(RDFResourceTree child1 : posTree.getChildren()){
260                        entry = 1;
261                Node edge = posTree.getEdgeToChild(child1);
262                for(RDFResourceTree child2 : negTree.getChildren(edge)){
263                        if(!child1.isVarNode() && child1.getData().equals(child2.getData())){
264                                entry = 0;
265                                checkTree(matrix, child1, child2, index);
266                        } else if(child1.isVarNode()){
267                                entry = 0;
268                                checkTree(matrix, child1, child2, index);
269                        }
270                }
271                setMatrixEntry(matrix, child1, index, entry);
272                if(entry == 1){
273                        for(RDFResourceTree child : QueryTreeUtils.getNodes(posTree)) {
274                                setMatrixEntry(matrix, child, index, 0);
275                        }
276                }
277                }
278                
279        }
280        
281        private void setMatrixEntry(Map<RDFResourceTree, List<Integer>> matrix, RDFResourceTree row, int column, int entry){
282                List<Integer> list = matrix.get(row);
283                if(list == null){
284                        list = new ArrayList<>();
285                        matrix.put(row, list);
286                }
287                try {
288                        list.set(column, entry);
289                } catch (IndexOutOfBoundsException e) {
290                        list.add(entry);
291                }
292        }
293
294//      @Override
295//      public RDFResourceTree computeNBR(RDFResourceTree posExampleTree,
296//                      List<RDFResourceTree> negExampleTrees) {
297//              Map<RDFResourceTree, Integer> map = new HashMap<RDFResourceTree, Integer>();
298//              for(RDFResourceTree negExampleTree : negExampleTrees){
299//                      checkSubsumptionBreadthFirst(posExampleTree, negExampleTree, map);
300//              }
301//              
302//              Map<RDFResourceTree, Integer> sortedMap = sortByValues(map);
303//              System.out.println(sortedMap);
304//              return null;
305//      }
306//
307//      @Override
308//      public List<RDFResourceTree> computeNBRs(RDFResourceTree posExampleTree,
309//                      List<RDFResourceTree> negExampleTrees) {
310//              // TODO Auto-generated method stub
311//              return null;
312//      }
313//      
314//      private void checkSubsumptionBreadthFirst(RDFResourceTree tree1, RDFResourceTree tree2, Map<RDFResourceTree, Integer> map){
315//              Object edge;
316//              for(RDFResourceTree child1 : tree1.getChildren()){
317//                      edge = tree1.getEdge(child1);
318//                      for(RDFResourceTree child2 : tree2.getChildren(edge)){
319//                              if(child1.getUserObject().equals("?") || child2.getUserObject().equals(child1.getUserObject())){
320//                                      Integer i = map.get(child1);
321//                                      if(i == null){
322//                                              i = Integer.valueOf(0);
323//                                      }
324//                                      map.put(child1, Integer.valueOf(i.intValue() +1));
325//                                      checkSubsumptionBreadthFirst(child1, child2, map);
326//                              } else {
327//                                      Integer i = map.get(child1);
328//                                      if(i == null){
329//                                              map.put(child1, Integer.valueOf(0));
330//                                      }
331//                                      
332//                              }
333//                      }
334//              }
335//      }
336//      
337//      private <K, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {
338//              Comparator<K> valueComparator =  new Comparator<K>() {
339//                  public int compare(K k1, K k2) {
340//                      int compare = map.get(k2).compareTo(map.get(k1));
341//                      if (compare == 0) return 1;
342//                      else return compare;
343//                  }
344//              };
345//              Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
346//              sortedByValues.putAll(map);
347//              return sortedByValues;
348//      }
349//      
350//      public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(
351//                      Map<K, V> map) {
352//              List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(
353//                              map.entrySet());
354//              Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
355//                      public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
356//                              return (o1.getValue()).compareTo(o2.getValue());
357//                      }
358//              });
359//
360//              Map<K, V> result = new LinkedHashMap<K, V>();
361//              for (Map.Entry<K, V> entry : list) {
362//                      result.put(entry.getKey(), entry.getValue());
363//              }
364//              return result;
365//      }
366        
367        
368
369}