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 probability. The
010     * choice for each student is remembered, i.e., if the student is passed to the
011     * filter multiple times the same answer is returned.
012     * 
013     * @version StudentSct 1.2 (Student Sectioning)<br>
014     *          Copyright (C) 2007 - 2010 Tomas Muller<br>
015     *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
016     *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
017     * <br>
018     *          This library is free software; you can redistribute it and/or modify
019     *          it under the terms of the GNU Lesser General Public License as
020     *          published by the Free Software Foundation; either version 3 of the
021     *          License, or (at your option) any later version. <br>
022     * <br>
023     *          This library is distributed in the hope that it will be useful, but
024     *          WITHOUT ANY WARRANTY; without even the implied warranty of
025     *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
026     *          Lesser General Public License for more details. <br>
027     * <br>
028     *          You should have received a copy of the GNU Lesser General Public
029     *          License along with this library; if not see
030     *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
031     */
032    public class RandomStudentFilter implements StudentFilter {
033        private double iProb = 1.0;
034        private HashSet<Long> iAcceptedStudentIds = new HashSet<Long>();
035        private HashSet<Long> iRejectedStudentIds = new HashSet<Long>();
036    
037        /**
038         * Constructor
039         * 
040         * @param prob
041         *            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        @Override
051        public boolean accept(Student student) {
052            Long studentId = new Long(student.getId());
053            if (iAcceptedStudentIds.contains(studentId))
054                return true;
055            if (iRejectedStudentIds.contains(studentId))
056                return false;
057            boolean accept = (Math.random() < iProb);
058            if (accept)
059                iAcceptedStudentIds.add(studentId);
060            else
061                iRejectedStudentIds.add(studentId);
062            return accept;
063        }
064    
065        /**
066         * Set acceptance probability. Update the sets of accepted and rejected
067         * students accordingly.
068         * 
069         * @param prob
070         *            new acceptance probability
071         */
072        public void setProbability(double prob) {
073            iProb = prob;
074            int accept = (int) Math.round(prob * (iAcceptedStudentIds.size() + iRejectedStudentIds.size()));
075            while (iAcceptedStudentIds.size() < accept && !iRejectedStudentIds.isEmpty()) {
076                Long studentId = ToolBox.random(iRejectedStudentIds);
077                iRejectedStudentIds.remove(studentId);
078                iAcceptedStudentIds.add(studentId);
079            }
080            while (iAcceptedStudentIds.size() > accept && !iAcceptedStudentIds.isEmpty()) {
081                Long studentId = ToolBox.random(iAcceptedStudentIds);
082                iRejectedStudentIds.add(studentId);
083                iAcceptedStudentIds.remove(studentId);
084            }
085        }
086    
087    }