All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.grouplens.lenskit.collections.LongUtils Maven / Gradle / Ivy

The newest version!
/*
 * LensKit, an open source recommender systems toolkit.
 * Copyright 2010-2014 LensKit Contributors.  See CONTRIBUTORS.md.
 * Work on LensKit has been funded by the National Science Foundation under
 * grants IIS 05-34939, 08-08692, 08-12148, and 10-17697.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the
 * License, or (at your option) any later version.
 *
 * This program 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, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package org.grouplens.lenskit.collections;

import it.unimi.dsi.fastutil.longs.*;

import java.util.*;

/**
 * Utilities for working with longs and collections of them from Fastutil.
 *
 * @since 2.0
 * @author GroupLens Research
 * @compat Public
 * @deprecated Replaced by equivalent class in `lenskit-core`.
 */
@Deprecated
public final class LongUtils {
    private LongUtils() {}

    /**
     * Pack longs into a sorted set.
     * @param longs A collection of longs.
     * @return An efficient sorted set containing the numbers in {@code longs}.
     */
    public static LongSortedSet packedSet(Collection longs) {
        return LongKeyDomain.fromCollection(longs, true).activeSetView();
    }

    /**
     * Pack longs into a sorted set.
     * @param longs An array of longs.  This array is copied, not wrapped.
     * @return An efficient sorted set containing the numbers in {@code longs}.
     */
    public static LongSortedSet packedSet(long... longs) {
        return LongKeyDomain.create(longs).activeSetView();
    }

    /**
     * Get a Fastutil {@link it.unimi.dsi.fastutil.longs.LongCollection} from a {@link java.util.Collection} of longs.
     * This method simply casts the collection, if possible, and returns a
     * wrapper otherwise.
     *
     * @param longs A collection of longs.
     * @return The collection as a {@link it.unimi.dsi.fastutil.longs.LongCollection}.
     */
    public static LongCollection asLongCollection(final Collection longs) {
        if (longs instanceof LongCollection) {
            return (LongCollection) longs;
        } else {
            return new LongCollectionWrapper(longs);
        }
    }

    /**
     * Get a Fastutil {@link it.unimi.dsi.fastutil.longs.LongSet} from a {@link java.util.Set} of longs.
     *
     * @param longs The set of longs.
     * @return {@code longs} as a fastutil {@link it.unimi.dsi.fastutil.longs.LongSet}. If {@code longs} is already
     *         a LongSet, it is cast.
     */
    public static LongSet asLongSet(final Set longs) {
        if (longs == null) {
            return null;
        } else if (longs instanceof LongSet) {
            return (LongSet) longs;
        } else {
            return new LongSetWrapper(longs);
        }
    }

    /**
     * Compute the set difference of two sets.
     *
     * @param items   The initial set
     * @param exclude The items to remove
     * @return The elements of items that are not in exclude.
     */
    public static LongSortedSet setDifference(LongSet items, LongSet exclude) {
        long[] data = new long[items.size()];
        final LongIterator iter = items.iterator();
        int i = 0;
        while (iter.hasNext()) {
            final long x = iter.nextLong();
            if (!exclude.contains(x)) {
                data[i++] = x;
            }
        }
        if (!(items instanceof LongSortedSet)) {
            Arrays.sort(data, 0, i);
        }
        // trim the array
        //CHECKSTYLE:OFF MagicNumber
        if (data.length * 2 > i * 3) {
            data = Arrays.copyOf(data, i);
        }
        //CHECKSTYLE:ON
        return new LongSortedArraySet(LongKeyDomain.wrap(data, i, true));
    }

    /**
     * Compute the size of the union of two sets.
     * @param a The first set.
     * @param b The second set.
     * @return The size of the union of the two sets.
     */
    public static int unionSize(LongSortedSet a, LongSortedSet b) {
        if (a instanceof LongSortedArraySet && b instanceof LongSortedArraySet) {
            LongKeyDomain da = ((LongSortedArraySet) a).getDomain();
            LongKeyDomain db = ((LongSortedArraySet) b).getDomain();
            if (da.isCompatibleWith(db)) {
                BitSet bits = (BitSet) da.getActiveMask().clone();
                bits.or(db.getActiveMask());
                return bits.cardinality();
            }
        }

        // we can't do fast bit operations, scan both sets instead
        LongIterator ait = a.iterator();
        LongIterator bit = b.iterator();
        boolean hasA = ait.hasNext();
        boolean hasB = bit.hasNext();
        long nextA = hasA ? ait.nextLong() : Long.MAX_VALUE;
        long nextB = hasB ? bit.nextLong() : Long.MAX_VALUE;
        int nshared = 0;
        while (hasA && hasB) {
            if (nextA < nextB) {
                hasA = ait.hasNext();
                nextA = hasA ? ait.nextLong() : Long.MAX_VALUE;
            } else if (nextB < nextA) {
                hasB = bit.hasNext();
                nextB = hasB ? bit.nextLong() : Long.MAX_VALUE;
            } else {
                nshared += 1;
                hasA = ait.hasNext();
                nextA = hasA ? ait.nextLong() : Long.MAX_VALUE;
                hasB = bit.hasNext();
                nextB = hasB ? bit.nextLong() : Long.MAX_VALUE;
            }
        }
        return a.size() + b.size() - nshared;
    }

    /**
     * Compute the union of two sets.
     *
     * @param a The first set.
     * @param b The second set.
     * @return The elements of items that are not in exclude.
     */
    public static LongSortedSet setUnion(LongSortedSet a, LongSortedSet b) {
        if (a instanceof LongSortedArraySet && b instanceof LongSortedArraySet) {
            LongKeyDomain da = ((LongSortedArraySet) a).getDomain();
            LongKeyDomain db = ((LongSortedArraySet) b).getDomain();
            if (da.isCompatibleWith(db)) {
                LongKeyDomain result = da.clone();
                // we're in-package, go ahead and modify. our job to know it's safe.
                result.getActiveMask().or(db.getActiveMask());
                return result.activeSetView();
            }
        }

        long[] data = new long[unionSize(a, b)];

        LongIterator ait = a.iterator();
        LongIterator bit = b.iterator();
        boolean hasA = ait.hasNext();
        boolean hasB = bit.hasNext();
        long nextA = hasA ? ait.nextLong() : Long.MAX_VALUE;
        long nextB = hasB ? bit.nextLong() : Long.MAX_VALUE;
        int i = 0;
        while (hasA || hasB) {
            if (!hasB || nextA < nextB) {
                // use A
                data[i++] = nextA;
                hasA = ait.hasNext();
                nextA = hasA ? ait.nextLong() : Long.MAX_VALUE;
            } else if (!hasA || nextB < nextA) {
                // use B
                data[i++] = nextB;
                hasB = bit.hasNext();
                nextB = hasB ? bit.nextLong() : Long.MAX_VALUE;
            } else {
                // they're both present and equal, use A but advance both
                // edge case: if one is missing but other is MAX_VALUE, it will go here
                // but that is fine, no harm will be done, as they're both MAX_VALUE
                data[i++] = nextA;
                hasA = ait.hasNext();
                nextA = hasA ? ait.nextLong() : Long.MAX_VALUE;
                hasB = bit.hasNext();
                nextB = hasB ? bit.nextLong() : Long.MAX_VALUE;
            }
        }
        assert i == data.length;

        return new LongSortedArraySet(LongKeyDomain.wrap(data, data.length, true));
    }

    /**
     * Selects a random subset of {@code n} longs from a given set of longs. If fewer than {@code n}
     * items can be selected the whole set is returned. 
     *
     *
     * @param set the set of items to select from
     * @param num The number of random items to add.
     * @param random a random number generator to be used.
     * @return An item selector that selects the items selected by {@code base} plus an additional
     * {@code nRandom} items.
     */
    public static LongSet randomSubset(LongSet set, int num, Random random) {
        return randomSubset(set, num, LongSortedSets.EMPTY_SET, random);
    }
    
    /**
     * Selects a random subset of {@code n} longs from a given set of longs such that no selected 
     * items is in a second set of longs. If fewer than {@code n} items can be selected the whole set is returned. 
     *
     *
     * @param set the set of items to select from
     * @param num The number of random items to add.
     * @param exclude a set of longs which must not be returned
     * @param rng a random number generator to be used.
     * @return An item selector that selects the items selected by {@code base} plus an additional
     * {@code nRandom} items.
     */
    public static LongSortedSet randomSubset(LongSet set, int num, LongSet exclude, Random rng) {
        // FIXME The RNG should come from configuration
        LongSet initial = exclude;
        LongList selected = new LongArrayList(num);
        int n = 0;
        LongIterator iter = set.iterator();
        while (iter.hasNext()) {
            final long item = iter.nextLong();
            if (exclude.contains(item)) {
                continue;
            }
            // algorithm adapted from Wikipedia coverage of Fisher-Yates shuffle
            // https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
            int j = rng.nextInt(n + 1);
            n = n + 1;
            if (j < num) {
                if (j == selected.size()) {
                    selected.add(item);
                } else {
                    long old = selected.getLong(j);
                    if (selected.size() ==  num) {
                        selected.set(num - 1, old);
                    } else {
                        selected.add(old);
                    }
                    selected.set(j, item);
                }
            }
        }
        return LongUtils.packedSet(selected);

    }
    
    /**
     * Wrapper class that implements a {@link LongCollection} by delegating to
     * a {@link Collection}.
     *
     * @author GroupLens Research
     */
    private static class LongCollectionWrapper implements LongCollection {
        protected final Collection base;

        LongCollectionWrapper(Collection b) {
            base = b;
        }

        @Override
        public int size() {
            return base.size();
        }

        @Override
        public boolean contains(long key) {
            return base.contains(key);
        }

        @Override
        public LongIterator iterator() {
            return LongIterators.asLongIterator(base.iterator());
        }

        @Override
        public boolean add(Long item) {
            return base.add(item);
        }

        @Override
        public boolean addAll(Collection items) {
            return base.addAll(items);
        }

        @Override
        public void clear() {
            base.clear();
        }

        @Override
        public boolean contains(Object item) {
            return base.contains(item);
        }

        @Override
        public boolean containsAll(Collection items) {
            return base.containsAll(items);
        }

        @Override
        public boolean isEmpty() {
            return base.isEmpty();
        }

        @Override
        public boolean remove(Object item) {
            return base.remove(item);
        }

        @Override
        public boolean removeAll(Collection items) {
            return base.removeAll(items);
        }

        @Override
        public boolean retainAll(Collection items) {
            return base.retainAll(items);
        }

        @Override
        public Object[] toArray() {
            return base.toArray();
        }

        /**
         * {@inheritDoc}
         *
         * @deprecated see {@link LongCollection#longIterator()}
         */
        @Override
        @Deprecated
        public LongIterator longIterator() {
            return iterator();
        }

        @Override
        public  T[] toArray(T[] a) {
            return base.toArray(a);
        }

        @Override
        public long[] toLongArray() {
            final long[] items = new long[size()];
            LongIterators.unwrap(iterator(), items);
            return items;
        }

        @Override
        public long[] toLongArray(long[] a) {
            long[] output = a;
            if (output.length < size()) {
                output = new long[size()];
            }
            final int sz = LongIterators.unwrap(iterator(), output);
            if (sz < output.length) {
                output = Arrays.copyOf(output, sz);
            }
            return output;
        }

        @Override
        public long[] toArray(long[] a) {
            return toLongArray(a);
        }

        @Override
        public boolean add(long key) {
            return base.add(key);
        }

        @Override
        public boolean rem(long key) {
            return base.remove(key);
        }

        @Override
        public boolean addAll(LongCollection c) {
            return base.addAll(c);
        }

        @Override
        public boolean containsAll(LongCollection c) {
            return base.containsAll(c);
        }

        @Override
        public boolean removeAll(LongCollection c) {
            return base.removeAll(c);
        }

        @Override
        public boolean retainAll(LongCollection c) {
            return base.retainAll(c);
        }
    }

    private static class LongSetWrapper extends LongCollectionWrapper implements LongSet {
        LongSetWrapper(Collection base) {
            super(base);
        }

        @Override
        public boolean remove(long k) {
            return super.rem(k);
        }

        @Override
        public boolean equals(Object obj) {
            return base.equals(obj);
        }

        @Override
        public int hashCode() {
            return base.hashCode();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy