Exemplo n.º 1
0
  public void save() {
    iProgress.setStatus("Saving solution ...");
    org.hibernate.Session hibSession = new ExamDAO().getSession();
    hibSession.setCacheMode(CacheMode.IGNORE);
    Transaction tx = null;
    try {
      tx = hibSession.beginTransaction();
      saveSolution(hibSession);
      tx.commit();

      iProgress.setPhase("Refreshing solution ...", 1);
      try {
        if (SolverServerImplementation.getInstance() != null)
          SolverServerImplementation.getInstance().refreshExamSolution(iSessionId, iExamTypeId);
        iProgress.incProgress();
      } catch (Exception e) {
        iProgress.warn("Unable to refresh solution, reason:" + e.getMessage(), e);
      }
    } catch (Exception e) {
      if (tx != null) tx.rollback();
      iProgress.fatal("Unable to save a solution, reason: " + e.getMessage(), e);
    } finally {
      // here we need to close the session since this code may run in a separate thread
      if (hibSession != null && hibSession.isOpen()) hibSession.close();
    }
  }
Exemplo n.º 2
0
  protected void saveSolution(org.hibernate.Session hibSession) {
    TimetableManager owner =
        TimetableManager.findByExternalId(
            getModel().getProperties().getProperty("General.OwnerPuid"));
    Collection exams = org.unitime.timetable.model.Exam.findAll(iSessionId, iExamTypeId);
    Hashtable<Long, ExamEvent> examEvents = new Hashtable();
    for (Iterator i =
            hibSession
                .createQuery(
                    "select e from ExamEvent e where e.exam.session.uniqueId=:sessionId and e.exam.examType.uniqueId=:examTypeId")
                .setLong("sessionId", iSessionId)
                .setLong("examTypeId", iExamTypeId)
                .iterate();
        i.hasNext(); ) {
      ExamEvent e = (ExamEvent) i.next();
      examEvents.put(e.getExam().getUniqueId(), e);
    }
    iProgress.setPhase("Saving assignments...", exams.size());
    Hashtable examTable = new Hashtable();
    for (Iterator i = exams.iterator(); i.hasNext(); ) {
      iProgress.incProgress();
      org.unitime.timetable.model.Exam exam = (org.unitime.timetable.model.Exam) i.next();
      ExamAssignment oldAssignment = new ExamAssignment(exam);
      exam.setAssignedPeriod(null);
      exam.setAssignedPreference(null);
      exam.getAssignedRooms().clear();
      ExamEvent event = examEvents.get(exam.getUniqueId());
      if (event != null) hibSession.delete(event);
      for (Iterator j = exam.getConflicts().iterator(); j.hasNext(); ) {
        ExamConflict conf = (ExamConflict) j.next();
        hibSession.delete(conf);
        j.remove();
      }
      Exam examVar = null;
      for (Exam x : getModel().variables()) {
        if (exam.getUniqueId().equals(x.getId())) {
          examVar = x;
          break;
        }
      }
      if (examVar == null) {
        iProgress.warn("Exam " + getExamLabel(exam) + " was not loaded.");
        if (oldAssignment.getPeriodId() != null) {
          SubjectArea subject = null;
          Department dept = null;
          for (Iterator j = new TreeSet(exam.getOwners()).iterator(); j.hasNext(); ) {
            ExamOwner xo = (ExamOwner) j.next();
            subject = xo.getCourse().getSubjectArea();
            dept = subject.getDepartment();
            break;
          }
          ChangeLog.addChange(
              hibSession,
              owner,
              exam.getSession(),
              exam,
              exam.getName()
                  + " ("
                  + oldAssignment.getPeriodAbbreviation()
                  + " "
                  + oldAssignment.getRoomsName(", ")
                  + " &rarr; N/A)",
              ChangeLog.Source.EXAM_SOLVER,
              ChangeLog.Operation.UNASSIGN,
              subject,
              dept);
        }
        continue;
      }
      examTable.put(examVar.getId(), exam);
      ExamPlacement placement = getAssignment().getValue(examVar);
      if (placement == null) {
        iProgress.warn("Exam " + getExamLabel(exam) + " has no assignment.");
        if (oldAssignment.getPeriodId() != null) {
          SubjectArea subject = null;
          Department dept = null;
          for (Iterator j = new TreeSet(exam.getOwners()).iterator(); j.hasNext(); ) {
            ExamOwner xo = (ExamOwner) j.next();
            subject = xo.getCourse().getSubjectArea();
            dept = subject.getDepartment();
            break;
          }
          ChangeLog.addChange(
              hibSession,
              owner,
              exam.getSession(),
              exam,
              exam.getName()
                  + " ("
                  + oldAssignment.getPeriodAbbreviation()
                  + " "
                  + oldAssignment.getRoomsName(", ")
                  + " &rarr; N/A)",
              ChangeLog.Source.EXAM_SOLVER,
              ChangeLog.Operation.UNASSIGN,
              subject,
              dept);
        }
        continue;
      }
      ExamPeriod period = new ExamPeriodDAO().get(placement.getPeriod().getId());
      if (period == null) {
        iProgress.warn(
            "Examination period "
                + placement.getPeriod().getDayStr()
                + " "
                + placement.getPeriod().getTimeStr()
                + " not found.");
        if (oldAssignment.getPeriodId() != null) {
          SubjectArea subject = null;
          Department dept = null;
          for (Iterator j = new TreeSet(exam.getOwners()).iterator(); j.hasNext(); ) {
            ExamOwner xo = (ExamOwner) j.next();
            subject = xo.getCourse().getSubjectArea();
            dept = subject.getDepartment();
            break;
          }
          ChangeLog.addChange(
              hibSession,
              owner,
              exam.getSession(),
              exam,
              exam.getName()
                  + " ("
                  + oldAssignment.getPeriodAbbreviation()
                  + " "
                  + oldAssignment.getRoomsName(", ")
                  + " &rarr; N/A)",
              ChangeLog.Source.EXAM_SOLVER,
              ChangeLog.Operation.UNASSIGN,
              subject,
              dept);
        }
        continue;
      }
      exam.setAssignedPeriod(period);
      for (Iterator j = placement.getRoomPlacements().iterator(); j.hasNext(); ) {
        ExamRoomPlacement room = (ExamRoomPlacement) j.next();
        Location location = new LocationDAO().get(room.getId());
        if (location == null) {
          iProgress.warn("Location " + room.getName() + " (id:" + room.getId() + ") not found.");
          continue;
        }
        exam.getAssignedRooms().add(location);
      }
      exam.setAssignedPreference(
          new ExamAssignment(placement, getAssignment()).getAssignedPreferenceString());

      hibSession.saveOrUpdate(exam);
      ExamAssignment newAssignment = new ExamAssignment(exam);
      if (!ToolBox.equals(newAssignment.getPeriodId(), oldAssignment.getPeriodId())
          || !ToolBox.equals(newAssignment.getRooms(), oldAssignment.getRooms())) {
        SubjectArea subject = null;
        Department dept = null;
        for (Iterator j = new TreeSet(exam.getOwners()).iterator(); j.hasNext(); ) {
          ExamOwner xo = (ExamOwner) j.next();
          subject = xo.getCourse().getSubjectArea();
          dept = subject.getDepartment();
          break;
        }
        ChangeLog.addChange(
            hibSession,
            owner,
            exam.getSession(),
            exam,
            exam.getName()
                + " ("
                + (oldAssignment.getPeriod() == null
                    ? "N/A"
                    : oldAssignment.getPeriodAbbreviation()
                        + " "
                        + oldAssignment.getRoomsName(", "))
                + " &rarr; "
                + newAssignment.getPeriodAbbreviation()
                + " "
                + newAssignment.getRoomsName(", ")
                + ")",
            ChangeLog.Source.EXAM_SOLVER,
            ChangeLog.Operation.ASSIGN,
            subject,
            dept);
      }
    }
    iProgress.setPhase("Saving conflicts...", getAssignment().nrAssignedVariables());
    for (Exam examVar : getAssignment().assignedVariables()) {
      iProgress.incProgress();
      org.unitime.timetable.model.Exam exam =
          (org.unitime.timetable.model.Exam) examTable.get(examVar.getId());
      if (exam == null) continue;
      ExamPlacement placement = (ExamPlacement) getAssignment().getValue(examVar);
      ExamAssignmentInfo info = new ExamAssignmentInfo(placement, getAssignment());
      for (Iterator i = info.getDirectConflicts().iterator(); i.hasNext(); ) {
        ExamAssignmentInfo.DirectConflict dc = (ExamAssignmentInfo.DirectConflict) i.next();
        if (dc.getOtherExam() == null) continue;
        if (examVar.getId() < dc.getOtherExam().getExamId().longValue()) {
          org.unitime.timetable.model.Exam otherExam =
              (org.unitime.timetable.model.Exam) examTable.get(dc.getOtherExam().getExamId());
          if (otherExam == null) {
            iProgress.warn(
                "Exam "
                    + dc.getOtherExam().getExamName()
                    + " (id:"
                    + dc.getOtherExam().getExamId()
                    + ") not found.");
            continue;
          }
          ExamConflict conf = new ExamConflict();
          conf.setConflictType(ExamConflict.sConflictTypeDirect);
          conf.setStudents(getStudents(hibSession, dc.getStudents()));
          conf.setNrStudents(conf.getStudents().size());
          hibSession.save(conf);
          exam.getConflicts().add(conf);
          otherExam.getConflicts().add(conf);
          iProgress.debug(
              "Direct conflict of "
                  + dc.getStudents().size()
                  + " students between "
                  + exam.getLabel()
                  + " and "
                  + otherExam.getLabel());
        }
      }
      for (Iterator i = info.getBackToBackConflicts().iterator(); i.hasNext(); ) {
        ExamAssignmentInfo.BackToBackConflict btb =
            (ExamAssignmentInfo.BackToBackConflict) i.next();
        if (examVar.getId() < btb.getOtherExam().getExamId().longValue()) {
          org.unitime.timetable.model.Exam otherExam =
              (org.unitime.timetable.model.Exam) examTable.get(btb.getOtherExam().getExamId());
          if (otherExam == null) {
            iProgress.warn(
                "Exam "
                    + btb.getOtherExam().getExamName()
                    + " (id:"
                    + btb.getOtherExam().getExamId()
                    + ") not found.");
            continue;
          }
          ExamConflict conf = new ExamConflict();
          conf.setConflictType(
              btb.isDistance()
                  ? ExamConflict.sConflictTypeBackToBackDist
                  : ExamConflict.sConflictTypeBackToBack);
          conf.setDistance(btb.getDistance());
          conf.setStudents(getStudents(hibSession, btb.getStudents()));
          conf.setNrStudents(conf.getStudents().size());
          exam.getConflicts().add(conf);
          otherExam.getConflicts().add(conf);
          hibSession.save(conf);
          iProgress.debug(
              "Back-to-back conflict of "
                  + btb.getStudents().size()
                  + " students between "
                  + exam.getLabel()
                  + " and "
                  + otherExam.getLabel());
        }
      }
      m2d:
      for (Iterator i = info.getMoreThanTwoADaysConflicts().iterator(); i.hasNext(); ) {
        ExamAssignmentInfo.MoreThanTwoADayConflict m2d =
            (ExamAssignmentInfo.MoreThanTwoADayConflict) i.next();
        HashSet confExams = new HashSet();
        confExams.add(exam);
        for (Iterator j = m2d.getOtherExams().iterator(); j.hasNext(); ) {
          ExamAssignment otherExamAsg = (ExamAssignment) j.next();
          if (examVar.getId() >= otherExamAsg.getExamId().longValue()) continue m2d;
          org.unitime.timetable.model.Exam otherExam =
              (org.unitime.timetable.model.Exam) examTable.get(otherExamAsg.getExamId());
          if (otherExam == null) {
            iProgress.warn(
                "Exam "
                    + otherExamAsg.getExamName()
                    + " (id:"
                    + otherExamAsg.getExamId()
                    + ") not found.");
            continue;
          }
          confExams.add(otherExam);
        }
        if (confExams.size() >= 3) {
          ExamConflict conf = new ExamConflict();
          conf.setConflictType(ExamConflict.sConflictTypeMoreThanTwoADay);
          conf.setStudents(getStudents(hibSession, m2d.getStudents()));
          conf.setNrStudents(conf.getStudents().size());
          hibSession.save(conf);
          for (Iterator j = confExams.iterator(); j.hasNext(); )
            ((org.unitime.timetable.model.Exam) j.next()).getConflicts().add(conf);
          iProgress.debug(
              "More than 2 a day conflict of "
                  + m2d.getStudents().size()
                  + " students between "
                  + exam.getLabel()
                  + " and "
                  + m2d.getOtherExams());
        }
      }

      for (Iterator i = info.getInstructorDirectConflicts().iterator(); i.hasNext(); ) {
        ExamAssignmentInfo.DirectConflict dc = (ExamAssignmentInfo.DirectConflict) i.next();
        if (dc.getOtherExam() == null) continue;
        if (examVar.getId() < dc.getOtherExam().getExamId().longValue()) {
          org.unitime.timetable.model.Exam otherExam =
              (org.unitime.timetable.model.Exam) examTable.get(dc.getOtherExam().getExamId());
          if (otherExam == null) {
            iProgress.warn(
                "Exam "
                    + dc.getOtherExam().getExamName()
                    + " (id:"
                    + dc.getOtherExam().getExamId()
                    + ") not found.");
            continue;
          }
          ExamConflict conf = new ExamConflict();
          conf.setConflictType(ExamConflict.sConflictTypeDirect);
          conf.setInstructors(getInstructors(hibSession, dc.getStudents()));
          conf.setNrInstructors(conf.getInstructors().size());
          hibSession.save(conf);
          exam.getConflicts().add(conf);
          otherExam.getConflicts().add(conf);
          iProgress.debug(
              "Direct conflict of "
                  + dc.getStudents().size()
                  + " instructors between "
                  + exam.getLabel()
                  + " and "
                  + otherExam.getLabel());
        }
      }
      for (Iterator i = info.getInstructorBackToBackConflicts().iterator(); i.hasNext(); ) {
        ExamAssignmentInfo.BackToBackConflict btb =
            (ExamAssignmentInfo.BackToBackConflict) i.next();
        if (examVar.getId() < btb.getOtherExam().getExamId().longValue()) {
          org.unitime.timetable.model.Exam otherExam =
              (org.unitime.timetable.model.Exam) examTable.get(btb.getOtherExam().getExamId());
          if (otherExam == null) {
            iProgress.warn(
                "Exam "
                    + btb.getOtherExam().getExamName()
                    + " (id:"
                    + btb.getOtherExam().getExamId()
                    + ") not found.");
            continue;
          }
          ExamConflict conf = new ExamConflict();
          conf.setConflictType(
              btb.isDistance()
                  ? ExamConflict.sConflictTypeBackToBackDist
                  : ExamConflict.sConflictTypeBackToBack);
          conf.setDistance(btb.getDistance());
          conf.setInstructors(getInstructors(hibSession, btb.getStudents()));
          conf.setNrInstructors(conf.getInstructors().size());
          exam.getConflicts().add(conf);
          otherExam.getConflicts().add(conf);
          hibSession.save(conf);
          iProgress.debug(
              "Back-to-back conflict of "
                  + btb.getStudents().size()
                  + " instructors between "
                  + exam.getLabel()
                  + " and "
                  + otherExam.getLabel());
        }
      }
      m2d:
      for (Iterator i = info.getInstructorMoreThanTwoADaysConflicts().iterator(); i.hasNext(); ) {
        ExamAssignmentInfo.MoreThanTwoADayConflict m2d =
            (ExamAssignmentInfo.MoreThanTwoADayConflict) i.next();
        HashSet confExams = new HashSet();
        confExams.add(exam);
        for (Iterator j = m2d.getOtherExams().iterator(); j.hasNext(); ) {
          ExamAssignment otherExamAsg = (ExamAssignment) j.next();
          if (examVar.getId() >= otherExamAsg.getExamId().longValue()) continue m2d;
          org.unitime.timetable.model.Exam otherExam =
              (org.unitime.timetable.model.Exam) examTable.get(otherExamAsg.getExamId());
          if (otherExam == null) {
            iProgress.warn(
                "Exam "
                    + otherExamAsg.getExamName()
                    + " (id:"
                    + otherExamAsg.getExamId()
                    + ") not found.");
            continue;
          }
          confExams.add(otherExam);
        }
        if (confExams.size() >= 3) {
          ExamConflict conf = new ExamConflict();
          conf.setConflictType(ExamConflict.sConflictTypeMoreThanTwoADay);
          conf.setInstructors(getInstructors(hibSession, m2d.getStudents()));
          conf.setNrInstructors(conf.getInstructors().size());
          hibSession.save(conf);
          for (Iterator j = confExams.iterator(); j.hasNext(); )
            ((org.unitime.timetable.model.Exam) j.next()).getConflicts().add(conf);
          iProgress.debug(
              "More than 2 a day conflict of "
                  + m2d.getStudents().size()
                  + " instructors between "
                  + exam.getLabel()
                  + " and "
                  + m2d.getOtherExams());
        }
      }
    }
    iProgress.setPhase("Saving events...", getAssignment().nrAssignedVariables());
    String ownerPuid = getModel().getProperties().getProperty("General.OwnerPuid");
    EventContact contact = EventContact.findByExternalUniqueId(ownerPuid);
    if (contact == null) {
      TimetableManager manager = TimetableManager.findByExternalId(ownerPuid);
      contact = new EventContact();
      contact.setFirstName(manager.getFirstName());
      contact.setMiddleName(manager.getMiddleName());
      contact.setLastName(manager.getLastName());
      contact.setExternalUniqueId(manager.getExternalUniqueId());
      contact.setEmailAddress(manager.getEmailAddress());
      hibSession.save(contact);
    }
    for (Exam examVar : getAssignment().assignedVariables()) {
      iProgress.incProgress();
      org.unitime.timetable.model.Exam exam =
          (org.unitime.timetable.model.Exam) examTable.get(examVar.getId());
      if (exam == null) continue;
      ExamEvent event = exam.generateEvent(null, true);
      if (event != null) {
        event.setEventName(examVar.getName());
        event.setMinCapacity(examVar.getSize());
        event.setMaxCapacity(examVar.getSize());
        event.setMainContact(contact);
        hibSession.saveOrUpdate(event);
      }
      if (event != null || !exam.getConflicts().isEmpty()) hibSession.saveOrUpdate(exam);
    }
  }
Exemplo n.º 3
0
 public ExamDatabaseSaver(Solver solver) {
   super(solver);
   iProgress = Progress.getInstance(getModel());
   iSessionId = getModel().getProperties().getPropertyLong("General.SessionId", (Long) null);
   iExamTypeId = getModel().getProperties().getPropertyLong("Exam.Type", null);
 }
  public static void main(String[] args) {
    try {
      DataProperties properties = ToolBox.loadProperties(new java.io.File(args[0]));
      properties.putAll(System.getProperties());
      properties.setProperty(
          "General.Output",
          properties.getProperty("General.Output", ".")
              + File.separator
              + (sDateFormat.format(new Date())));
      if (args.length > 1) properties.setProperty("General.Input", args[1]);
      if (args.length > 2)
        properties.setProperty(
            "General.Output", args[2] + File.separator + (sDateFormat.format(new Date())));
      System.out.println("Output folder: " + properties.getProperty("General.Output"));
      ToolBox.configureLogging(properties.getProperty("General.Output"), properties, false, false);

      File outDir = new File(properties.getProperty("General.Output", "."));
      outDir.mkdirs();

      Solver solver = new Solver<Lecture, Placement>(properties);
      TimetableModel model = new TimetableModel(properties);
      solver.setInitalSolution(model);
      Progress.getInstance(model).addProgressListener(new ProgressWriter(System.out));

      TimetableLoader loader =
          new TimetableXMLLoader(model, solver.currentSolution().getAssignment());
      loader.load();

      solver.initSolver();

      sLogger.info(
          "Starting from: "
              + ToolBox.dict2string(
                  model.getExtendedInfo(solver.currentSolution().getAssignment()), 2));

      PrintWriter csv =
          new PrintWriter(new FileWriter(outDir.toString() + File.separator + "stat.csv"));
      csv.println("class,timeout,#sol,#comb,time,best,timeout,#sol,#comb,time,best");
      csv.flush();

      int depth = Integer.parseInt(System.getProperty("depth", "3"));

      int nrClasses1 = 0, nrClasses2 = 0;
      double bestValue1 = 0, bestValue2 = 0;
      long combinations1 = 0, combinations2 = 0;
      long solutions1 = 0, solutions2 = 0;
      double time1 = 0, time2 = 0;
      int timeout = 0;
      for (Lecture lect : model.variables()) {
        SuggestionsModel m1 = new SuggestionsModel();
        m1.setDepth(depth);
        m1.setTimeout(5000);
        m1.setClassId(lect.getClassId());
        Suggestions s1 = new Suggestions(solver, m1);
        long t0 = System.currentTimeMillis();
        s1.computeSuggestions();
        long t1 = System.currentTimeMillis();
        csv.print(
            lect.getName()
                + ","
                + (s1.getTimeoutReached() ? "T" : "F")
                + ","
                + s1.getNrSolutions()
                + ","
                + s1.getNrCombinationsConsidered()
                + ","
                + (t1 - t0)
                + ","
                + (s1.getSuggestions().isEmpty()
                    ? "-"
                    : ((Suggestion) s1.getSuggestions().first()).getValue())
                + ",");
        csv.flush();
        SuggestionsModel m2 = new SuggestionsModel();
        m2.setDepth(m1.getDepth());
        m2.setTimeout(360000);
        m2.setClassId(lect.getClassId());
        Suggestions s2 = new Suggestions(solver, m2);
        long t2 = System.currentTimeMillis();
        s2.computeSuggestions();
        long t3 = System.currentTimeMillis();
        combinations1 += s1.getNrCombinationsConsidered();
        combinations2 += s2.getNrCombinationsConsidered();
        time1 += (t1 - t0) / 1000.0;
        time2 += (t3 - t2) / 1000.0;
        solutions1 += s1.getNrSolutions();
        solutions2 += s2.getNrSolutions();
        if (s1.getTimeoutReached()) timeout++;
        if (!s1.getSuggestions().isEmpty() && !s2.getSuggestions().isEmpty()) {
          Suggestion x1 = (Suggestion) s1.getSuggestions().first();
          Suggestion x2 = (Suggestion) s2.getSuggestions().first();
          bestValue1 += x1.getValue();
          bestValue2 += x2.getValue();
          nrClasses1++;
          nrClasses2++;
        } else if (!s2.getSuggestions().isEmpty()) {
          nrClasses2++;
        }
        csv.println(
            (s2.getTimeoutReached() ? "T" : "F")
                + ","
                + s2.getNrSolutions()
                + ","
                + s2.getNrCombinationsConsidered()
                + ","
                + (t3 - t2)
                + ","
                + (s2.getSuggestions().isEmpty()
                    ? "-"
                    : ((Suggestion) s2.getSuggestions().first()).getValue()));
        csv.flush();
      }

      csv.close();
      sLogger.info(
          "Number of solutions: "
              + sDoubleFormat.format(100.0 * solutions1 / solutions2)
              + "% ("
              + solutions1
              + " of "
              + solutions2
              + ")");
      sLogger.info(
          "Number of combinations: "
              + sDoubleFormat.format(100.0 * combinations1 / combinations2)
              + "% ("
              + combinations1
              + " of "
              + combinations2
              + ")");
      sLogger.info(
          "Average time needed: "
              + sDoubleFormat.format(time1 / model.variables().size())
              + " (versus "
              + sDoubleFormat.format(time2 / model.variables().size())
              + ")");
      sLogger.info(
          "Timeout reached: "
              + sDoubleFormat.format(100.0 * timeout / model.variables().size())
              + " ("
              + timeout
              + "x)");
      sLogger.info(
          "Improvement found: "
              + sDoubleFormat.format(100.0 * nrClasses1 / model.variables().size())
              + " ("
              + nrClasses1
              + ")");
      sLogger.info(
          "Improvement found (w/o time limit): "
              + sDoubleFormat.format(100.0 * nrClasses2 / model.variables().size())
              + " ("
              + nrClasses2
              + ")");
      sLogger.info("Average improvement: " + sDoubleFormat.format(bestValue1 / nrClasses1));
      sLogger.info(
          "Average improvement (w/o time limit): " + sDoubleFormat.format(bestValue2 / nrClasses1));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }