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    }