/* * MiniCon.java * ------------- * Implements the MiniCon algorithm. * $Id: MiniCon.java,v 1.33 2000/11/17 01:35:39 chenli Exp $ * */ import java.util.*; class MiniCon { public static double timeFormMCD; public static double timeCombineMCD; public static int numMCDs; public static int numRews; public static Prof prof; // calls the MiniCon algorithm to generate rewritings for the query static HashSet genPlan(Query query, Vector views) { long startTime = 0; long endTime = 0; prof = new Prof("MCDs"); prof.start(); HashSet mcds = formMCDs(query, views); prof.stop(); //HashSet rewritings = new HashSet(); HashSet rewritings = combineMCDs(query, mcds); prof.stop2(); timeFormMCD = (prof.stopcputime - prof.startcputime)/1000.0; timeCombineMCD = (prof.stopcputime2 - prof.stopcputime)/1000.0 ; //minimizeRews(); numMCDs = mcds.size(); numRews = rewritings.size(); return rewritings; } // calls the MiniCon algorithm to generate rewritings for the query static HashSet genPlan2(String type, Query query, Vector views) { long startTime = 0; long endTime = 0; prof = new Prof("MCDs"); prof.start(); HashSet mcds = formMCDs(query, views); System.out.println( mcds); System.out.println("query "+ query); prof.stop(); numMCDs = mcds.size(); HashSet rewritings = new HashSet(); if (type.equals("RW")){ rewritings = combineMCDs(query, mcds); prof.stop2(); timeCombineMCD = (prof.stopcputime2 - prof.stopcputime)/1000.0 ; numRews = rewritings.size(); } timeFormMCD = (prof.stopcputime - prof.startcputime)/1000.0; //minimizeRews(); return rewritings; } // generates all MCDs for a query and views static HashSet formMCDs(Query query, Vector views) { UserLib.myprintln("calling formMCDs()..."); HashSet mcds = new HashSet(); for (int i = 0; i < views.size(); i ++) { Query view = (Query) views.elementAt(i); mcds.addAll(formMCDs(query, view)); } return mcds; } // generates all MCDs for a query and views static HashSet formMCDs(Query query, Query view) { UserLib.myprintln("calling formMCDs(), view = " + view); HashSet mcds = new HashSet(); Vector querySubgoals = (Vector) query.getBody(); // generates all subsets of the query subgoals except the given one HashSet querySubsets = UserLib.genSubsets(querySubgoals); // scans the subsets from the smallest one to the largest one for (int i = 1; i <= querySubgoals.size(); i ++) { for (Iterator iter = querySubsets.iterator(); iter.hasNext();) { // for this "i"^th around, we consider only subsets with size i HashSet querySubgoalSubset = (HashSet) iter.next(); if (querySubgoalSubset.size() != i) continue; //System.out.println("query-subgoal subset = " + querySubgoalSubset); // tries to extend this subset ONLY IF it is not a superset of // another existing subset in the found MCDs if (containsQuerySubgoalSubset(mcds, querySubgoalSubset)) continue; // we should rename the view and adjust the PhiHH Query renamedView = view.rename(); //System.out.println("after renaming, view = " + renamedView); HashSet newMCDs = extend(query, querySubgoalSubset, renamedView); // it IS extendable. finally, we got some mcds mcds.addAll(newMCDs); } } return mcds; } /** * Given a query subgoal and a view subguoa, tries to find an HH of the * view, under which there is a mapping phi from the query subgoal to * the view subgoal. */ private static PhiHH unifiable(Query query, int querySubgoalIndex, Query view, int viewSubgoalIndex) { Subgoal querySubgoal = query.getSubgoal(querySubgoalIndex); Subgoal viewSubgoal = view.getSubgoal(viewSubgoalIndex); // they must use the same name if (!querySubgoal.isSameName(viewSubgoal)) return null; Vector queryArgs = querySubgoal.getArgs(); Vector viewArgs = viewSubgoal.getArgs(); if (queryArgs.size() != viewArgs.size()) UserLib.myerror("MiniCon.unifiable(), wrong args!"); Mapping phi = new Mapping(); Mapping hh = new Mapping(); // checks if a query arg is unifiable with the corresponding view arg for (int i = 0; i < queryArgs.size(); i ++) { Argument queryArg = (Argument) queryArgs.elementAt(i); Argument viewArg = (Argument) viewArgs.elementAt(i); if (!queryArg.unifiable(viewArg, phi, hh, view.getDistVars())) return null; } return (new PhiHH(phi, hh)); } // for (i = 1; i < number of query's subgoals; i ++) // { // for each superset querySuperset of {querySubgoal} with size i // { // if querySuperset can be mapped to some view subgoals while // the mapping is consistent with phihh, and the mapping satisfies // the PROPERTY // { // if this superset is not a superset of another existing // superset in moreMCDs // { // form an MCD and add // } // } // } // } /** * checks if a subset of query's subgoals can be mapped to some view * subgoals while the mapping is consistent with a given phihh from a * given query subgoal to a given view subgoal, and the mapping * satisfies the PROPERTY. * If so, returns the set of new MCDs. */ private static HashSet extend(Query query, HashSet querySubgoalSubset, Query view) { HashSet mcds = new HashSet(); // translates the querySubgoalSubset to a vector Vector querySubgoalSeq = new Vector(); for (Iterator iter = querySubgoalSubset.iterator(); iter.hasNext();) { querySubgoalSeq.add(iter.next()); } // clones the view's body Vector viewSubgoals = (Vector) view.getBody(); // generates all subsets of the view subgoals except the given one HashSet viewSubsets = UserLib.genSubsets(viewSubgoals); //System.out.println("viewSubsets = " + viewSubsets); // scans the subsets from the smallest one to the largest one for (int i = 1; i <= viewSubgoals.size(); i ++) { if (i > querySubgoalSubset.size()) break; for (Iterator iter = viewSubsets.iterator(); iter.hasNext();) { // for this "i"^th around, we consider only subsets with size i HashSet viewSubgoalSubset = (HashSet) iter.next(); if (viewSubgoalSubset.size() != i) continue; //System.out.println("view-subgoal subset = " + viewSubgoalSubset); // tries to extend the view-subgoal subset ONLY IF it is not a // superset of another existing view-subgoal subset in the found MCDs if (containsViewSubgoalSubset(mcds, viewSubgoalSubset)) continue; // considers this pair of query-subgoal subset and view-subgoal subset MCD mcd = formOneMCD(query, querySubgoalSeq, view, viewSubgoalSubset); if (mcd != null) mcds.add(mcd); } } return mcds; } /** * checks if one query-subgoal subset is a superset of another existing * query-subgoal subset in a given set of MCDs. */ private static boolean containsQuerySubgoalSubset(HashSet mcds, HashSet querySubgoals) { for (Iterator iter = mcds.iterator(); iter.hasNext();) { MCD mcd = (MCD) iter.next(); HashSet mcdQuerySubgoals = mcd.getMappedQuerySubgoals(); // checks if the given set of subgoals is a super set of the // subgoals in this MCD. !!! make sure the sets are using references // to the same set of query subgoals if (querySubgoals.containsAll(mcdQuerySubgoals)) return true; } return false; } /** * checks if one query-subgoal subset is a superset of another existing * query-subgoal subset in a given set of MCDs. */ private static boolean containsViewSubgoalSubset(HashSet mcds, HashSet viewSubgoals) { for (Iterator iter = mcds.iterator(); iter.hasNext();) { MCD mcd = (MCD) iter.next(); HashSet mcdViewSubgoals = mcd.getViewSubgoals(); // checks if the given set of subgoals is a super set of the // subgoals in this MCD. !!! make sure the sets are using references // to the same set of query subgoals if (viewSubgoals.containsAll(mcdViewSubgoals)) // <== !!! renamed return true; } return false; } /** * Given a pair of query-subgoal subset and view-subgoal subset, * tries to extend them to form an MCD. Note that ALL the subgoals in * the two subsets must be used. */ private static MCD formOneMCD(Query query, Vector querySubgoalSeq, Query view, HashSet viewSubgoalSubset) { /*System.out.println("formOneMCD(): querySubgoalSeq = " + querySubgoalSeq + " viewSubgoalSubset " + viewSubgoalSubset);*/ // the view-subgoal subest cannot have more subgoals than the // query-subgoal subset if (viewSubgoalSubset.size() > querySubgoalSeq.size()) return null; // generates all the sequences of length querySubgoalSubset.size() for // the view subgoals which each view subgoal should appear at least // once. Vector viewSubgoalSeqs = UserLib.getAllSeqs(viewSubgoalSubset, querySubgoalSeq.size()); //System.out.println("formOneMCD(): viewSubgoalSeqs = " + viewSubgoalSeqs); if (viewSubgoalSeqs == null) return null; for (int i = 0; i < viewSubgoalSeqs.size(); i ++) { // tries to create an MCD for this pair of sequences of query // subgoals and view subgoals Vector viewSubgoalSeq = (Vector) viewSubgoalSeqs.elementAt(i); MCD mcd = buildMCD(query, querySubgoalSeq, view, viewSubgoalSeq); // returns once if we find one MCD if (mcd != null) return mcd; } return null; } private static MCD buildMCD(Query query, Vector querySubgoalSeq, Query view, Vector viewSubgoalSeq) { // two vectors should have the same size if (querySubgoalSeq.size() != viewSubgoalSeq.size()) UserLib.myerror("MiniCon.buildMCD(): error. The two " + "vectors should have the same size."); // clones a new phihh Mapping phi = new Mapping(); Mapping hh = new Mapping(); // scans the subgoals to match for (int i = 0; i < querySubgoalSeq.size(); i ++) { Subgoal querySubgoal = (Subgoal) querySubgoalSeq.elementAt(i); Subgoal viewSubgoal = (Subgoal) viewSubgoalSeq.elementAt(i); // they should have the same name // !!! make sure "equals" works if (!querySubgoal.getName().equals(viewSubgoal.getName())) return null; Vector queryArgs = querySubgoal.getArgs(); Vector viewArgs = viewSubgoal.getArgs(); // they should have the same number of subgoals if (viewArgs.size() != queryArgs.size()) UserLib.myerror("MiniCon.buildmCD(): error. The two " + "subgoals should have the same size."); // checks if a query arg is unifiable with the corresponding view arg for (int j = 0; j < queryArgs.size(); j ++) { Argument queryArg = (Argument) queryArgs.elementAt(j); Argument viewArg = (Argument) viewArgs.elementAt(j); if (!queryArg.unifiable(viewArg, phi, hh, view.getDistVars())) return null; } } // transforms vectors to sets HashSet querySubgoalSubset = new HashSet(querySubgoalSeq); HashSet viewSubgoalSubset = new HashSet(viewSubgoalSeq); // checks if the mapping satisfies the PROPERTY if (satisfyProperty(phi, hh, query, querySubgoalSubset, view)) { // finally we got one! MCD mcd = new MCD(query, querySubgoalSubset, hh.apply(view), // applies hh here! viewSubgoalSubset, phi, hh); // hh has been extended UserLib.myprintln("WE FOUND ONE MCD! ==> \n" + mcd); return mcd; } return null; } /** * Checks if a mapping satisfies the PROPERTY. */ private static boolean satisfyProperty(Mapping phi, Mapping hh, Query query, HashSet querySubgoalSubset, Query view) { /*System.out.println("In satisfyProperty()!"); System.out.println("phi = " + phi + "\n" + " hh = " + hh + "query = " + query + "\n" + "querySubgoalSubset = " + querySubgoalSubset + "\n" + "view = " + view);*/ Map map = phi.getMap(); Set entrySet = (Set) map.entrySet(); for (Iterator iter = entrySet.iterator(); iter.hasNext();) { Map.Entry mapEntry = (Map.Entry) iter.next(); Argument queryArg = (Argument) mapEntry.getKey(); Argument viewArg = (Argument) mapEntry.getValue(); /*System.out.println("queryArg = " + queryArg + " viewArg = " + viewArg );*/ // it's OK if the view arg is distinguished if (view.isDistVar(viewArg)) continue; // the view arg is not distinguished, // then the query arg must be distinguished if (query.isDistVar(queryArg)) { UserLib.myprintln("Case 1 failed."); return false; } // queryArg is not distinguished, and viewArg is not either, then // all the query subgoals that use this var should be mapped, i.e., // they are in querySubgoalSubset for (int i = 0; i < query.getSubgoalNum(); i ++) { Subgoal querySubgoal = query.getSubgoal(i); if (querySubgoal.contains(queryArg) // this subgoal uses this var && !querySubgoalSubset.contains(querySubgoal)) { UserLib.myprintln("Case 2 failed."); UserLib.myprintln("querySubgoal = " + querySubgoal + "querySubgoalSubset = " + querySubgoalSubset); return false; } } } return true; } /* for each subgoal g in Q For view V in \V and every subgoal v_i in V Let h be the least restrictive head homomorphism on V such that there exists a mapping \phi, s.t., \phi(g) = h(v). If h and \phi exist, then add to C any new MCD C that can be constructed where: (a) \phi_C (resp. h_C) is an extension of \phi (res. h); (b) G_C is the minimal subset of subgoals of Q such that G_C,\phi)C and h_C satisfy Peoperty I, and (c) it is not possible to extend \phi and h to an MCD that covers fewer subgoals than G_C. Return C. */ /** * Step 2: combines MCDs to generate rewritings. */ /* static HashSet combineMCDs(Query query, HashSet mcds) { // computes the EC function Mapping ec = new Mapping(); for (Iterator iter = mcds.iterator(); iter.hasNext();) { MCD mcd = (MCD) iter.next(); Mapping ec = computeECPsi(ec, mcd); } return genRewritings(query, mcds, ec); } */ /** * Given a set of MCDs (with their psi functions computed) and an EC, * generates rewritings by trying all possible combinations of these MCDs. */ static HashSet combineMCDs(Query query, HashSet mcds) { UserLib.myprintln("calling combineMCDs()..."); HashSet rewritings = new HashSet(); HashSet mcdSubsets = UserLib.genSubsets(mcds); // scans the subsets from the smallest one to the largest one for (int i = 1; i <= mcds.size(); i ++) { for (Iterator iter = mcdSubsets.iterator(); iter.hasNext();) { HashSet oneMCDSubset = (HashSet) iter.next(); if (oneMCDSubset.size() != i) continue; // tries to build an MCD ONLY IF it is not a superset of // another existing subset in the found rewritings if (containsMCDSubset(rewritings, oneMCDSubset)) continue; Mapping ec = computeEC(oneMCDSubset); // computes the EC Rewriting rewriting = buildRewriting(query, oneMCDSubset, ec); if (rewriting != null) rewritings.add(rewriting); } } return rewritings; } /** * computes the EC function for the query and the psi function for a set * of MCDs. */ static Mapping computeEC(HashSet mcdSubset) { Mapping ec = new Mapping(); for (Iterator iter = mcdSubset.iterator(); iter.hasNext();) { MCD mcd = (MCD) iter.next(); computeECPsi(ec, mcd); } // in the case of X1->Y1, Y1->Y2, we need to propogate the mappings to // the tail Mapping pec = new Mapping(); Set keySet = (Set) ec.getMap().keySet(); for (Iterator iter = keySet.iterator(); iter.hasNext();) { Argument headArg = (Argument) iter.next(); Argument tailArg = ec.getTail(headArg); // finds the tail for this srcArg pec.put(headArg, tailArg); } return pec; // returns the propogated EC } /** * computes the EC function for the query and the psi function for the * MCD given an MCD */ static void computeECPsi(Mapping ec, MCD mcd) { // sets the psi /*System.out.println("WWWWW: in computeECPsi()"); System.out.println("WWWWW: ec = " + ec + " mcd = " + mcd);*/ Mapping phi = mcd.getPhi(); Query view = mcd.getView(); // applies the HH on the view Mapping psi = new Mapping(); // scans the args in phi Set entrySet = phi.getMap().entrySet(); for (Iterator iter = entrySet.iterator(); iter.hasNext();) { Map.Entry mapEntry = (Map.Entry) iter.next(); Argument queryArg = (Argument) mapEntry.getKey(); Argument viewArg = (Argument) mapEntry.getValue(); // this view arg should exist in the view viewArg = mcd.getHH().applyTryIdentity(viewArg); if (!view.containsArg(viewArg)) UserLib.myerror("MiniCon.computeECPsi(), didn't find viewArg " + viewArg); Argument oldQueryArg = psi.apply(viewArg); if (oldQueryArg == null) { // this view arg hasn't been mapped. // puts a pair in psi by reversing this pair psi.put(viewArg, queryArg); } else { // this view arg already mapped. extends the ec // oldQueryArg queryArg // \ | // \ | // viewArg /*if (ec.get(queryArg) == null) ec.put(queryArg, oldQueryArg);*/ if (queryArg.equals(oldQueryArg)) continue; // identical if (ec.apply(queryArg) != null) continue; // already mapped ec.put(queryArg, oldQueryArg); } } // sets the psi //System.out.println("WWWWW: computed psi = " + psi); mcd.setPsi(psi); } /** * Given a set of MCDs and an EC, build a rewriting */ static Rewriting buildRewriting(Query query, HashSet oneMCDSubset, Mapping ec) { HashSet coveredQuerySubgoals = new HashSet(); for (Iterator iter = oneMCDSubset.iterator(); iter.hasNext();) { MCD mcd = (MCD) iter.next(); HashSet querySubgoals = mcd.getMappedQuerySubgoals(); // all the subgoals in the MCDs should be disjoint if (!UserLib.disjoint(coveredQuerySubgoals, querySubgoals)) return null; // adds these new subgoals to the whole subgoals coveredQuerySubgoals.addAll(querySubgoals); } // all subgoal subgoals should be covered if (!coveredQuerySubgoals.containsAll(query.getBody())) return null; return createRewriting(query, oneMCDSubset, ec); } /** * creates a rewriting. */ static Rewriting createRewriting(Query query, HashSet oneMCDSubset, Mapping ec) { /*System.out.println("forming a rewriting using MCDs\n " + oneMCDSubset);*/ int id = 0; String name = query.getName(); Subgoal head = ec.apply(query.getHead()); // head Vector body = new Vector(); // body for (Iterator iter = oneMCDSubset.iterator(); iter.hasNext();) { MCD mcd = (MCD) iter.next(); Query view = mcd.getView(); // already applies HH ! Mapping psi = mcd.getPsi(); Subgoal subgoal = ec.apply(psi.apply(view.getHead())); body.add(subgoal); } Query rew = new Query(name, head, body); return new Rewriting(rew, oneMCDSubset, ec); } /** * checks if a mcd subset is a superset of another existing * mcd set in a given set of rewritings. */ private static boolean containsMCDSubset(HashSet rewritings, HashSet oneMCDSubset) { for (Iterator iter = rewritings.iterator(); iter.hasNext();) { Rewriting rewriting = (Rewriting) iter.next(); HashSet mcds = rewriting.getMCDs(); if (oneMCDSubset.containsAll(mcds)) return true; } return false; } // minimizes the rwritings static void minimizeRews() { } static class Prof extends JCProf { String me; long starttime, startcputime; long stoptime, stopcputime; long stoptime2, stopcputime2; Prof(String name) { me = name; } void start() { startcputime = getCpuTime(); // starttime = System.currentTimeMillis(); } void stop() { stopcputime = getCpuTime(); //stoptime = System.currentTimeMillis(); } void stop2() { stopcputime2 = getCpuTime(); //stoptime2 = System.currentTimeMillis(); } void print(){ System.out.println(startcputime + " " + stopcputime + " " + stopcputime2); } } }