001    package net.sf.cpsolver.ifs.heuristics;
002    
003    import java.util.Enumeration;
004    import java.util.Vector;
005    
006    import net.sf.cpsolver.ifs.util.ToolBox;
007    
008    /**
009     * A general roulette wheel selection.
010     * An object is selected randomly, proportionaly to the provided weight.
011     * This class also supports multiple selections (it implements {@link Enumeration} interface).
012     *
013     * <br><br>
014     * 
015     * @version
016     * StudentSct 1.1 (Student Sectioning)<br>
017     * Copyright (C) 2007 Tomáš Müller<br>
018     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
019     * Lazenska 391, 76314 Zlin, Czech Republic<br>
020     * <br>
021     * This library is free software; you can redistribute it and/or
022     * modify it under the terms of the GNU Lesser General Public
023     * License as published by the Free Software Foundation; either
024     * version 2.1 of the License, or (at your option) any later version.
025     * <br><br>
026     * This library is distributed in the hope that it will be useful,
027     * but WITHOUT ANY WARRANTY; without even the implied warranty of
028     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
029     * Lesser General Public License for more details.
030     * <br><br>
031     * You should have received a copy of the GNU Lesser General Public
032     * License along with this library; if not, write to the Free Software
033     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
034     */
035    
036    public class RouletteWheelSelection implements Enumeration {
037        private Vector iAdepts = new Vector(), iPoints = new Vector();
038        private double iTotalPoints = 0, iUsedPoints = 0;
039        private int iFirst = 0;
040        
041        /** 
042         * Add an adept to the selection
043         * @param adept an object
044         * @param points object weight (more points, better chance to be selected)
045         */
046        public void add(Object adept, double points) {
047            iAdepts.add(adept);
048            iPoints.add(new Double(points));
049            iTotalPoints+=points;
050        }
051        
052        private void swap(int idx1, int idx2) {
053            Object a1 = iAdepts.elementAt(idx1);
054            Object a2 = iAdepts.elementAt(idx2);
055            iAdepts.setElementAt(a2, idx1);
056            iAdepts.setElementAt(a1, idx2);
057            Object p1 = iPoints.elementAt(idx1);
058            Object p2 = iPoints.elementAt(idx2);
059            iPoints.setElementAt(p2, idx1);
060            iPoints.setElementAt(p1, idx2);
061        }
062        
063        /** Are there still some adepts that have not been yet selected */
064        public boolean hasMoreElements() {
065            return iFirst<iAdepts.size();
066        }
067        
068        /** Perform selection. An object is selected randomly with the probability proportional to the 
069         * provided weight. Each object can be selected only once. 
070         */
071        public Object nextElement() {
072            if (!hasMoreElements()) return null;
073            double rx = ToolBox.random()*iTotalPoints;
074            
075            int iIdx = iFirst; rx -= ((Double)iPoints.elementAt(iIdx)).doubleValue();
076            while (rx>0 && iIdx+1<iAdepts.size()) {
077                iIdx++;
078                rx -= ((Double)iPoints.elementAt(iIdx)).doubleValue();
079            }
080            
081            Object selectedObject = iAdepts.elementAt(iIdx);
082            double points = ((Double)iPoints.elementAt(iIdx)).doubleValue();
083            iTotalPoints -= points;
084            iUsedPoints += points;
085            swap(iFirst, iIdx);
086            iFirst++;
087            
088            return selectedObject;
089        }
090        
091        /** Number of objects in the set */
092        public int size() {
093            return iAdepts.size();
094        }
095        
096        /** Total value of objects that were already returned by the selection. */
097        public double getUsedPoints() {
098            return iUsedPoints;
099        }
100        
101        /** Total value of objects that are still in the selection. */
102        public double getRemainingPoints() {
103            return iTotalPoints;
104        }
105    
106        /** Total value of objects that were added into the selection. */
107        public double getTotalPoints() {
108            return iTotalPoints+iUsedPoints;
109        }
110    }