package sets;
import java.util.ArrayList;
import java.util.Iterator;
import lipstone.joshua.parser.exceptions.UndefinedResultException;
import lipstone.joshua.parser.types.BigDec;
public class Set<T> implements Iterable<T> {
protected final ArrayList<T> set;
protected final ArrayList<Set<T>> subsets;
/**
* Constructs an empty set
*/
public Set() {
set = new ArrayList<T>();
subsets = new ArrayList<Set<T>>();
}
/**
* Constructs a clone of a <tt>Set</tt>
*
* @param set
* the set to clone
*/
public Set(Set<T> set) {
this();
this.set.addAll(set.set);
subsets.addAll(set.subsets);
}
private Set(BigDec[] items) {
this();
for (BigDec item : items)
set.add((T) item);
}
/**
* Constructs a Set from an <tt>ArrayList</tt> of items
*
* @param items
* the <tt>ArrayList</tt> of items
*/
public Set(ArrayList<T> items) {
this();
set.addAll(items);
}
/**
* Calculates the subsets of this set and then caches and returns them
*
* @param singularSubsets
* if true, this will not cache the subsets
* @return all of the subsets of this set
* @throws UndefinedResultException
*/
public ArrayList<Set<T>> subsets(boolean singularSubsets) throws UndefinedResultException {
if (subsets.size() == subsetCount())
return subsets;
subsets.add(new Set<T>());
subsets(0, singularSubsets);
return subsets;
}
private ArrayList<Set<T>> subsets(int start, boolean singularSubsets) throws UndefinedResultException {
if (subsets.size() == subsetCount() && !singularSubsets)
return subsets;
ArrayList<Set<T>> subsets = new ArrayList<Set<T>>();
ArrayList<Set<BigDec>> binaryInclusions = binaryRatchet();
binaryInclusions.remove(0);
for (Set<BigDec> binarySet : binaryInclusions) {
ArrayList<T> tempSet = new ArrayList<T>();
boolean include = true;
for (int i = 0; i < set.size(); i++) { //Place all items into tempSet
if (binarySet.get(i).subtract(BigDec.ONE).gteq(BigDec.ZERO))
tempSet.add(set.get(i));
}
Set<T> newSet = new Set<T>(tempSet);
if (((subsets.size() >= 0 && tempSet.size() > 0) || (subsets.size() == 0 && tempSet.size() == 0)) && include && !subsets.contains(newSet))
subsets.add(newSet);
}
if (!singularSubsets || this.subsets.size() == 0)
this.subsets.clear();
return subsets;
}
/**
* Construct an ArrayList containing the inclusion patterns for subsets of this Set. For a Set of Sets (i.e. Set<Set<?>>)
* it will return inclusion patterns from 0 to the number of subsets of that set in each place. For any other structure
* (i.e. Set<String>) it will return binary inclusion patterns.
*
* @return An ArrayList<Set<BigDec>> of all subset inclusion patterns for this set.
*/
protected ArrayList<Set<BigDec>> binaryRatchet() {
ArrayList<Set<BigDec>> output = new ArrayList<Set<BigDec>>();
BigDec[] ioSet = new BigDec[set.size()];
for (int i = 0; i < ioSet.length; i++)
//Initialize all "wheels" to the starting value
ioSet[i] = BigDec.ZERO;
output.add(new Set<BigDec>(ioSet));
ArrayList<Integer> max = new ArrayList<Integer>();
for (int i = 0; i < set.size(); i++)
max.add(1);
boolean isMax = false;
while (!isMax) {
for (int i = 0; i < ioSet.length; i++) {
ioSet[i] = ioSet[i].pp();
if (ioSet[i].gt(new BigDec(max.get(i)))) {
isMax = true;
ioSet[i] = BigDec.ZERO;
}
else {
isMax = false;
break;
}
}
output.add(new Set<BigDec>(ioSet));
}
return output;
}
/**
* This calculates the number of subsets in this set /without/ actually calculating the subsets themselves
*
* @return the number of subsets that this set has
*/
public int subsetCount() {
int count = 1;
try { //If it is a set of Set<?>s, then multiply by the subsetCount() of the Set<?>.
for (int i = 0; i < set.size(); i++)
count *= (((Set<?>) this.get(i)).subsetCount() + 1);
}
catch (ClassCastException e) {
count = ((int) Math.pow(2, set.size()));
}
return count;
}
/**
* @return a <tt>String</tt> generated by putting the set into standard mathematical set notation. Examples:
* <code>{1, 2, 3}, {{1, 6, 5}, {1, 3}}, etc.</code>
*/
@Override
public String toString() {
String output = "{";
for (T i : set)
output = output + i + ", ";
if (output.length() >= 4)
output = output.substring(0, output.length() - 2);
output = output + "}";
return output;
}
/**
* Adds an item to the end of the set
*
* @param item
* the item to add
*/
public void add(T item) {
set.add(item);
}
/**
* Removes the first instance of the given item from the set
*
* @param item
* the item to remove
* @return true if the item was removed, false otherwise
*/
public boolean remove(T item) {
return set.remove(item);
}
/**
* @return the size of this set
*/
public int size() {
return set.size();
}
/**
* @param index
* the index of the item to retrieve
* @return the item at index
* @throws IndexOutOfBoundsException
*/
public T get(int index) throws IndexOutOfBoundsException {
return set.get(index);
}
/**
* @return the iterator for this set
*/
@Override
public Iterator<T> iterator() {
return set.iterator();
}
}