Skip to content

Instantly share code, notes, and snippets.

@nwertzberger
Last active August 29, 2015 14:26
Show Gist options
  • Save nwertzberger/e0f972dd476022d0eedb to your computer and use it in GitHub Desktop.
Save nwertzberger/e0f972dd476022d0eedb to your computer and use it in GitHub Desktop.
package objects.model;
import org.pojomatic.Pojomatic;
import org.pojomatic.annotations.AutoProperty;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
/**
* This is a sparse represented version of a transition. It makes the assumption that you wouldn't ask it a question
* it shouldn't answer. This means that if you try to get a transition probability that hasn't been set, and you've set
* the total number of transitions, this will auto-calculate the right transition probability, which is either just
* zero, or will be the proper probability given the number of recorded times that end state was chosen and the default
* occurrences defined.
* <p>
* The equation for probability is as follows:
* (recordedOccurrences_{state} + defaultOccurrences) /
* (totalRecordedOccurrences + defaultOccurrences * totalDestinationStates)
*/
@AutoProperty
public class Transition {
private double random = new Random().nextDouble();
public enum SparseProbabilityCalculation {
NO_PROBABILITY,
SPARSE_PROBABILITY,
RANDOM_PROBABILITY
}
private Map<State, Long> stateOccurrences = new HashMap<>();
private Map<State, Double> stateProbabilities = new HashMap<>();
private final long defaultOccurrences;
private final SparseProbabilityCalculation calculation;
private long totalTransitions;
public Transition() {
this(0, 0, SparseProbabilityCalculation.NO_PROBABILITY);
}
/**
* In many cases, we know the total number of destination states. If you don't know. Set it to 0 or use the default
* constructor. Both of these disable this class's sparse representation of transition probabilities.
*
* @param totalDestinationStates
*/
public Transition(
long totalDestinationStates,
long defaultOccurrences,
SparseProbabilityCalculation calculation) {
this.defaultOccurrences = defaultOccurrences;
this.calculation = calculation;
this.totalTransitions = totalDestinationStates * defaultOccurrences;
}
@Override
public boolean equals(Object that) {
if (that == null) {
return false;
}
if (!(that instanceof Transition)) {
return false;
}
Transition other = (Transition) that;
if (differingProbabilities(other, other.stateProbabilities.keySet()))
return false;
if (differingProbabilities(other, stateProbabilities.keySet()))
return false;
if (differingProbabilities(other, other.stateOccurrences.keySet()))
return false;
if (differingProbabilities(other, stateOccurrences.keySet()))
return false;
return true;
}
private boolean differingProbabilities(
Transition other,
Set<State> stateProbabilities) {
for (State state : stateProbabilities) {
if (Math.abs(
other.getStateProbability(state) - getStateProbability(
state
)
) > Double.MIN_NORMAL) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return Pojomatic.hashCode(this);
}
@Override
public String toString() {
return Pojomatic.toString(this);
}
public Transition withStateProbability(State state, double probability) {
stateProbabilities.put(state, probability);
return this;
}
public double getStateProbability(State state) {
if (calculation == SparseProbabilityCalculation.NO_PROBABILITY) {
return stateProbabilities.getOrDefault(state, 0.0);
}
double rawOccurrences = stateOccurrences.getOrDefault(state, 0L)
+ defaultOccurrences;
return (rawOccurrences * 1.0 / totalTransitions);
}
public synchronized void setStateProbability(State state, double prob) {
if (calculation != SparseProbabilityCalculation.NO_PROBABILITY) {
throw new IllegalStateException(
"Can't set state probabilities directly on sparse calculated transition!"
);
}
stateProbabilities.put(state, prob);
}
public synchronized Transition incrementTransitionOccurrence(State nextState) {
totalTransitions++;
stateOccurrences.compute(nextState, (k, v) -> v == null ? 1 : v + 1);
return this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment