private Collection<CQIE> rewriteCC(QueryConnectedComponent cc, Function headAtom,  Multimap<Predicate, CQIE> edgeDP) {
		
		List<CQIE> outputRules = new LinkedList<>();	

		TreeWitnessSet tws = TreeWitnessSet.getTreeWitnesses(cc, reasoner, generators, immutabilityTools);

		if (cc.hasNoFreeTerms()) {  
			if (!cc.isDegenerate() || cc.getLoop() != null) 
				for (Function a : getAtomsForGenerators(tws.getGeneratorsOfDetachedCC(), getFreshVariable())) {
					outputRules.add(datalogFactory.getCQIE(headAtom, a));
				}
		}

		// COMPUTE AND STORE TREE WITNESS FORMULAS
		for (TreeWitness tw : tws.getTWs()) {
			log.debug("TREE WITNESS: {}", tw);		
			List<Function> twf = new LinkedList<>();
			
			// equality atoms
			Iterator<Term> i = tw.getRoots().iterator();
			Term r0 = i.next();
			while (i.hasNext()) 
				twf.add(termFactory.getFunctionEQ(i.next(), r0));
			
			// root atoms
			for (Function a : tw.getRootAtoms()) {
				if (!(a.getFunctionSymbol() instanceof TriplePredicate))
					throw new MinorOntopInternalBugException("A triple atom was expected: " + a);

				boolean isClass = ((TriplePredicate) a.getFunctionSymbol()).getClassIRI(
						a.getTerms().stream()
								.map(immutabilityTools::convertIntoImmutableTerm)
								.collect(ImmutableCollectors.toList()))
						.isPresent();

				twf.add(isClass
						? atomFactory.getMutableTripleAtom(r0, a.getTerm(1), a.getTerm(2))
						: atomFactory.getMutableTripleAtom(r0, a.getTerm(1), r0));
			}
			
			List<Function> genAtoms = getAtomsForGenerators(tw.getGenerators(), r0);			
			boolean subsumes = false;
//			for (Function a : genAtoms) 				
//				if (twf.subsumes(a)) {
//					subsumes = true;
//					log.debug("TWF {} SUBSUMES {}", twf.getAllAtoms(), a);
//					break;
//				}

			List<List<Function>> twfs = new ArrayList<>(subsumes ? 1 : genAtoms.size());
//			if (!subsumes) {
				for (Function a : genAtoms) {				
					LinkedList<Function> twfa = new LinkedList<>(twf);
					twfa.add(a); // 
					twfs.add(twfa);
				}
//			}
//			else
//				twfs.add(twf.getAllAtoms());
			
			tw.setFormula(twfs);
		}

		final String headURI = headAtom.getFunctionSymbol().getName();
		if (!cc.isDegenerate()) {
			if (tws.hasConflicts()) { 
				// there are conflicting tree witnesses
				// use compact exponential rewriting by enumerating all compatible subsets of tree witnesses
				CompatibleTreeWitnessSetIterator iterator = tws.getIterator();
				while (iterator.hasNext()) {
					Collection<TreeWitness> compatibleTWs = iterator.next();
					log.debug("COMPATIBLE: {}", compatibleTWs);
					LinkedList<Function> mainbody = new LinkedList<Function>(); 
					
					for (Edge edge : cc.getEdges()) {
						boolean contained = false;
						for (TreeWitness tw : compatibleTWs)
							if (tw.getDomain().contains(edge.getTerm0()) && tw.getDomain().contains(edge.getTerm1())) {
								contained = true;
								log.debug("EDGE {} COVERED BY {}", edge, tw);
								break;
							}
						if (!contained) {
							log.debug("EDGE {} NOT COVERED BY ANY TW",  edge);
							mainbody.addAll(edge.getAtoms());
						}
					}
					for (TreeWitness tw : compatibleTWs) {
						Function twAtom = getHeadAtom(headURI, "_TW_" + (edgeDP.size() + 1), cc.getVariables());
						mainbody.add(twAtom);				
						for (List<Function> twfa : tw.getFormula())
							edgeDP.put(twAtom.getFunctionSymbol(), datalogFactory.getCQIE(twAtom, twfa));
					}	
					mainbody.addAll(cc.getNonDLAtoms());					
					outputRules.add(datalogFactory.getCQIE(headAtom, mainbody));
				}
			}
			else {
				// no conflicting tree witnesses
				// use polynomial tree witness rewriting by treating each edge independently 
				LinkedList<Function> mainbody = new LinkedList<>();
				for (Edge edge : cc.getEdges()) {
					log.debug("EDGE {}", edge);
					
					Function edgeAtom = null;
					for (TreeWitness tw : tws.getTWs())
						if (tw.getDomain().contains(edge.getTerm0()) && tw.getDomain().contains(edge.getTerm1())) {
							if (edgeAtom == null) {
								//IRI atomURI = edge.getBAtoms().iterator().next().getIRI().getName();
								edgeAtom = getHeadAtom(headURI, 
										"_EDGE_" + (edgeDP.size() + 1) /*+ "_" + atomURI.getRawFragment()*/, cc.getVariables());
								mainbody.add(edgeAtom);				
								
								LinkedList<Function> edgeAtoms = new LinkedList<>();
								edgeAtoms.addAll(edge.getAtoms());
								edgeDP.put(edgeAtom.getFunctionSymbol(), datalogFactory.getCQIE(edgeAtom, edgeAtoms));
							}
							
							for (List<Function> twfa : tw.getFormula())
								edgeDP.put(edgeAtom.getFunctionSymbol(), datalogFactory.getCQIE(edgeAtom, twfa));
						}
					
					if (edgeAtom == null) // no tree witnesses -- direct insertion into the main body
						mainbody.addAll(edge.getAtoms());
				}
				mainbody.addAll(cc.getNonDLAtoms());
				outputRules.add(datalogFactory.getCQIE(headAtom, mainbody));
			}
		}
		else {
			// degenerate connected component
			LinkedList<Function> loopbody = new LinkedList<>();
			Loop loop = cc.getLoop();
			log.debug("LOOP {}", loop);
			if (loop != null)
				loopbody.addAll(loop.getAtoms());
			loopbody.addAll(cc.getNonDLAtoms());
			outputRules.add(datalogFactory.getCQIE(headAtom, loopbody));
		}
		return outputRules;
	}
private Collection < CQIE > rewriteCC ( QueryConnectedComponent cc , Function headAtom , Multimap < Predicate , CQIE > edgeDP ) { List < CQIE > outputRules = new LinkedList < > ( ) ; TreeWitnessSet tws = TreeWitnessSet . getTreeWitnesses ( cc , reasoner , generators , immutabilityTools ) ; if ( cc . hasNoFreeTerms ( ) ) { if ( ! cc . isDegenerate ( ) || cc . getLoop ( ) != null ) for ( Function a : getAtomsForGenerators ( tws . getGeneratorsOfDetachedCC ( ) , getFreshVariable ( ) ) ) { outputRules . add ( datalogFactory . getCQIE ( headAtom , a ) ) ; } } for ( TreeWitness tw : tws . getTWs ( ) ) { log . debug ( "TREE WITNESS: {}" , tw ) ; List < Function > twf = new LinkedList < > ( ) ; Iterator < Term > i = tw . getRoots ( ) . iterator ( ) ; Term r0 = i . next ( ) ; while ( i . hasNext ( ) ) twf . add ( termFactory . getFunctionEQ ( i . next ( ) , r0 ) ) ; for ( Function a : tw . getRootAtoms ( ) ) { if ( ! ( a . getFunctionSymbol ( ) instanceof TriplePredicate ) ) throw new MinorOntopInternalBugException ( "A triple atom was expected: " + a ) ; boolean isClass = ( ( TriplePredicate ) a . getFunctionSymbol ( ) ) . getClassIRI ( a . getTerms ( ) . stream ( ) . map ( immutabilityTools :: convertIntoImmutableTerm ) . collect ( ImmutableCollectors . toList ( ) ) ) . isPresent ( ) ; twf . add ( isClass ? atomFactory . getMutableTripleAtom ( r0 , a . getTerm ( 1 ) , a . getTerm ( 2 ) ) : atomFactory . getMutableTripleAtom ( r0 , a . getTerm ( 1 ) , r0 ) ) ; } List < Function > genAtoms = getAtomsForGenerators ( tw . getGenerators ( ) , r0 ) ; boolean subsumes = false ; List < List < Function > > twfs = new ArrayList < > ( subsumes ? 1 : genAtoms . size ( ) ) ; for ( Function a : genAtoms ) { LinkedList < Function > twfa = new LinkedList < > ( twf ) ; twfa . add ( a ) ; twfs . add ( twfa ) ; } tw . setFormula ( twfs ) ; } final String headURI = headAtom . getFunctionSymbol ( ) . getName ( ) ; if ( ! cc . isDegenerate ( ) ) { if ( tws . hasConflicts ( ) ) { CompatibleTreeWitnessSetIterator iterator = tws . getIterator ( ) ; while ( iterator . hasNext ( ) ) { Collection < TreeWitness > compatibleTWs = iterator . next ( ) ; log . debug ( "COMPATIBLE: {}" , compatibleTWs ) ; LinkedList < Function > mainbody = new LinkedList < Function > ( ) ; for ( Edge edge : cc . getEdges ( ) ) { boolean contained = false ; for ( TreeWitness tw : compatibleTWs ) if ( tw . getDomain ( ) . contains ( edge . getTerm0 ( ) ) && tw . getDomain ( ) . contains ( edge . getTerm1 ( ) ) ) { contained = true ; log . debug ( "EDGE {} COVERED BY {}" , edge , tw ) ; break ; } if ( ! contained ) { log . debug ( "EDGE {} NOT COVERED BY ANY TW" , edge ) ; mainbody . addAll ( edge . getAtoms ( ) ) ; } } for ( TreeWitness tw : compatibleTWs ) { Function twAtom = getHeadAtom ( headURI , "_TW_" + ( edgeDP . size ( ) + 1 ) , cc . getVariables ( ) ) ; mainbody . add ( twAtom ) ; for ( List < Function > twfa : tw . getFormula ( ) ) edgeDP . put ( twAtom . getFunctionSymbol ( ) , datalogFactory . getCQIE ( twAtom , twfa ) ) ; } mainbody . addAll ( cc . getNonDLAtoms ( ) ) ; outputRules . add ( datalogFactory . getCQIE ( headAtom , mainbody ) ) ; } } else { LinkedList < Function > mainbody = new LinkedList < > ( ) ; for ( Edge edge : cc . getEdges ( ) ) { log . debug ( "EDGE {}" , edge ) ; Function edgeAtom = null ; for ( TreeWitness tw : tws . getTWs ( ) ) if ( tw . getDomain ( ) . contains ( edge . getTerm0 ( ) ) && tw . getDomain ( ) . contains ( edge . getTerm1 ( ) ) ) { if ( edgeAtom == null ) { edgeAtom = getHeadAtom ( headURI , "_EDGE_" + ( edgeDP . size ( ) + 1 ) , cc . getVariables ( ) ) ; mainbody . add ( edgeAtom ) ; LinkedList < Function > edgeAtoms = new LinkedList < > ( ) ; edgeAtoms . addAll ( edge . getAtoms ( ) ) ; edgeDP . put ( edgeAtom . getFunctionSymbol ( ) , datalogFactory . getCQIE ( edgeAtom , edgeAtoms ) ) ; } for ( List < Function > twfa : tw . getFormula ( ) ) edgeDP . put ( edgeAtom . getFunctionSymbol ( ) , datalogFactory . getCQIE ( edgeAtom , twfa ) ) ; } if ( edgeAtom == null ) mainbody . addAll ( edge . getAtoms ( ) ) ; } mainbody . addAll ( cc . getNonDLAtoms ( ) ) ; outputRules . add ( datalogFactory . getCQIE ( headAtom , mainbody ) ) ; } } else { LinkedList < Function > loopbody = new LinkedList < > ( ) ; Loop loop = cc . getLoop ( ) ; log . debug ( "LOOP {}" , loop ) ; if ( loop != null ) loopbody . addAll ( loop . getAtoms ( ) ) ; loopbody . addAll ( cc . getNonDLAtoms ( ) ) ; outputRules . add ( datalogFactory . getCQIE ( headAtom , loopbody ) ) ; } return outputRules ; }
/*
rewrites a given connected CQ with the rules put into output