package edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.flow.multiswitch;
import java.util.*;
/*
* Created with IntelliJ IDEA.
* User: Masoud
* Date: 1/22/13
* Time: 11:07 PM <br/>
* A set of limited number of objects.
* This saves memory comparing to a hashset and can find union, intersection faster using bitwise operations
*/
public class MatrixSet<E extends MatrixSet.MatrixObject> implements Set<E>, Cloneable {
private final MatrixMapping<E> mapping;
private long[] matrix;
private int size;
/*public static void setMapping(MatrixMapping matrixMapping) {
if (mapping == null) {
mapping = matrixMapping;
} else {
System.out.println("Mapping has been set before");
mapping = matrixMapping;
//throw new UnsupportedOperationException("RuleSet has been set before");
}
}*/
public MatrixSet(MatrixMapping<E> mapping) {
this.mapping = mapping;
matrix = new long[getLongNums(this.mapping.size())];
size = 0;
}
public MatrixSet(long[] matrix, MatrixMapping<E> mapping) {
this.mapping = mapping;
this.matrix = matrix;
size = getSize(matrix);
}
public static int getLongNums(int rulesNum) {
return (int) Math.ceil(1.0 * rulesNum / 64);
}
public static long[] convertToMatrix(long[] partitionRuleMatrix, Collection<MatrixObject> rules) {
Arrays.fill(partitionRuleMatrix, 0l);
for (MatrixObject rule : rules) {
int longIndex = (rule.getId() - 1) / 64;
int intraIndex = 63 - (rule.getId() - 1) % 64;
partitionRuleMatrix[longIndex] |= (1l << intraIndex);
}
return partitionRuleMatrix;
}
public static void setUnSet(long[] matrix, int index, boolean set) {
int longIndex = index / 64;
int intraIndex = 63 - index % 64;
if (set) {
matrix[longIndex] |= (1l << intraIndex);
} else {
matrix[longIndex] &= ~(1l << intraIndex);
}
}
public static int getSize(long[] union) {
int unionSize = 0;
for (long u : union) {
unionSize += Long.bitCount(u);
}
return unionSize;
}
public static void union(long[] union, long[] longs) {
for (int j = 0; j < longs.length; j++) {
union[j] |= longs[j];
}
}
public static void subtract(long[] union, long[] longs) {
for (int j = 0; j < longs.length; j++) {
union[j] &= ~longs[j];
}
}
public static boolean hasCommon(long[] a, long[] b) {
for (int j = 0; j < a.length; j++) {
if ((a[j] & b[j]) > 0) {
return true;
}
}
return false;
}
public static boolean hasOneAt(long[] longs, int i) {
int longIndex = i / 64;
int intraIndex = 63 - i % 64;
if (longIndex >= longs.length) {
System.out.println();
}
return (longs[longIndex] & (1l << intraIndex)) != 0;
}
public void extend(int newSize) {
long[] newMatrix = new long[getLongNums(newSize)];
System.arraycopy(matrix, 0, newMatrix, 0, Math.min(matrix.length, newMatrix.length));
matrix = newMatrix;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(Object o) {
if (o == null) {
return false;
}
if (o instanceof MatrixObject) {
return hasOneAt(matrix, ((MatrixObject) o).getId() - 1);
}
return false;
}
@Override
public MatrixSet<E> clone() {
MatrixSet<E> output = new MatrixSet<E>(mapping);
System.arraycopy(matrix, 0, output.matrix, 0, matrix.length);
output.size = size;
return output;
}
@Override
public boolean add(E rule) {
if (rule == null) {
return false;
}
final int index = rule.getId() - 1;
boolean alreadyThere = hasOneAt(matrix, index);
if (!alreadyThere) {
setUnSet(matrix, index, true);
size++;
}
return !alreadyThere;
}
@Override
public boolean remove(Object o) {
if (o == null) {
return false;
}
final int index = ((E) o).getId() - 1;
boolean alreadyThere = hasOneAt(matrix, index);
if (alreadyThere) {
setUnSet(matrix, index, false);
size--;
}
return alreadyThere;
}
@Override
public boolean containsAll(Collection<?> c) {
if (c instanceof MatrixSet) {
for (int i = 0; i < matrix.length; i++) {
long l = matrix[i] | ((MatrixSet) c).matrix[i];
if (Long.bitCount(l) > Long.bitCount(matrix[i])) {
return false;
}
}
} else {
for (E rule : (Collection<? extends E>) c) {
if (rule == null) {
return false;
}
if (!hasOneAt(matrix, rule.getId() - 1)) {
return false;
}
}
}
return true;
}
@Override
/*
* Note that it returns always true because of performance
*/
public boolean addAll(Collection<? extends E> c) {
boolean output = false;
if (c instanceof MatrixSet) {
int oldSize = size;
union(matrix, ((MatrixSet) c).matrix);
size = getSize(matrix);
output = size != oldSize;
} else {
for (E rule : c) {
output = add(rule) || output;
}
}
return output;
}
public void copy(MatrixSet src) {
System.arraycopy(src.matrix, 0, matrix, 0, matrix.length);
size = src.size;
}
public int getSimilarity(MatrixSet other) {
int sum = 0;
for (int i = 0; i < matrix.length; i++) {
sum += Long.bitCount(matrix[i] & other.matrix[i]);
}
return sum;
}
@Override
public boolean removeAll(Collection<?> c) {
boolean output = false;
if (c instanceof MatrixSet) {
int oldSize = size;
subtract(matrix, ((MatrixSet) c).matrix);
size = getSize(matrix);
output = size != oldSize;
} else {
for (E rule : (Collection<? extends E>) c) {
output = remove(rule) || output;
}
}
return output;
}
@Override
public boolean retainAll(Collection<?> c) {
int oldSize = size;
if (c instanceof MatrixSet) {
for (int i = 0; i < matrix.length; i++) {
matrix[i] &= ((MatrixSet) c).matrix[i];
}
} else {
for (int i = 0; i < c.size(); i++) {
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
}
size = getSize(matrix);
return size != oldSize;
}
@Override
public void clear() {
Arrays.fill(matrix, 0l);
size = 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MatrixSet rules = (MatrixSet) o;
if (size != rules.size()) {
return false;
}
if (!Arrays.equals(matrix, rules.matrix)) return false;
return true;
}
@Override
public int hashCode() {
return Arrays.hashCode(matrix);
}
@Override
public Iterator<E> iterator() {
// System.out.println("A rule iterator on Matrix ruleset created!!!");
// try {
// throw new RuntimeException();
// } catch (RuntimeException e) {
// e.printStackTrace();
// }
return new RuleIterator();
}
@Override
public Object[] toArray() {
Object[] output = new Object[size()];
final Iterator<E> iterator = iterator();
int i = 0;
while (iterator.hasNext()) {
output[i] = iterator.next();
}
return output;
}
@Override
public <T> T[] toArray(T[] a) {
final int size = size();
if (a.length < size) {
return (T[]) toArray();
}
final Iterator<E> iterator = iterator();
int i = 0;
while (iterator.hasNext()) {
a[i] = (T) iterator.next();
}
a[size] = null;
return a;
}
/**
* Each matrix item must be distinguishable by a unique ID
*/
public static class MatrixObject {
private int id;
protected int getId() {
return id;
}
protected void setId(int id) {
this.id = id;
}
}
public static class MatrixMapping<E extends MatrixObject> extends AbstractCollection<E> {
private final List<E> objects;
public MatrixMapping() {
this.objects = new ArrayList<>();
}
@Override
public Iterator<E> iterator() {
return objects.iterator();
}
public int size() {
return objects.size();
}
public boolean add(E o) {
objects.add(o);
o.setId(objects.size());
return true;
}
public E get(int currentIndex) {
return objects.get(currentIndex);
}
}
private class RuleIterator implements Iterator<E> {
private static final int INITIAL_VALUE = -2;
private static final int INVALID_VALUE = -1;
int nextIndex;
int currentIndex = INITIAL_VALUE;
private RuleIterator() {
nextIndex = findNextIndex();
}
@Override
public boolean hasNext() {
return nextIndex != INVALID_VALUE;
}
@Override
public E next() {
if (nextIndex == INVALID_VALUE) {
throw new NoSuchElementException();
}
currentIndex = nextIndex;
nextIndex++;
nextIndex = findNextIndex();
return (E) mapping.get(currentIndex);
}
@Override
public void remove() {
if (currentIndex >= 0) {
final int index = currentIndex;
boolean alreadyThere = hasOneAt(matrix, index);
if (alreadyThere) {
setUnSet(matrix, index, false);
size--;
}
currentIndex = -1;
}
}
private int findNextIndex() {
for (int i = Math.max(nextIndex, 0); i < matrix.length * 64; i++) {
if (hasOneAt(matrix, i)) {
return i;
}
}
return INVALID_VALUE;
}
}
}