edu.udo.scaffoldhunter.model.util.Subsets.java Source code

Java tutorial

Introduction

Here is the source code for edu.udo.scaffoldhunter.model.util.Subsets.java

Source

/*
 * Scaffold Hunter
 * Copyright (C) 2006-2008 PG504
 * Copyright (C) 2010-2011 PG552
 * See README.txt in the root directory of the Scaffold Hunter source tree
 * for details.
 *
 * Scaffold Hunter is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scaffold Hunter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package edu.udo.scaffoldhunter.model.util;

import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import edu.udo.scaffoldhunter.model.db.Molecule;
import edu.udo.scaffoldhunter.model.db.Scaffold;
import edu.udo.scaffoldhunter.model.db.Session;
import edu.udo.scaffoldhunter.model.db.Subset;
import edu.udo.scaffoldhunter.util.SwappingArrayList;

/**
 * @author Dominic Sacr
 * 
 */
public class Subsets {

    /**
     * Returns an Iterable which can be used to perform a preorder iteration
     * over the subset tree rooted at <code>subset</code>.
     * 
     * @param subset
     *            the root of the iterated subtree
     * @return an iterable which provides an iterator which performs a preorder
     *         iteration of the subtree rooted at <code>subset</code>
     * 
     */
    public static Iterable<Subset> getSubsetTreeIterable(Subset subset) {
        return new SubsetTreeIterable(subset);
    }

    private static class SubsetTreeIterable implements Iterable<Subset> {

        private final Subset subset;

        private SubsetTreeIterable(Subset root) {
            this.subset = root;
        }

        @Override
        public Iterator<Subset> iterator() {

            return new Iterator<Subset>() {

                Subset next = subset;
                private Deque<Iterator<Subset>> level = next == null ? null : new LinkedList<Iterator<Subset>>();

                @Override
                public void remove() {
                    throw new UnsupportedOperationException();
                }

                @Override
                public Subset next() {
                    if (next == null)
                        throw new NoSuchElementException();
                    Subset ret = next;
                    if (!next.getChildren().isEmpty()) {
                        level.addFirst(next.getChildren().iterator());
                        next = level.peekFirst().next();
                    } else {
                        while (!level.isEmpty() && !level.peekFirst().hasNext()) {
                            level.pollFirst();
                        }
                        if (level.isEmpty())
                            next = null;
                        else
                            next = level.peekFirst().next();
                    }
                    return ret;
                }

                @Override
                public boolean hasNext() {
                    return next != null;
                }
            };
        }
    }

    /**
     * A functor that returns a subset's title.
     */
    public static Function<Subset, String> getSubsetTitleFunction = new Function<Subset, String>() {
        @Override
        public String apply(Subset input) {
            return input.getTitle();
        }
    };

    /**
     * Creates a random {@link Subset} from a parent {@link Subset}. The
     * {@link Session} is the same as the parents {@link Session}.
     * 
     * @param parent
     *            the {@link Subset} from which the random {@link Subset} should
     *            be created.
     * @param size
     *            the size of the random {@link Subset}
     * 
     * @return the random {@link Subset}
     */
    public static Subset random(Subset parent, int size) {
        Preconditions.checkNotNull(parent);
        Preconditions.checkArgument(parent.size() >= size);
        Preconditions.checkArgument(size >= 0);

        SwappingArrayList<Molecule> randomSelection = new SwappingArrayList<Molecule>();
        randomSelection.addAll(parent.getMolecules());
        Random randomGenerator = new Random();

        int parentSize = parent.size();
        for (int i = 0; i < parentSize - size; i++) {
            randomSelection.swapAndRemove(randomGenerator.nextInt(parentSize - i));
        }
        return new Subset(parent, "random subset", null, parent.getSession(), randomSelection, null);
    }

    /**
     * Creates the union of an arbitrary number of subsets. The {@link Session}
     * is the same as the parents {@link Session}.
     * 
     * @param parent
     *            the parent subset, or null to use the lowest common ancestor
     * @param subsets
     *            the input subsets
     * 
     * @return the newly created subset
     */
    public static Subset union(Subset parent, Iterable<Subset> subsets) {
        Preconditions.checkNotNull(subsets);

        Set<Molecule> molecules = Sets.newHashSet(Iterables.concat(subsets));

        if (parent == null) {
            parent = getLowestCommonAncestor(subsets);
        }

        return new Subset(parent, "union subset", null, parent.getSession(), molecules, null);
    }

    /**
     * Creates the intersection of an arbitrary number of {@link Subsets}. The
     * {@link Session} is the same as the parents {@link Session}.
     * 
     * @param parent
     *            the parent {@link Subset}, or null to use the first input
     *            {@link Subset}
     * @param subsets
     *            the input {@link Subset}s
     * 
     * @return the intersection {@link Subset}
     */
    public static Subset intersection(Subset parent, Iterable<Subset> subsets) {
        Preconditions.checkNotNull(subsets);

        Set<Molecule> molecules = Sets.newHashSet(Iterables.get(subsets, 0));
        for (Subset s : Iterables.skip(subsets, 1)) {
            Set<Molecule> set = Sets.newHashSet(s);
            molecules.retainAll(set);
        }

        if (parent == null) {
            parent = Iterables.get(subsets, 0);
        }

        return new Subset(parent, "intersection subset", null, parent.getSession(), molecules, null);
    }

    /**
     * Creates the difference of one subset and an arbitrary number of other
     * subsets.The {@link Session} is the same as the parents {@link Session}.
     * 
     * @param parent
     *            the parent subset, or null to use the first input subset
     * @param source
     *            the first input subset (from which the others are subtracted)
     * @param subtract
     *            the other input subsets
     * 
     * @return the newly created subset
     */
    public static Subset difference(Subset parent, Subset source, Iterable<Subset> subtract) {
        Preconditions.checkNotNull(source);
        Preconditions.checkNotNull(subtract);

        Set<Molecule> molecules = Sets.newHashSet(source);
        for (Subset s : subtract) {
            Set<Molecule> set = Sets.newHashSet(s);
            molecules.removeAll(set);
        }

        if (parent == null) {
            parent = source;
        }

        return new Subset(parent, "difference subset", null, parent.getSession(), molecules, null);
    }

    /**
     * Creates a subset for each of the given scaffolds. The subset for a
     * scaffold contains the molecules associated with the scaffold and any of
     * its descendants in the scaffold tree. 
     * 
     * @param parent
     *            the parent subset
     * @param title
     *            prefix of the title of the subsets. We add a unique number as a suffix.
     * @param scaffolds
     *            Scaffolds to create a subtree subset for
     * @return the newly created subsets
     */
    public static Iterable<Subset> subsetsFromSubtrees(Subset parent, String title, Iterable<Scaffold> scaffolds) {
        Preconditions.checkNotNull(parent);
        Preconditions.checkNotNull(scaffolds);
        Preconditions.checkNotNull(title);

        List<Subset> subsets = Lists.newLinkedList();
        int counter = 1;
        for (Scaffold scaffold : scaffolds) {
            Iterable<Molecule> molecules = Scaffolds.getMolecules(Scaffolds.getSubtreePreorderIterable(scaffold));
            subsets.add(
                    new Subset(parent, title + " - " + (counter++), null, parent.getSession(), molecules, null));
        }

        return subsets;
    }

    /**
     * Calculated the lowest common ancestor of all given subsets.
     * 
     * @param subsets
     *            the given subsets.
     * 
     * @return the lowest common ancestor of all the given subsets.
     */
    public static Subset getLowestCommonAncestor(Iterable<Subset> subsets) {
        List<Subset> ancestors = Lists.newArrayList(getAncestors(Iterables.get(subsets, 0)));

        for (Subset s : Iterables.skip(subsets, 1)) {
            ancestors.retainAll(getAncestors(s));
        }

        if (ancestors.size() == 0) {
            throw new IllegalArgumentException(
                    "The subsets do not have a common ancestor. " + "They are not in a common subset tree.");
        }

        return ancestors.get(0);
    }

    /**
     * @param subset
     * 
     * @return the list of ancestors of the given subset, starting with (and
     *         including) the subset itself and ending with the root subset.
     */
    public static List<Subset> getAncestors(Subset subset) {
        List<Subset> ancestors = Lists.newArrayList();

        do {
            ancestors.add(subset);
            subset = subset.getParent();
        } while (subset != null);

        return ancestors;
    }

}