package be.ac.ulg.montefiore.run.jahmm.io;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import be.ac.ulg.montefiore.run.jahmm.ObservationVector;
import be.ac.ulg.montefiore.run.jahmm.Opdf;
/**
* TODO: now only supports binary state for each vector element.
*
* @author Brian Y. Lim
*
*/
public class OpdfVector implements Opdf<ObservationVector> {
private static final long serialVersionUID = -6795564904406631043L;
protected Map<Integer, Double> probs; // where Integer represents the integer form of the vector value in ObservationVector
protected int NUM_OBSERVATION_DIM;
private int NUM_VALUES;
// TODO: now only supports binary state for each vector element.
public static int NUM_OBSERVATION_VALS = 2;
/**
* This is effectively converting from the b emission probability matrix from SupervisedLearner
* TODO: Need to support other methods
* @param b_i b[i] where i is a state
* @param state which output state this emission PDF is for
*/
public OpdfVector(double[] b_i) {
probs = new LinkedHashMap<Integer, Double>();
NUM_VALUES = b_i.length;
NUM_OBSERVATION_DIM = (int)(Math.log(NUM_VALUES) / Math.log(NUM_OBSERVATION_VALS));
for (int j = 0; j < NUM_VALUES; j++) {
// double[] obsVal = toVector(j, NUM_OBSERVATION_VALS, NUM_OBSERVATION_DIM);
double prob = b_i[j];
probs.put(j, prob);
}
}
/**
* Number of permutations that can be formed from binary values of each element of the vector
* @return
*/
public int nbValues() {
return NUM_VALUES;
}
public int dimension() {
return NUM_OBSERVATION_DIM;
}
private OpdfVector() { // for cloning
}
/**
* Takes a number i and converts to n-ary form to populate cells of an array
* E.g. for n=2 and len=5: i=2 gives [0,0,0,1,0], i=7 gives [0,0,1,1,1]
*
* @param number to convert
* @param n the base of the number space
* @param dim length of vector; number of dimensions of vector
* @return
*/
public static double[] toVector(int number, int n, int dim) {
double[] vector = new double[dim];
for (int j = 0; j < dim; j++) {
vector[j] = number % n;
number = number/n; // whittle down
}
return vector;
}
public static int getIntegerEquivalent(double[] vector, int n) {
int value = 0;
for (int j = 0; j < vector.length; j++) { // TODO: change?
// for (int j = vector.length-1; j >= 0; j--) { // reverse order of bits
value += vector[j] * Math.pow(n, j);
}
return value;
}
@Override
public OpdfVector clone() {
OpdfVector clone = new OpdfVector();
clone.probs = new LinkedHashMap<Integer, Double>(this.probs);
return clone;
}
@Override
public void fit(ObservationVector... o) {
// TODO Auto-generated method stub
}
@Override
public void fit(Collection<? extends ObservationVector> o) {
// TODO Auto-generated method stub
}
@Override
public void fit(ObservationVector[] o, double[] weights) {
// TODO Auto-generated method stub
}
@Override
public void fit(Collection<? extends ObservationVector> o, double[] weights) {
// TODO Auto-generated method stub
}
@Override
public ObservationVector generate() {
// TODO Auto-generated method stub
return null;
}
@Override
public double probability(ObservationVector obs) {
int val = getIntegerEquivalent(obs.values(), NUM_OBSERVATION_VALS);
return probs.get(val);
}
public static double EPSILON = 1e-10;
/**
*
* @param k integer equivalent of values vector
* @return
*/
public double probability(int k) {
Double prob = probs.get(k);
if (prob == null) { // means vector value was never encountered before, and so the count is theoretically 0
return EPSILON; // using Laplace smoothing to avoid multiplication by zero
}
else {
return prob;
}
}
@Override
public String toString(NumberFormat nf) {
// TODO Auto-generated method stub
return null;
}
}