package mikera.vectorz;
import mikera.vectorz.impl.ABooleanVector;
/**
* Boolean vector backed by densely packed single bits - constrained to 0.0 / 1.0 values
*
* Setting the BitVector will set to 1.0 for any positive values (true) and 0.0 otherwise (false)
*
* Intended for compact representation/storage of boolean vectors
*
* @author Mike
*/
public final class BitVector extends ABooleanVector {
private static final long serialVersionUID = 349277216077562294L;
public static final double BIT_ON=1.0;
public static final double BIT_OFF=0.0;
public static final double BIT_THRESHOLD=0.0;
private final long[] data;
public BitVector(int length) {
super(length);
data=new long[requiredArraySize(length)];
}
private BitVector(AVector source) {
this(source.length());
set(source);
}
private BitVector(BitVector source) {
this(source.data.clone(),source.length());
}
private BitVector(long[] data, int length) {
super(length);
this.data=data;
}
private int requiredArraySize(int length) {
assert(length>=0);
return (length+63)/64;
}
public static BitVector createLength(int length) {
return new BitVector(length);
}
public static BitVector create(AVector source) {
return new BitVector(source);
}
private final boolean getBit(int i) {
return (((data[i>>>6] >>> (i%64))&1L)!=0L);
}
@Override
public double unsafeGet(int i) {
return getBit(i) ? BIT_ON : BIT_OFF;
}
@Override
public double get(int i) {
if ((i<0)||(i>=length)) throw new IndexOutOfBoundsException("Index = "+i);
return getBit(i) ? BIT_ON : BIT_OFF;
}
@Override
public boolean isFullyMutable() {
return false;
}
@Override
public boolean isView() {
return false;
}
@Override
public boolean isZero() {
for (int i=0; i<data.length; i++) {
if (data[i]!=0) return false;
}
return true;
}
@Override
public double elementSum() {
return nonZeroCount();
}
@Override
public double elementMax() {
if (length<1) return -Double.MAX_VALUE;
return isZero()?0.0:1.0;
}
@Override
public double magnitudeSquared() {
return elementSum();
}
@Override
public long nonZeroCount() {
long result=0;
for (int i=0; i<data.length; i++) {
result+=Long.bitCount(data[i]);
}
return result;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public double dotProduct(double[] data, int offset) {
double result=0.0;
for (int i=0; i<this.data.length; i++) {
long mask=this.data[i];
for (int j=0; j<64; j++) {
if (mask==0) break;
if ((mask&1L)!=0L) result+=data[offset+j];
mask>>>=1;
}
offset+=64;
}
return result;
}
@Override
public double dotProduct(AVector v) {
double result=0.0;
int offset=0;
for (int i=0; i<data.length; i++) {
long mask=this.data[i];
for (int j=0; j<64; j++) {
if (mask==0) break;
if ((mask&1L)!=0L) result+=v.unsafeGet(offset+j);
mask>>>=1;
}
offset+=64;
}
return result;
}
@Override
public void getElements(double[] data, int offset) {
int len = length();
for (int i=0; i<len; i++) {
data[i+offset]=unsafeGet(i);
}
}
@Override
public void set(int i, double value) {
if ((i<0)||(i>=length)) throw new IndexOutOfBoundsException("Index: "+i);
int bit=i%64;
long mask = (1L<<bit);
int p=i>>>6;
data[p]=(data[p]&(~mask))|(value>BIT_THRESHOLD?mask:0L);
}
public static BitVector of(double... values) {
int len=values.length;
BitVector b=new BitVector(len);
b.setElements(values);
return b;
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
int length=length();
sb.append('[');
if (length>0) {
sb.append(getBit(0)?'1':'0');
for (int i = 1; i < length; i++) {
sb.append(',');
sb.append(getBit(i)?'1':'0');
}
}
sb.append(']');
return sb.toString();
}
@Override
public BitVector exactClone() {
return new BitVector(this);
}
}