001 package aima.probability.reasoning; 002 003 import java.util.ArrayList; 004 import java.util.Hashtable; 005 import java.util.List; 006 007 import aima.probability.RandomVariable; 008 import aima.probability.Randomizer; 009 010 /** 011 * @author Ravi Mohan 012 * 013 */ 014 015 public class ParticleSet { 016 017 private List<Particle> particles; 018 019 private HiddenMarkovModel hmm; 020 021 public ParticleSet(HiddenMarkovModel hmm) { 022 particles = new ArrayList<Particle>(); 023 this.hmm = hmm; 024 } 025 026 // Use these two to get the filtered set directly. This is the only method a 027 // user class needs to call. 028 // The other methods are public only to be accessible to tests. 029 030 public ParticleSet filter(String perception, Randomizer r) { 031 return generateParticleSetForPredictedState(r).perceptionUpdate( 032 perception, r); 033 } 034 035 public ParticleSet filter(String action, String perception, Randomizer r) { 036 return generateParticleSetForPredictedState(action, r) 037 .perceptionUpdate(perception, r); 038 } 039 040 // these are internal methods. public only to facilitate testing 041 public int numberOfParticlesWithState(String state) { 042 int total = 0; 043 for (Particle p : particles) { 044 if (p.hasState(state)) { 045 total += 1; 046 } 047 } 048 return total; 049 } 050 051 public void add(Particle particle) { 052 particles.add(particle); 053 054 } 055 056 public int size() { 057 return particles.size(); 058 } 059 060 public RandomVariable toRandomVariable() { 061 List<String> states = new ArrayList<String>(); 062 Hashtable<String, Integer> stateCount = new Hashtable<String, Integer>(); 063 for (Particle p : particles) { 064 String state = p.getState(); 065 if (!(states.contains(state))) { 066 states.add(state); 067 stateCount.put(state, 0); 068 } 069 070 stateCount.put(state, stateCount.get(state).intValue() + 1); 071 072 } 073 074 RandomVariable result = new RandomVariable(states); 075 for (String state : stateCount.keySet()) { 076 result.setProbabilityOf(state, 077 ((double) stateCount.get(state) / particles.size())); 078 } 079 return result; 080 } 081 082 public ParticleSet generateParticleSetForPredictedState( 083 Randomizer randomizer) { 084 return generateParticleSetForPredictedState(HmmConstants.DO_NOTHING, 085 randomizer); 086 } 087 088 public ParticleSet generateParticleSetForPredictedState(String action, 089 Randomizer randomizer) { 090 ParticleSet predictedParticleSet = new ParticleSet(this.hmm); 091 for (Particle p : particles) { 092 String newState = hmm.transitionModel().getStateForProbability( 093 p.getState(), action, randomizer.nextDouble()); 094 095 Particle generatedParticle = new Particle(newState); 096 predictedParticleSet.add(generatedParticle); 097 } 098 return predictedParticleSet; 099 } 100 101 public ParticleSet perceptionUpdate(String perception, Randomizer r) { 102 // compute Particle Weight 103 for (Particle p : particles) { 104 double particleWeight = hmm.sensorModel().get(p.getState(), 105 perception); 106 p.setWeight(particleWeight); 107 } 108 109 // weighted sample to create new ParticleSet 110 ParticleSet result = new ParticleSet(hmm); 111 while (result.size() != size()) { 112 for (Particle p : particles) { 113 double probability = r.nextDouble(); 114 if (probability <= p.getWeight()) { 115 if (result.size() < size()) { 116 result.add(new Particle(p.getState(), p.getWeight())); 117 } 118 } 119 } 120 121 } 122 return result; 123 124 } 125 126 public Particle getParticle(int i) { 127 128 return particles.get(i); 129 } 130 131 }