/*
* Created on Jun 20, 2005
*/
package org.seqcode.gseutils;
import java.util.*;
/**
* @author tdanford
*/
public class ShortBitVector implements Comparable<ShortBitVector>, BitVector {
public static void main(String[] args) {
String b = args[0];
char[] array = b.toCharArray();
char m = '1';
short v = ON;
ShortBitVector bv = new ShortBitVector(array, m, v);
String expandString = args[1];
System.out.println(expandString + " --> " + bv.expandString(expandString, "-"));
}
public static short ON = (short)1;
public static short OFF = (short)0;
private static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
private short[] array;
/**
* Creates a blank bit-vector
* @param length The length of the blank vector.
*/
public ShortBitVector(int length) {
array = new short[length];
for(int i = 0; i < length; i++) {
array[i] = OFF;
}
}
/**
* Creates a blank bit-vector
* @param length The length of the blank vector.
* @param value The value of each bit in the new vector.
*/
public ShortBitVector(int length, short value) {
if(value != ON && value != OFF) { throw new IllegalArgumentException(); }
array = new short[length];
for(int i = 0; i < length; i++) {
array[i] = value;
}
}
/**
* Creates a pre-set Bit-vector
* @param _array The array of values for the vector: 0 values become OFF,
* everything else becomes ON.
*/
public ShortBitVector(int[] _array) {
array = new short[_array.length];
for(int i = 0; i < array.length; i++) {
if(_array[i] == 0) {
array[i] = OFF;
} else {
array[i] = ON;
}
}
}
/**
* Creates a BitVector from a raw string representation, with length equal to the
* character array supplied. If _array[i] == maker, then bit_vector[i] == value.
* @param _array The character array, whose values dictate the contents of the bit vector.
* @param marker The character that indicates which bits have 'value.'
* @param value The value of all bits that correspond to "marker" character.
*/
public ShortBitVector(char[] _array, char marker, short value) {
if(value != ON && value != OFF) { throw new IllegalArgumentException(); }
array = new short[_array.length];
short other_value = OFF;
if(value == OFF) { other_value = ON; }
for(int i = 0; i < array.length; i++) {
if(_array[i] == marker) {
array[i] = value;
} else {
array[i] = other_value;
}
}
}
/**
* Copy constructor.
* @param bv The bit-vector to copy.
*/
public ShortBitVector(ShortBitVector bv) {
array = new short[bv.array.length];
for(int i = 0; i < array.length; i++) { array[i] = bv.array[i]; }
}
/**
* Converts a hex string into a BitVector.
* @param length The length of the bit-vector
* @param hArray The hex-character string.
*/
public ShortBitVector(int length, char[] hArray) {
int starter = length % 4;
array = new short[length];
int hIndex = 0;
int aIndex = 0;
if(starter > 0) {
translateHex2Short(hArray[hIndex], array, aIndex, starter);
hIndex += 1;
aIndex += starter;
}
for(; aIndex < length; aIndex += 4, hIndex += 1) {
translateHex2Short(hArray[hIndex], array, aIndex, 4);
}
}
/* (non-Javadoc)
* @see org.seqcode.gseutils.BitVector#toHexString()
*/
public String toHexString() {
StringBuilder sb = new StringBuilder();
int index = 0;
int start = array.length % 4;
if(start > 0) {
sb.append(translateShort2Hex(array, index, start));
index += start;
}
for(; index < array.length; index += 4) {
sb.append(translateShort2Hex(array, index, 4));
}
return sb.toString();
}
/**
* expandString(base, offInsert) takes a string, which should have a length equal to
* the number of ON bits in the vector. It then returns the same string, but with
* the substring offInsert inserted repeatedly for each occurrence of an OFF bit.
* For instance, the bit vector 1101101 will expand the string "aabbc" (with offInsert
* set to "-") into the string "aa-bb-c".
*
* @param base The "base" string which will be inserted.
* @param offInsert The substring which we will insert for each occurrence of an OFF
* bit in the bit-vector.
* @return Returns the expanded String.
*/
public String expandString(String base, String offInsert) {
if(countOnBits() != base.length()) {
throw new IllegalArgumentException("length " + base.length() + " != " +
countOnBits());
}
StringBuilder sb = new StringBuilder(base);
int bi = 0, index = 0;
int offLength = offInsert.length();
for(; index < array.length; index+=1) {
if(array[index]==OFF) {
sb.insert(bi, offInsert);
bi += offLength;
} else {
bi += 1;
}
}
return sb.toString();
}
/* (non-Javadoc)
* @see org.seqcode.gseutils.BitVector#isOn(int)
*/
public boolean isOn(int index) { return array[index] == ON; }
/* (non-Javadoc)
* @see org.seqcode.gseutils.BitVector#isOff(int)
*/
public boolean isOff(int index) { return array[index] == OFF; }
/* (non-Javadoc)
* @see org.seqcode.gseutils.BitVector#length()
*/
public int length() { return array.length; }
/**
* @param offset The offset up to which we should count (inclusive).
* @return The number of "ON" bits with index <= offset.
*/
public int countOnBits(int offset) {
int count = 0;
for(int i = 0; i <= offset; i++) {
if(array[i] == ON) {
count += 1;
}
}
return count;
}
/**
* @param onBitIndex The number of the "on" bit which we want the index of.
* @return The index (into the total bit-vector) of the specified "on" bit,
* or -1 if onBitIndex < 0 or onBitIndex > # of ON bits.
*/
public int reverseMap(int onBitIndex) {
int bitsSeen = 0;
int i = 0;
for(; i < array.length && bitsSeen <= onBitIndex; i++) {
if(array[i] == ON) { bitsSeen += 1; }
}
if(i < array.length) { return i-1; }
return -1;
}
/* (non-Javadoc)
* @see org.seqcode.gseutils.BitVector#countOnBits()
*/
public int countOnBits() {
return countOnBits(array.length-1);
}
/* (non-Javadoc)
* @see org.seqcode.gseutils.BitVector#turnOnBit(int)
*/
public void turnOnBit(int index) { array[index] = ON; }
/* (non-Javadoc)
* @see org.seqcode.gseutils.BitVector#turnOffBit(int)
*/
public void turnOffBit(int index) { array[index] = OFF; }
public void bitwiseOR(ShortBitVector bv) {
if(array.length != bv.array.length) { throw new IllegalArgumentException(); }
for(int i = 0; i < array.length; i++) {
if(array[i] == ON || bv.array[i] == ON) {
array[i] = ON;
} else {
array[i] = OFF;
}
}
}
public void bitwiseAND(ShortBitVector bv) {
if(array.length != bv.array.length) { throw new IllegalArgumentException(); }
for(int i = 0; i < array.length; i++) {
if(array[i] == ON && bv.array[i] == ON) {
array[i] = ON;
} else {
array[i] = OFF;
}
}
}
public void flipLR() {
short[] newArray = new short[array.length];
for(int i = 0; i < array.length; i++) {
newArray[array.length-i-1] = array[i];
}
array = newArray;
}
public boolean matches(String pattern) {
if(pattern.length() != array.length) { return false; }
for(int i = 0; i < array.length; i++) {
char p = pattern.charAt(i);
if(p != '?') {
if(p != '1' && p != '0') { return false; }
if(p == '1' && array[i] == OFF) { return false; }
if(p == '0' && array[i] == ON) { return false; }
}
}
return true;
}
public boolean equals(Object o) {
if(!(o instanceof ShortBitVector)) { return false; }
ShortBitVector bv = (ShortBitVector)o;
if(array.length != bv.array.length) { return false; }
for(int i = 0; i< array.length; i++) {
if(array[i] != bv.array[i]) { return false; }
}
return true;
}
public int hashCode() {
int code = 17;
for(int i = 0; i < array.length; i++) {
if(array[i] == ON) {
code += i; code *= 37;
}
}
return code;
}
public String toString() {
return buildShortBitArrayString(array, 0, array.length);
}
public int compareTo(ShortBitVector bv) {
if(array.length < bv.array.length) { return -1; }
if(array.length > bv.array.length) { return 1; }
for(int i = 0; i < array.length; i++) {
if(array[i] < bv.array[i]) { return -1; }
if(array[i] > bv.array[i]) { return 1; }
}
return 0;
}
/*
* Static Helper Methods
*/
public static Vector<ShortBitVector> createAllBitVectors(int length) {
Vector<ShortBitVector> vector = new Vector<ShortBitVector>();
ShortBitVector base = new ShortBitVector(length);
addAllBitVectors(vector, base, 0);
return vector;
}
private static void addAllBitVectors(Vector<ShortBitVector> vector, ShortBitVector base, int position) {
if(position < base.length()) {
base.turnOffBit(position);
addAllBitVectors(vector, base, position+1);
base.turnOnBit(position);
addAllBitVectors(vector, base, position+1);
} else {
vector.add(new ShortBitVector(base));
}
}
private static int findHexChar(char c) {
for(int i = 0; i < hexChars.length; i++) {
if(hexChars[i] == c) { return i; }
}
return -1;
}
private static char translateShort2Hex(short[] array, int offset, int length) {
int hexIndex = 0;
int placeSize = 1;
for(int i = offset + length - 1; i >= offset; i--) {
if(array[i] == ON) { hexIndex += placeSize; }
placeSize *= 2;
}
return hexChars[hexIndex];
}
private static void translateHex2Short(char hexChar, short[] array, int offset, int length) {
int value = findHexChar(hexChar);
if(value == -1) { throw new IllegalArgumentException(); }
int placeSize = 2;
for(int i = offset+length-1; i>= offset; i--) {
int rem = value % placeSize;
if(rem != 0) {
array[i] = ON;
} else {
array[i] = OFF;
}
value -= rem;
placeSize *= 2;
}
}
private static String buildShortBitArrayString(short[] array, int offset, int length) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < length; i++) {
if(array[offset+i] == ON) {
sb.append("1");
} else {
sb.append("0");
}
}
return sb.toString();
}
}