com.actelion.research.util.EncoderIntegerNumbers Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
package com.actelion.research.util;
import com.actelion.research.calc.Logarithm;
import com.actelion.research.chem.descriptor.DescriptorEncoder;
import com.actelion.research.util.datamodel.IntArray;
import java.nio.charset.StandardCharsets;
import java.util.Random;
/**
* Encodes integer numbers into a string.
*/
public class EncoderIntegerNumbers {
private static final int CAPACITY_DATA = 100;
private int min;
private int max;
private int bits;
private int [] dataEncoded;
private int ccBitCounter;
private int ccAddedValuesCounter;
private boolean finalized;
/**
* More values can be added after the constructor was called. However, the must not exceed the min and the max
* value found in arrValue.
* @param arrValue array with the values that will be encoded. Determines also minimum and maximum encoding value.
*/
public EncoderIntegerNumbers(int [] arrValue) {
int min = Integer.MAX_VALUE;
int max = -Integer.MAX_VALUE;
for (int v : arrValue) {
if(vmax){
max=v;
}
}
if(min == max) {
throw new RuntimeException("Range is 0!");
}
initialize(min, max);
for (int v : arrValue) {
add(v);
}
}
private void initialize(int minValue, int maxValue){
min = minValue;
max = maxValue;
int range = max-min;
this.bits = Logarithm.log2(range)+1;
dataEncoded = new int [CAPACITY_DATA];
ccBitCounter = 0;
// The first byte stores the number of bits
ccBitCounter += Byte.SIZE;
// This integer stores the number of added values
ccBitCounter += Integer.SIZE;
// min value
ccBitCounter += Integer.SIZE;
ccAddedValuesCounter = 0;
finalized = false;
}
/**
* Add a value that will be encoded.
* @param v
*/
private void add(int v){
if(finalized){
throw new RuntimeException("Already finalized!");
}
if(v < min) {
throw new RuntimeException("Value lower than minimum!");
}
if(v > max) {
throw new RuntimeException("Value higher than maximum!");
}
int valueNorm = v - min;
for (int i = 0; i < bits; i++) {
if((1 & valueNorm)==1){
BitUtils.setBit(dataEncoded, ccBitCounter);
} else {
BitUtils.unsetBit(dataEncoded, ccBitCounter);
}
valueNorm >>= 1;
ccBitCounter++;
if(!BitUtils.isValidBitIndex(dataEncoded, ccBitCounter)){
int newlen = dataEncoded.length * 2;
dataEncoded = IntArray.resize(dataEncoded, newlen);
}
}
ccAddedValuesCounter++;
}
private void set(int l, int bits, int offset){
for (int i = 0; i < bits; i++) {
int indexBit = offset + i;
if((l & 1)==1){
BitUtils.setBit(dataEncoded, indexBit);
} else {
BitUtils.unsetBit(dataEncoded, indexBit);
}
l >>= 1;
}
}
private int [] finalizeAndGet() {
finalized = true;
int offset = 0;
set(bits, Byte.SIZE, offset);
offset += Byte.SIZE;
set(ccAddedValuesCounter, Integer.SIZE, offset);
offset += Integer.SIZE;
set(min, Integer.SIZE, offset);
int nInteger = ccBitCounter / Integer.SIZE + 1;
int [] data = new int[nInteger];
System.arraycopy(dataEncoded, 0, data, 0, nInteger);
return data;
}
private String encode() {
int [] data = finalizeAndGet();
String strData = new String(new DescriptorEncoder().encode(data), StandardCharsets.UTF_8);
return strData;
}
/**
*
* @param strData
* @return array with decoded values.
*/
public static int [] decode(String strData){
int [] data = new DescriptorEncoder().decode(strData);
return decode(data);
}
private static int [] decode(int [] data) {
int offset = 0;
int bits = decode(data, offset, Byte.SIZE);
offset += Byte.SIZE;
int nAddedValues = decode(data, offset, Integer.SIZE);
offset += Integer.SIZE;
int min = decode(data, offset, Integer.SIZE);
offset += Integer.SIZE;
int [] arrValue = new int[nAddedValues];
for (int i = 0; i < nAddedValues; i++) {
int value = decode(data, offset, bits)+min;
arrValue[i] = value;
offset += bits;
}
return arrValue;
}
private static int decode(int [] data, int offset, int length) {
int l = 0;
int start = offset+length-1;
for (int i = start; i >= offset; i--) {
if(BitUtils.isBitSet(data, i)){
l |= 1;
}
if(i>offset) {
l <<= 1;
}
}
return l;
}
/**
* Convenience method to encode a array with a given precision.
* @param arrValue
* @return
*/
public static String encode(int [] arrValue) {
EncoderIntegerNumbers efpnCoeff = new EncoderIntegerNumbers(arrValue);
return efpnCoeff.encode();
}
public static void main(String[] args) {
IntArray da = new IntArray();
int n = 100;
int min = 0;
int max = 1000;
Random random = new Random();
for (int i = 0; i < n; i++) {
int v = 0;
if(random.nextBoolean()) {
v = random.nextInt(max);
} else {
if(min>0) {
v = -random.nextInt(Math.abs(min));
} else {
v = random.nextInt(max);
}
}
da.add(v);
}
// da.add(18);
// da.add(-70);
// da.add(1);
// da.add(2);
int [] arr = da.get();
EncoderIntegerNumbers encoder = new EncoderIntegerNumbers(arr);
String strData = encoder.encode();
System.out.println(strData);
int [] arrValueDecoded = EncoderIntegerNumbers.decode(strData);
for (int i = 0; i < arrValueDecoded.length; i++) {
System.out.println(arr[i] + "\t" + arrValueDecoded[i]);
}
}
}