    001package net.sf.cpsolver.studentsct;
    002
    003import java.util.ArrayList;
    004import java.util.Collection;
    005import java.util.Iterator;
    006import java.util.List;
    007import java.util.Set;
    008
    009import net.sf.cpsolver.ifs.model.Model;
    010import net.sf.cpsolver.ifs.model.Neighbour;
    011import net.sf.cpsolver.ifs.solution.Solution;
    012import net.sf.cpsolver.ifs.util.DataProperties;
    013import net.sf.cpsolver.studentsct.constraint.SectionLimit;
    014import net.sf.cpsolver.studentsct.constraint.StudentConflict;
    015import net.sf.cpsolver.studentsct.heuristics.selection.BranchBoundSelection;
    016import net.sf.cpsolver.studentsct.model.Course;
    017import net.sf.cpsolver.studentsct.model.CourseRequest;
    018import net.sf.cpsolver.studentsct.model.Enrollment;
    019import net.sf.cpsolver.studentsct.model.Request;
    020import net.sf.cpsolver.studentsct.model.Student;
    021
    022/**
    023 * Online student sectioning test (using {@link BranchBoundSelection}
    024 * selection). This class is used by the online student sectioning mock-up page. <br>
    025 * <br>
    026 * Usage: <code>
    027 * StudentSctBBTest test = new StudentSctBBTest(student); //student already has all his/her requests defined<br>
    028 * Solution sectioningSolution = test.getSolution(); //solution contains only one student (the given one) with his/her schedule<br>
    029 * Vector sectioningMessages = test.getMessages(); //sectioning messages (to be printed in the GUI).
    030 * </code>
    031 *
    032 * <br>
    033 * <br>
    034 *
    035 * @version StudentSct 1.2 (Student Sectioning)<br>
    036 *          Copyright (C) 2007 - 2010 Tomáš Müller<br>
    037 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    038 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    039 * <br>
    040 *          This library is free software; you can redistribute it and/or modify
    041 *          it under the terms of the GNU Lesser General Public License as
    042 *          published by the Free Software Foundation; either version 3 of the
    043 *          License, or (at your option) any later version. <br>
    044 * <br>
    045 *          This library is distributed in the hope that it will be useful, but
    046 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    047 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    048 *          Lesser General Public License for more details. <br>
    049 * <br>
    050 *          You should have received a copy of the GNU Lesser General Public
    051 *          License along with this library; if not see
    052 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    053 */
    054public class StudentSctBBTest extends Model<Request, Enrollment> {
    055    private Student iStudent = null;
    056    private Solution<Request, Enrollment> iSolution = null;
    057    private long iTime;
    058    private boolean iTimeoutReached = false;
    059
    060    /**
    061     * Constructor
    062     *
    063     * @param student
    064     *            a student to be sectioned
    065     */
    066    public StudentSctBBTest(Student student) {
    067        iStudent = student;
    068        for (Request request : iStudent.getRequests())
    069            addVariable(request);
    070        addGlobalConstraint(new SectionLimit(new DataProperties()));
    071        addConstraint(new StudentConflict(student));
    072    }
    073
    074    /** Return the given student */
    075    public Student getStudent() {
    076        return iStudent;
    077    }
    078
    079    /**
    080     * Compute and return the sectioning solution. It contains only the given
    081     * student with his/her schedule
    082     */
    083    public Solution<Request, Enrollment> getSolution() {
    084        if (iSolution == null) {
    085            iSolution = new Solution<Request, Enrollment>(this);
    086            BranchBoundSelection.Selection selection = new BranchBoundSelection(new DataProperties())
    087                    .getSelection(getStudent());
    088            Neighbour<Request, Enrollment> neighbour = selection.select();
    089            if (neighbour != null)
    090                neighbour.assign(0);
    091            iTime = selection.getTime();
    092            iTimeoutReached = selection.isTimeoutReached();
    093        }
    094        return iSolution;
    095    }
    096
    097    /**
    098     * Return a list of messages ({@link Message} objects) from the sectioning
    099     * of the given student
    100     */
    101    public List<Message> getMessages() {
    102        List<Message> ret = new ArrayList<Message>();
    103        ret.add(new Message(Message.sMsgLevelInfo, null, "<li>Solution found in " + iTime + " ms."));
    104        if (iTimeoutReached)
    105            ret.add(new Message(Message.sMsgLevelInfo, null,
    106                    "<li>Time out reached, solution optimality can not be guaranteed."));
    107        for (Request request : getStudent().getRequests()) {
    108            if (!request.isAlternative() && request.getAssignment() == null) {
    109                ret
    110                        .add(new Message(Message.sMsgLevelWarn, request,
    111                                "<li>Unable to enroll to "
    112                                        + request
    113                                        + ", "
    114                                        + (request instanceof CourseRequest ? ((CourseRequest) request).getCourses()
    115                                                .size() == 1 ? "course is" : "courses are" : "time is")
    116                                        + " not available."));
    117                Collection<Enrollment> values = (request instanceof CourseRequest ? (Collection<Enrollment>) ((CourseRequest) request)
    118                        .getAvaiableEnrollmentsSkipSameTime()
    119                        : request.computeEnrollments());
    120                for (Iterator<Enrollment> f = values.iterator(); f.hasNext();) {
    121                    Enrollment enrollment = f.next();
    122                    Set<Enrollment> conf = conflictValues(enrollment);
    123                    if (conf != null && !conf.isEmpty()) {
    124                        Enrollment conflict = conf.iterator().next();
    125                        if (conflict.equals(enrollment))
    126                            ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of "
    127                                    + enrollment.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")
    128                                    + "<br> is not available."));
    129                        else
    130                            ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of "
    131                                    + enrollment.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")
    132                                    + "<br> conflicts with "
    133                                    + conflict.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;") + "</ul>"));
    134                    }
    135                }
    136            }
    137            if (request instanceof CourseRequest && request.getAssignment() != null) {
    138                CourseRequest courseRequest = (CourseRequest) request;
    139                Enrollment enrollment = request.getAssignment();
    140                List<Enrollment> selectedEnrollments = courseRequest.getSelectedEnrollments(false);
    141                if (selectedEnrollments != null && !selectedEnrollments.isEmpty()
    142                        && !selectedEnrollments.contains(enrollment)) {
    143                    Course course = (courseRequest.getSelectedChoices().iterator().next()).getOffering().getCourse(
    144                            getStudent());
    145                    Enrollment selected = selectedEnrollments.get(0);
    146                    Set<Enrollment> conf = conflictValues(selected);
    147                    if (conf != null && !conf.isEmpty()) {
    148                        ret.add(new Message(Message.sMsgLevelWarn, request,
    149                                "<li>Unable to enroll selected enrollment for " + course.getName() + ", seleted "
    150                                        + (courseRequest.getSelectedChoices().size() == 1 ? "class is" : "classes are")
    151                                        + " conflicting with other choices."));
    152                        Enrollment conflict = conf.iterator().next();
    153                        if (conflict.equals(selected))
    154                            ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of "
    155                                    + selected.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")
    156                                    + "<br> is not available."));
    157                        else
    158                            ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of "
    159                                    + selected.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;")
    160                                    + "<br> conflicts with "
    161                                    + conflict.getName().replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;&nbsp;") + "</ul>"));
    162                    } else {
    163                        ret.add(new Message(Message.sMsgLevelWarn, request,
    164                                "<li>Unable to enroll selected enrollment for " + course.getName() + "."));
    165                    }
    166                }
    167            }
    168        }
    169        return ret;
    170    }
    171
    172    /** Sectioning message */
    173    public static class Message {
    174        /** Message levels */
    175        public static String[] sMsgLevels = { "INFO", "WARN", "ERROR" };
    176        /** Info message level */
    177        public static int sMsgLevelInfo = 0;
    178        /** Warning message level */
    179        public static int sMsgLevelWarn = 1;
    180        /** Error message level */
    181        public static int sMsgLevelError = 2;
    182
    183        private int iLevel;
    184        private Request iRequest;
    185        private String iMessage;
    186
    187        /**
    188         * Constructor
    189         *
    190         * @param level
    191         *            message level (one of
    192         *            {@link StudentSctBBTest.Message#sMsgLevelInfo},
    193         *            {@link StudentSctBBTest.Message#sMsgLevelWarn}, and
    194         *            {@link StudentSctBBTest.Message#sMsgLevelError})
    195         * @param request
    196         *            related course / free time request
    197         * @param message
    198         *            a message
    199         */
    200        public Message(int level, Request request, String message) {
    201            iLevel = level;
    202            iRequest = request;
    203            iMessage = message;
    204        }
    205
    206        /**
    207         * Message level (one of {@link StudentSctBBTest.Message#sMsgLevelInfo},
    208         * {@link StudentSctBBTest.Message#sMsgLevelWarn}, and
    209         * {@link StudentSctBBTest.Message#sMsgLevelError})
    210         */
    211        public int getLevel() {
    212            return iLevel;
    213        }
    214
    215        /** Message level as string */
    216        public String getLevelString() {
    217            return sMsgLevels[iLevel];
    218        }
    219
    220        /** Related course / free time request */
    221        public Request getRequest() {
    222            return iRequest;
    223        }
    224
    225        /** Message */
    226        public String getMessage() {
    227            return iMessage;
    228        }
    229
    230        /** String representation (message level: message) */
    231        @Override
    232        public String toString() {
    233            return getLevelString() + ":" + getMessage();
    234        }
    235    }
    236}