public Set findByTopology3(TaxonVariant a, TaxonVariant b, TaxonVariant c) { Set returnVal = new HashSet(); Set aTV = getTaxonLabelHome().expandTaxonVariant(a); Set bTV = getTaxonLabelHome().expandTaxonVariant(b); Set cTV = getTaxonLabelHome().expandTaxonVariant(c); if (aTV.isEmpty() || bTV.isEmpty() || cTV.isEmpty()) { // XXX This avoids a query syntax error later on but maybe isn't // the best behavior. return new HashSet (); } String query = "select distinct a.tree.rootNode " + // Find the trees with three nodes a, b, and c, such that... "from PhyloTreeNode as a, PhyloTreeNode as b, PhyloTreeNode as c, " + // There's a node "ab" (which will be an ancestor of both a and b) "PhyloTreeNode as ab " + // All four nodes are in the same tree "where a.tree = b.tree " + "and a.tree = c.tree " + "and a.tree = ab.tree " + "and a.taxonLabel.taxonVariant in (:a) " + "and b.taxonLabel.taxonVariant in (:b) " + "and c.taxonLabel.taxonVariant in (:c) " + // ab is an ancestor of a "and ab.leftNode < a.leftNode and ab.rightNode > a.rightNode " + // ab is an ancestor of b "and ab.leftNode < b.leftNode and ab.rightNode > b.rightNode " + // ab is NOT an ancestor of c "and (ab.leftNode >= c.leftNode or ab.rightNode <= c.rightNode) "; Query q = getSession().createQuery(query); q.setParameterList("a", aTV); q.setParameterList("b", bTV); q.setParameterList("c", cTV); List rootNodes = q.list(); if (rootNodes.isEmpty()) { return returnVal; } Query t = getSession().createQuery("from PhyloTree where rootNode in (:roots)"); t.setParameterList("roots", rootNodes); returnVal.addAll(t.list()); return returnVal; }