From 5523f0060903823e2770b727f3a0c0de6c46a39b Mon Sep 17 00:00:00 2001 From: "pablo.rodriguez.mier" Date: Fri, 21 Jun 2013 09:58:56 +0200 Subject: [PATCH] New Parallel class provides some functionality to work with parallel processing. ParallelSetCover and IterativeSetCover implementations added. Close #46 --- .../combinatorial/IterativeSetCover.java | 279 ++++++++++++++ .../combinatorial/ParallelSetCover.java | 359 ++++++++++++++++++ .../lab/hipster/util/parallel/Parallel.java | 313 +++++++++++++++ .../combinatorial/IterativeSetCoverTest.java | 20 + 4 files changed, 971 insertions(+) create mode 100644 src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCover.java create mode 100644 src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/ParallelSetCover.java create mode 100644 src/main/java/es/usc/citius/lab/hipster/util/parallel/Parallel.java create mode 100644 src/test/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCoverTest.java diff --git a/src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCover.java b/src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCover.java new file mode 100644 index 0000000..9b45f18 --- /dev/null +++ b/src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCover.java @@ -0,0 +1,279 @@ +package es.usc.citius.lab.hipster.algorithm.combinatorial; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Queue; +import java.util.Set; +import java.util.TreeMap; + + +/** + * This class computes all combinations of sets that covers all of the possible + * elements. Combinations of sets that does not provide new information are not + * considered. The implementation of the class relies on BitSet class and + * performs logic operations between bits. The generation of the combinations is + * done using a Breadth First Search. + * + * @author Pablo Rodríguez Mier + * + * @param + */ +public class IterativeSetCover implements Iterator>> { + + // Ordered map (descending by key) with the available sets + // ordered by size and mapped back to their bitset representation + private TreeMap, BitSet> orderedSets; + // Maps bitset with their set representation + private Map> bitsetMap; + // List of subsets, ordered by size + private List bitsetList; + // Holds an ordered list with all possible elements + private List elements; + // Bit size used to store the information of all elements + private int size; + + // Iterator + private Iterator>> iterator; + + private class State { + State previous; + BitSet selected; + BitSet statebits; + + public State() { + this.previous = null; + this.selected = new BitSet(size); + this.statebits = new BitSet(size); + } + + public State(State previous, BitSet selected) { + this.previous = previous; + this.selected = selected; + this.statebits = new BitSet(size); + this.statebits.or(previous.statebits); + this.statebits.or(selected); + } + + boolean isFinal() { + return this.statebits.cardinality() == size; + } + + Set> stateSets() { + Set> combination = new HashSet>(); + combination.add(bitsetMap.get(this.selected)); + State parent = previous; + while (parent != null) { + Set set = bitsetMap.get(parent.selected); + if (set != null && !set.isEmpty()) { + combination.add(set); + } + parent = parent.previous; + } + return combination; + } + + + Set candidates() { + Set candidateStates = new HashSet(); + Set candidates = new HashSet(); + // Now, select all those bitsets with a bigger index + // which sets some bits of the current bitset + int from = bitsetList.indexOf(this.selected); + // If position = -1, start from 0 + from = (from < 0) ? 0 : from; + List zeros = findBitIndex(this.statebits, false); + for (Integer i : zeros) { + Set c = findByColumn(from, i, true); + // If there is no candidate for the current bit + // then this branch is not solvable + if (c.isEmpty()){ + return Collections.emptySet(); + } + candidates.addAll(c); + } + for(BitSet c : candidates){ + candidateStates.add(new State(this, c)); + } + candidates.clear(); + return candidateStates; + } + + + + } + + public IterativeSetCover(Set> sets) { + this.elements = elements(sets); + this.bitsetList = new ArrayList(); + + this.size = this.elements.size(); + this.orderedSets = new TreeMap, BitSet>( + new Comparator>() { + public int compare(Set o1, Set o2) { + if (o2.size() > o1.size()) { + return 1; + } + return -1; + } + }); + this.bitsetMap = new HashMap>(); + + // Initialize the values of the bitset list + // (there are m sets) + for (Set set : sets) { + // Create a set of n bits (1 bit per element) + BitSet b = new BitSet(this.size); + for (int j = 0; j < this.size; j++) { + // b(j)=1 if the element j appears on set(i) + b.set(j, set.contains(this.elements.get(j))); + } + this.orderedSets.put(set, b); + this.bitsetMap.put(b, set); + } + + // Insert ordered bitsets into a list + for (Entry, BitSet> entry : this.orderedSets.entrySet()) { + this.bitsetList.add(entry.getValue()); + } + this.iterator = enumerate().iterator(); + } + + private Comparator bitComparator(final BitSet source) { + return new Comparator() { + + public int compare(BitSet o1, BitSet o2) { + // Check how many bits of source are changed + BitSet original = new BitSet(); + original.or(source); + // Test o1 + original.or(o1); + Integer sizeO1 = original.size(); + // Reset original bitset + original.xor(original); + original.or(source); + original.or(o2); + Integer sizeO2 = original.size(); + if (sizeO1 > sizeO2) { + return 1; + } + return -1; + } + }; + } + + + /** + * Return BitSets with the bit at position = value + * + * @param value + * True (1) false (0) + */ + public Set findByColumn(Collection bitsets, int position, + boolean value) { + Set rows = new HashSet(); + // Find rows with ones in that position + for (BitSet b : bitsets) { + if (b.get(position) == value) { + rows.add(b); + } + } + return rows; + } + + public Set findByColumn(int fromIndex, int bitPosition, + boolean value) { + Set rows = new HashSet(); + for (int i = fromIndex; i < this.bitsetList.size(); i++) { + BitSet current = this.bitsetList.get(i); + if (current.get(bitPosition) == value) { + rows.add(current); + } + } + return rows; + } + + public List findBitIndex(BitSet bitset, boolean value) { + List indexes = new ArrayList(); + for (int i = 0; i < this.size; i++) { + if (bitset.get(i) == value) { + indexes.add(i); + } + } + return indexes; + } + + // TODO: Optimize this function. + private boolean isDominated(Collection>> solutions, + Set> candidate) { + for (Set> solution : solutions) { + // Check if this combination is worse. If a valid combination + // has less length than the current combination, check if the + // valid combination is a subset of combination. + if (solution.size() < candidate.size()) { + if (candidate.containsAll(solution)) { + return true; + } + } + } + return false; + } + + private List elements(Collection> sets) { + Set universe = new HashSet(); + for (Set set : sets) { + universe.addAll(set); + } + return new ArrayList(universe); + } + + public Collection>> enumerate() { + Collection>> solutions = new LinkedHashSet>>(); + // Queue used for BFS + Queue queue = new LinkedList(); + // Root element + queue.add(new State()); + + // Breadth-First-Search + while (!queue.isEmpty()) { + State next = queue.poll(); + // Check if some candidate is final + for (State candidate : next.candidates()) { + // Discard this candidate if dominated + Set> candidateSets = candidate.stateSets(); + if (!isDominated(solutions, candidateSets)) { + if (candidate.isFinal()) { + // add it as a final + solutions.add(candidateSets); + } else { + queue.add(candidate); + } + } + } + } + return solutions; + } + + public boolean hasNext() { + return iterator.hasNext(); + } + + public Set> next() { + return iterator.next(); + } + + public void remove() { + iterator.remove(); + } + +} diff --git a/src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/ParallelSetCover.java b/src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/ParallelSetCover.java new file mode 100644 index 0000000..3808876 --- /dev/null +++ b/src/main/java/es/usc/citius/lab/hipster/algorithm/combinatorial/ParallelSetCover.java @@ -0,0 +1,359 @@ +package es.usc.citius.lab.hipster.algorithm.combinatorial; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Queue; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ExecutionException; + +import es.usc.citius.lab.hipster.util.parallel.Parallel; + + + +/** + * This class computes all combinations of sets that covers all of the possible + * elements. Combinations of sets that does not provide new information are not + * considered. The implementation of the class relies on BitSet class and + * performs logic operations between bits. The generation of the combinations is + * done using a Parallelized Breadth-First-Search.
+ *
+ * Example:
+ * Suppose you have the following sets: 1={a,c}, 2={a,b}, 3={c}, 4={d}, + * 5={a,b,d}.
+ * + * Then, the goal is to find the whole combinations of sets that cover all + * elements (a,b,c,d). + *
    + *
  • 3 + 5 ({c} U {a,b,e}) it's a valid solution, which uses two sets (3 and + * 5).
  • + *
  • 1 + 5 it's a valid solution, which uses two sets (1 and 5).
  • + *
  • 2 + 3 + 5 it's not a valid solution since there exist a solution which + * takes only sets 3 and 5, thus set 2 is not required and does not provide new + * information. This combination is redundant.
  • + *
+ * + * This problem is based on the SCP (Set Cover Problem) but it does not find the + * combination with the minimum number of sets. Instead, it enumerates all + * possible combinations that cover all elements discarding redundant solutions. + * For more information read http://en.wikipedia.org/wiki/Set_cover_problem + * + * @author Pablo Rodríguez Mier + * + * @param + */ +public class ParallelSetCover implements Iterator>> { + + // Ordered map (descending by key) with the available sets + // ordered by size and mapped back to their bitset representation + private final TreeMap, BitSet> orderedSets; + // Maps bitset with their set representation + private final Map> bitsetMap; + // List of subsets, ordered by size + private final List bitsetList; + // Holds an ordered list with all possible elements + private final List elements; + // Bit size used to store the information of all elements + private int size; + // This collection stores the solutions found + private List>> solutions; + // Queue used for BFS. A synchronized queue is not required + private Queue queue; + // Next element index + private int nextElementIndex = 0; + private Set> nextElement = null; + + /** + * Class Result is used to store the information obtained for each thread + * while performing the BFS + * + */ + private class Result { + Set candidates; + Collection>> solutions; + + Result(Set candidates, Collection>> solutions) { + this.candidates = candidates; + this.solutions = solutions; + } + } + + /** + * State class is used to represent a state node during the search. A state + * is defined by a set of bits (statebits) that indicates which elements are + * selected upon this state, a set of bits (selected) that indicates the + * movement (the set selected) and the previous state.
+ *
+ * Example:
+ * from State1 (initial) to State2 selecting {a,d}
+ * Elements = {a,b,c,d} (4 bits)
+ * State1 = {previous=null, selected=0000, statebits=0000}
+ * State2 = {previous=State1, selected=1001 (a,d), statebits=1001 (0000 | 1001)} + * + */ + private class State { + State previous; + BitSet selected; + BitSet statebits; + + public State() { + this.previous = null; + this.selected = new BitSet(size); + this.statebits = new BitSet(size); + } + + public State(State previous, BitSet selected) { + this.previous = previous; + this.selected = selected; + this.statebits = new BitSet(size); + this.statebits.or(previous.statebits); + this.statebits.or(selected); + } + + boolean isFinal() { + return this.statebits.cardinality() == size; + } + + Set> stateSets() { + Set> combination = new HashSet>(); + combination.add(bitsetMap.get(this.selected)); + State parent = previous; + while (parent != null) { + Set set = bitsetMap.get(parent.selected); + if (set != null && !set.isEmpty()) { + combination.add(set); + } + parent = parent.previous; + } + return combination; + } + + Set candidates() { + Set candidateStates = new HashSet(); + Set candidates = new HashSet(); + // Now, select all those bitsets with a bigger index + // which sets some bits of the current bitset + int from = bitsetList.indexOf(this.selected); + // If position = -1, start from 0 + from = (from < 0) ? 0 : from; + List zeros = findBitIndex(this.statebits, false); + for (Integer i : zeros) { + Set c = findByColumn(from, i, true); + // If there is no candidate for the current bit + // then this branch is not solvable + if (c.isEmpty()) { + return Collections.emptySet(); + } + candidates.addAll(c); + } + for (BitSet c : candidates) { + candidateStates.add(new State(this, c)); + } + candidates.clear(); + return candidateStates; + } + + } + + public ParallelSetCover(Set> sets) + throws InterruptedException, ExecutionException { + + this.solutions = new LinkedList>>(); + // Obtain the elements from the sets + this.elements = elements(sets); + this.bitsetList = new ArrayList(); + this.size = this.elements.size(); + // Sort the collection of sets by the their size + this.orderedSets = new TreeMap, BitSet>( + new Comparator>() { + public int compare(Set o1, Set o2) { + if (o2.size() > o1.size()) { + return 1; + } + return -1; + } + }); + + this.bitsetMap = new HashMap>(); + + // Initialize the values of the bitset list (there are m sets) + for (Set set : sets) { + // Create a set of n bits (1 bit per element) + BitSet b = new BitSet(this.size); + for (int j = 0; j < this.size; j++) { + // b(j)=1 if the element j appears on set(i) + b.set(j, set.contains(this.elements.get(j))); + } + this.orderedSets.put(set, b); + this.bitsetMap.put(b, set); + } + + // Insert ordered bitsets into a list + for (Entry, BitSet> entry : this.orderedSets.entrySet()) { + this.bitsetList.add(entry.getValue()); + } + + // Initialize the queue and put the first states to explore + this.queue = new LinkedList(new State().candidates()); + + } + + /** + * Return BitSets with the bit at position = value + * + * @param value + * True (1) false (0) + */ + public Set findByColumn(Collection bitsets, int position, + boolean value) { + Set rows = new HashSet(); + // Find rows with ones in that position + for (BitSet b : bitsets) { + if (b.get(position) == value) { + rows.add(b); + } + } + return rows; + } + + public Set findByColumn(int fromIndex, int bitPosition, + boolean value) { + Set rows = new HashSet(); + for (int i = fromIndex; i < this.bitsetList.size(); i++) { + BitSet current = this.bitsetList.get(i); + if (current.get(bitPosition) == value) { + rows.add(current); + } + } + return rows; + } + + public List findBitIndex(BitSet bitset, boolean value) { + List indexes = new ArrayList(); + for (int i = 0; i < this.size; i++) { + if (bitset.get(i) == value) { + indexes.add(i); + } + } + return indexes; + } + + // TODO: Optimize this function. + private boolean isDominated(Collection>> solutions, + Set> candidate) { + for (Set> solution : solutions) { + // Check if this combination is worse. If a valid combination + // has less length than the current combination, check if the + // valid combination is a subset of combination. + if (solution.size() < candidate.size()) { + if (candidate.containsAll(solution)) { + return true; + } + } + } + return false; + } + + private List elements(Collection> sets) { + Set universe = new HashSet(); + for (Set set : sets) { + universe.addAll(set); + } + return new ArrayList(universe); + } + + /** + * Parallelized version of the Iterative Set Cover + * + * @return Iterator with all combinations of sets + * @throws ExecutionException + * @throws InterruptedException + */ + public Collection>> enumerate() throws InterruptedException, + ExecutionException { + + return solutions; + + } + + public boolean hasNext() { + + // Breadth-First-Search, parallelized and synchronized by levels. + // In each step, take all states in the same level, process them and + // collect all new candidate states to process in the next step + + while (this.solutions.size() <= this.nextElementIndex + && !this.queue.isEmpty()) { + + Collection nextLevel = null; + try { + + nextLevel = new Parallel.ForEach(queue) + .apply(new Parallel.F() { + public Result apply(State state) { + Set candidates = new HashSet(); + Collection>> localSolutions = new HashSet>>(); + for (State candidate : state.candidates()) { + Set> candidateSets = candidate + .stateSets(); + if (!isDominated(solutions, candidateSets)) { + if (candidate.isFinal()) { + localSolutions.add(candidateSets); + } else { + candidates.add(candidate); + } + } + } + return new Result(candidates, localSolutions); + + } + }).values(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + + // Empty the queue + queue.clear(); + + // Take the results obtained by each thread + for (Result result : nextLevel) { + this.queue.addAll(result.candidates); + this.solutions.addAll(result.solutions); + } + } + // Get the next solution + // TODO: Solutions cannot be removed!!!!!! + if (this.nextElementIndex < solutions.size()) { + this.nextElement = solutions.get(this.nextElementIndex); + this.nextElementIndex++; + } else { + this.nextElement = null; + } + + return this.nextElement != null; + } + + public Set> next() { + return this.nextElement; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/es/usc/citius/lab/hipster/util/parallel/Parallel.java b/src/main/java/es/usc/citius/lab/hipster/util/parallel/Parallel.java new file mode 100644 index 0000000..8c3a8c7 --- /dev/null +++ b/src/main/java/es/usc/citius/lab/hipster/util/parallel/Parallel.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2012 University of Santiago de Compostela + * Centro de Investigación en Tecnoloxías da Información (CITIUS) + * + * This program 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. + * + * 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, see . + */ + +package es.usc.citius.lab.hipster.util.parallel; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + *

+ * This class contains some useful classes and methods to parallelize code in an + * easy and fluent way. Parallel class is self-contained to enable an easier + * integration and reuse in different java projects.
+ * + * Code example:
+ * + *

+ * new ForEach<String, String>(elements).apply(new Function<String>() {
+ * 	public String apply(String element) {
+ * 		System.out.println(element);
+ * 	}
+ * }).values();
+ * 
+ * + * @author Pablo Rodríguez Mier + * @version 13.01, 26 Jan 2013 + */ +public class Parallel { + + private Parallel() { + throw new RuntimeException("Not instantiable"); + } + + /** + * First-order function interface + * + * @author pablo.rodriguez.mier + * + * @param + * Element to transform + * @param + * Result of the transformation + */ + + public static interface F { + /** + * Apply a function over the element e. + * + * @param e + * Input element + * @return transformation result + */ + V apply(E e); + } + + /** + * Action class can be used to define a concurrent task that does not return + * any value after processing the element. + * + * @param + * Element processed within the action + */ + public static abstract class Action implements F { + + /** + * This method is final and cannot be overridden. It applies the action + * implemented by {@link Action#doAction(Object)}. + */ + public final Void apply(E element) { + doAction(element); + return null; + } + + /** + * Defines the action that will be applied over the element. Every + * action must implement this method. + * + * @param element + * element to process + */ + public abstract void doAction(E element); + } + + /** + * This class provides some useful methods to handle the execution of a + * collection of tasks. + * + * @param + * value of the task + */ + public static class TaskHandler { + private Collection> runningTasks = new LinkedList>(); + private ExecutorService executorService; + + public TaskHandler(ExecutorService executor, + Collection> tasks) { + + this.executorService = executor; + + for (Callable task : tasks) { + runningTasks.add(executor.submit(task)); + } + } + + /** + * Get the current tasks (futures) that are being executed. + * + * @return Collection of futures + * @see Future + */ + public Collection> tasks() { + return this.runningTasks; + } + + /** + * This function is equivalent to + * {@link ExecutorService#awaitTermination(long, TimeUnit)} + * + * @see ExecutorService#awaitTermination(long, TimeUnit) + */ + public boolean wait(long timeout, TimeUnit unit) + throws InterruptedException { + return this.executorService.awaitTermination(timeout, unit); + } + + /** + * Retrieves the result of the transformation of each element (the value + * of each Future). This function blocks until all tasks are terminated. + * + * @return a collection with the results of the elements transformation + * @throws InterruptedException + * @throws ExecutionException + */ + public Collection values() throws InterruptedException, + ExecutionException { + Collection results = new LinkedList(); + for (Future future : this.runningTasks) { + results.add(future.get()); + } + return results; + } + } + + /** + * + * @param + * @param + */ + public static class ForEach implements F, TaskHandler> { + // Source elements + private Iterable elements; + // Executor used to invoke concurrent tasks. By default it uses as many + // threads + // as processors available + private ExecutorService executor = Executors.newFixedThreadPool(Runtime + .getRuntime().availableProcessors()); + + public ForEach(Iterable elements) { + this.elements = elements; + } + + /** + * Configure the number of available threads that will be used. Note + * that this configuration has no effect if a custom executor + * {@link ForEach#customExecutor(ExecutorService)} is provided. + * + * @param threads + * number of threads to use + * @return a ForEach instance + */ + public ForEach withThreads(int threads) { + this.executor = Executors.newFixedThreadPool(threads); + return this; + } + + /** + * Set a custom executor service + * + * @param executor + * ExecutorService to use + * @return the instance of ForEach configured with the new executor + * service. + */ + public ForEach customExecutor(ExecutorService executor) { + this.executor = executor; + return this; + } + + /** + * Encapsulates the ForEach instance into a Callable that retrieves a + * TaskHandler with the invoked tasks.
+ * Example:
+ * + *
+		 * Collection<Double> numbers = new Collection<Double>(...);
+		 * Callable<TaskHandler<V>> forEach = new ForEach<Double, String>(numbers)
+		 * 		.prepare(new F<Double, String>() {
+		 * 			String apply(Double e) {
+		 * 				return e.toString();
+		 * 			}
+		 * 		});
+		 * forEach.call().values();
+		 * 
+ * + * @param f + * @return + */ + public Callable> prepare(final F f) { + return new Callable>() { + public TaskHandler call() throws Exception { + return new ForEach(elements).apply(f); + } + }; + } + + public TaskHandler apply(F f) { + return new TaskHandler(executor, map(elements, f)); + } + + private Collection> map(Iterable elements, + final F f) { + // List of concurrent tasks + List> mappedTasks = new LinkedList>(); + // Create a task for each element + for (final E element : elements) { + mappedTasks.add(new Callable() { + public V call() throws Exception { + return f.apply(element); + } + }); + } + return mappedTasks; + } + } + + /** + * InterruptedExceptions occurred during the execution will be thrown as + * RuntimeExceptions. To handle these interruptions, use new For.Each + * instead of this static method. + * + * @param elements + * @param task + * @see Each + */ + public static Collection ForEach(Iterable elements, + F task) { + try { + return new ForEach(elements).apply(task).values(); + } catch (Exception e) { + throw new RuntimeException("ForEach method interrupted. " + + e.getMessage()); + } + } + + /** + * Perform a parallel iteration, similar to a for(i=from;i action) { + + ForEach(new Iterable() { + public Iterator iterator() { + return new Iterator() { + private long current = from; + + public boolean hasNext() { + return current < to; + } + + public Long next() { + return current++; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }, action); + } + +} diff --git a/src/test/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCoverTest.java b/src/test/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCoverTest.java new file mode 100644 index 0000000..61839b3 --- /dev/null +++ b/src/test/java/es/usc/citius/lab/hipster/algorithm/combinatorial/IterativeSetCoverTest.java @@ -0,0 +1,20 @@ +package es.usc.citius.lab.hipster.algorithm.combinatorial; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class IterativeSetCoverTest { + + @Test + public void test() { + /* + Given: Elements of Main Set = {1, 2, 3, 4, 5, 6} + Now, consider 4 subsets as follows: Subset 1 = {1, 2}, Subset 2 = {3, 4}, Subset 3 = {5, 6}, Subset 4 = {1, 3, 5}. + The Greedy algorithm for the above collection of Subsets gives the Minimum Set Cover as: Minimum Set Cover + contains the Subsets= { 1, 2, 3, 4}. + Test with: http://stackoverflow.com/questions/4287302/find-combinations-of-all-sets-set-cover + */ + } + +}