001    package net.sf.cpsolver.studentsct.filter;
002    
003    import java.util.HashSet;
004    
005    import net.sf.cpsolver.ifs.util.ToolBox;
006    import net.sf.cpsolver.studentsct.model.Student;
007    
008    /**
009     * This student filter accepts every student with the given 
010     * probability. The choice for each student is remembered,
011     * i.e., if the student is passed to the filter multiple times
012     * the same answer is returned.    
013     * 
014     * @version
015     * StudentSct 1.1 (Student Sectioning)<br>
016     * Copyright (C) 2007 Tomáš Müller<br>
017     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
018     * Lazenska 391, 76314 Zlin, Czech Republic<br>
019     * <br>
020     * This library is free software; you can redistribute it and/or
021     * modify it under the terms of the GNU Lesser General Public
022     * License as published by the Free Software Foundation; either
023     * version 2.1 of the License, or (at your option) any later version.
024     * <br><br>
025     * This library is distributed in the hope that it will be useful,
026     * but WITHOUT ANY WARRANTY; without even the implied warranty of
027     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
028     * Lesser General Public License for more details.
029     * <br><br>
030     * You should have received a copy of the GNU Lesser General Public
031     * License along with this library; if not, write to the Free Software
032     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
033     */
034    public class RandomStudentFilter implements StudentFilter {
035        private double iProb = 1.0;
036        private HashSet iAcceptedStudentIds = new HashSet();
037        private HashSet iRejectedStudentIds = new HashSet();
038        
039        /**
040         * Constructor
041         * @param prob probability of acceptance of a student
042         */
043        public RandomStudentFilter(double prob) {
044            iProb = prob;
045        }
046        
047        /**
048         * A student is accepted with the given probability
049         */
050        public boolean accept(Student student) {
051            Long studentId = new Long(student.getId());
052            if (iAcceptedStudentIds.contains(studentId)) return true;
053            if (iRejectedStudentIds.contains(studentId)) return false;
054            boolean accept = (Math.random()<iProb);
055            if (accept)
056                iAcceptedStudentIds.add(studentId);
057            else
058                iRejectedStudentIds.add(studentId);
059            return accept;
060        }
061        
062        /**
063         * Set acceptance probability. Update the sets of accepted and rejected students accordingly.
064         * @param prob new acceptance probability
065         */
066        public void setProbability(double prob) {
067            iProb = prob;
068            int accept = (int)Math.round(prob*(iAcceptedStudentIds.size()+iRejectedStudentIds.size()));
069            while (iAcceptedStudentIds.size()<accept && !iRejectedStudentIds.isEmpty()) {
070                Long studentId = (Long)ToolBox.random(iRejectedStudentIds);
071                iRejectedStudentIds.remove(studentId);
072                iAcceptedStudentIds.add(studentId);
073            }
074            while (iAcceptedStudentIds.size()>accept && !iAcceptedStudentIds.isEmpty()) {
075                Long studentId = (Long)ToolBox.random(iAcceptedStudentIds);
076                iRejectedStudentIds.add(studentId);
077                iAcceptedStudentIds.remove(studentId);
078            }
079        }
080    
081    }