Skip to content

Commit

Permalink
conf scheduling: improve indictment overview in popup on views
Browse files Browse the repository at this point in the history
  • Loading branch information
ge0ffrey committed Mar 6, 2018
1 parent 01b1c07 commit ab54c0f
Showing 1 changed file with 91 additions and 26 deletions.
Expand Up @@ -29,7 +29,9 @@
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
Expand All @@ -45,6 +47,7 @@
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;


import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
Expand All @@ -68,6 +71,8 @@
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.optaplanner.core.api.score.Score; import org.optaplanner.core.api.score.Score;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.optaplanner.core.api.score.constraint.ConstraintMatch;
import org.optaplanner.core.api.score.constraint.ConstraintMatchTotal;
import org.optaplanner.core.api.score.constraint.Indictment; import org.optaplanner.core.api.score.constraint.Indictment;
import org.optaplanner.core.api.solver.SolverFactory; import org.optaplanner.core.api.solver.SolverFactory;
import org.optaplanner.core.impl.score.director.ScoreDirector; import org.optaplanner.core.impl.score.director.ScoreDirector;
Expand Down Expand Up @@ -826,6 +831,7 @@ public void write(ConferenceSolution solution, File outputSolutionFile) {
private static class ConferenceSchedulingXlsxWriter { private static class ConferenceSchedulingXlsxWriter {


protected final ConferenceSolution solution; protected final ConferenceSolution solution;
protected final List<ConstraintMatchTotal> constraintMatchTotalList;
protected final Map<Object, Indictment> indictmentMap; protected final Map<Object, Indictment> indictmentMap;


protected XSSFWorkbook workbook; protected XSSFWorkbook workbook;
Expand Down Expand Up @@ -854,6 +860,8 @@ public ConferenceSchedulingXlsxWriter(ConferenceSolution solution) {
try (ScoreDirector<ConferenceSolution> scoreDirector = scoreDirectorFactory.buildScoreDirector()) { try (ScoreDirector<ConferenceSolution> scoreDirector = scoreDirectorFactory.buildScoreDirector()) {
scoreDirector.setWorkingSolution(solution); scoreDirector.setWorkingSolution(solution);
scoreDirector.calculateScore(); scoreDirector.calculateScore();
constraintMatchTotalList = new ArrayList<>(scoreDirector.getConstraintMatchTotals());
constraintMatchTotalList.sort(Comparator.comparing(ConstraintMatchTotal::getScoreTotal));
indictmentMap = scoreDirector.getIndictmentMap(); indictmentMap = scoreDirector.getIndictmentMap();
} }
} }
Expand All @@ -867,14 +875,15 @@ public Workbook write() {
writeRoomList(); writeRoomList();
writeSpeakerList(); writeSpeakerList();
writeTalkList(); writeTalkList();
writeScoreView(); writeInfeasibleView();
writeRoomsView(); writeRoomsView();
writeSpeakersView(); writeSpeakersView();
writeThemeTracksView(); writeThemeTracksView();
writeSectorsView(); writeSectorsView();
writeAudienceTypesView(); writeAudienceTypesView();
writeAudienceLevelsView(); writeAudienceLevelsView();
writeContentsView(); writeContentsView();
writeScoreView();
return workbook; return workbook;
} }


Expand Down Expand Up @@ -1132,8 +1141,11 @@ private void writeTalkList() {
autoSizeColumnsWithHeader(); autoSizeColumnsWithHeader();
} }


private void writeScoreView() { private void writeInfeasibleView() {
nextSheet("Score view", 1, 1, true); if (solution.getScore() == null || solution.getScore().isFeasible()) {
return;
}
nextSheet("Infeasible view", 1, 1, true);
nextRow(); nextRow();
nextHeaderCell("Score"); nextHeaderCell("Score");
nextCell().setCellValue(solution.getScore() == null ? "Not yet solved" : solution.getScore().toShortString()); nextCell().setCellValue(solution.getScore() == null ? "Not yet solved" : solution.getScore().toShortString());
Expand Down Expand Up @@ -1169,7 +1181,15 @@ private void writeScoreView() {
nextCell().setCellValue(timeslotListSize); nextCell().setCellValue(timeslotListSize);
int roomListSize = solution.getRoomList().size(); int roomListSize = solution.getRoomList().size();
nextCell().setCellValue(roomListSize); nextCell().setCellValue(roomListSize);
int sessionCount = timeslotListSize * roomListSize; int sessionCount = 0;
for (Timeslot timeslot : solution.getTimeslotList()) {
for (Room room : solution.getRoomList()) {
if (!Collections.disjoint(timeslot.getTalkTypeSet(), room.getTalkTypeSet())
&& !room.getUnavailableTimeslotSet().contains(timeslot)) {
sessionCount++;
}
}
}
nextCell(sessionCount < talkListSize ? hardPenaltyStyle : defaultStyle).setCellValue(sessionCount); nextCell(sessionCount < talkListSize ? hardPenaltyStyle : defaultStyle).setCellValue(sessionCount);
autoSizeColumnsWithHeader(); autoSizeColumnsWithHeader();
} }
Expand Down Expand Up @@ -1358,6 +1378,37 @@ private void writeContentsView() {
autoSizeColumnsWithHeader(); autoSizeColumnsWithHeader();
} }


private void writeScoreView() {
nextSheet("Score view", 1, 1, true);
nextRow();
nextCell();
nextHeaderCell("Score");
nextCell().setCellValue(solution.getScore() == null ? "Not yet solved" : solution.getScore().toShortString());
nextRow();
nextRow();
nextHeaderCell("Constraint match");
nextHeaderCell("Match score");
nextHeaderCell("Total score");
for (ConstraintMatchTotal constraintMatchTotal : constraintMatchTotalList) {
nextRow();
nextHeaderCell(constraintMatchTotal.getConstraintName());
nextCell();
nextCell().setCellValue(constraintMatchTotal.getScoreTotal().toShortString());
List<ConstraintMatch> constraintMatchList = new ArrayList<>(constraintMatchTotal.getConstraintMatchSet());
constraintMatchList.sort(Comparator.comparing(ConstraintMatch::getScore));
for (ConstraintMatch constraintMatch : constraintMatchList) {
nextRow();
nextCell().setCellValue(" " + constraintMatch.getJustificationList().stream()
.filter(o -> o instanceof Talk).map(o -> ((Talk) o).getCode())
.collect(joining(", ")));
nextCell().setCellValue(constraintMatch.getScore().toShortString());
nextCell();
nextCell();
}
}
autoSizeColumnsWithHeader();
}

private void writeTimeslotDaysHeaders() { private void writeTimeslotDaysHeaders() {
LocalDate previousTimeslotDay = null; LocalDate previousTimeslotDay = null;
int mergeStart = -1; int mergeStart = -1;
Expand Down Expand Up @@ -1425,11 +1476,10 @@ protected void nextTalkListCell(boolean unavailable, List<Talk> talkList, Functi
if (talkList == null) { if (talkList == null) {
talkList = Collections.emptyList(); talkList = Collections.emptyList();
} }
List<Indictment> indictmentList = talkList.stream() HardSoftScore score = talkList.stream()
.map(indictmentMap::get).filter(Objects::nonNull).collect(Collectors.toList()); .map(indictmentMap::get).filter(Objects::nonNull)
HardSoftScore score = indictmentList.stream()
.flatMap(indictment -> indictment.getConstraintMatchSet().stream()) .flatMap(indictment -> indictment.getConstraintMatchSet().stream())
.map(tConstraintMatch -> (HardSoftScore) tConstraintMatch.getScore()) .map(constraintMatch -> (HardSoftScore) constraintMatch.getScore())
// Filter out positive constraints // Filter out positive constraints
.filter(indictmentScore -> !(indictmentScore.getHardScore() >= 0 && indictmentScore.getSoftScore() >= 0)) .filter(indictmentScore -> !(indictmentScore.getHardScore() >= 0 && indictmentScore.getSoftScore() >= 0))
.reduce(Score::add).orElse(HardSoftScore.ZERO); .reduce(Score::add).orElse(HardSoftScore.ZERO);
Expand All @@ -1448,27 +1498,42 @@ protected void nextTalkListCell(boolean unavailable, List<Talk> talkList, Functi
if (!talkList.isEmpty()) { if (!talkList.isEmpty()) {
ClientAnchor anchor = creationHelper.createClientAnchor(); ClientAnchor anchor = creationHelper.createClientAnchor();
anchor.setCol1(cell.getColumnIndex()); anchor.setCol1(cell.getColumnIndex());
anchor.setCol2(cell.getColumnIndex() + 5); anchor.setCol2(cell.getColumnIndex() + 4);
anchor.setRow1(currentRow.getRowNum()); anchor.setRow1(currentRow.getRowNum());
anchor.setRow2(currentRow.getRowNum() + 5); anchor.setRow2(currentRow.getRowNum() + 4);
Comment comment = currentDrawing.createCellComment(anchor); Comment comment = currentDrawing.createCellComment(anchor);
String commentString = talkList.stream() StringBuilder commentString = new StringBuilder(talkList.size() * 200);
.map(talk -> talk.getCode() + ": " for (Talk talk : talkList) {
+ talk.getTitle() + "\n " commentString.append(talk.getCode()).append(": ").append(talk.getTitle()).append("\n ")
+ talk.getSpeakerList().stream().map(Speaker::getName).collect(joining(", ")) .append(talk.getSpeakerList().stream().map(Speaker::getName).collect(joining(", ")))
+ (talk.isPinnedByUser() ? "\n PINNED BY USER" : "") .append(talk.isPinnedByUser() ? "\nPINNED BY USER" : "");
).collect(joining("\n\n")); Indictment indictment = indictmentMap.get(talk);
if (!indictmentList.isEmpty()) { if (indictment != null) {
commentString += "\n\nConstraint matches:\n " commentString.append("\n").append(indictment.getScoreTotal().toShortString())
+ indictmentList.stream().flatMap(indictment -> indictment.getConstraintMatchSet().stream()) .append(" total");
.map(constraintMatch -> constraintMatch.getConstraintName() + " (" Set<ConstraintMatch> constraintMatchSet = indictment.getConstraintMatchSet();
+ constraintMatch.getJustificationList().stream() List<String> constraintNameList = constraintMatchSet.stream()
.filter(o -> o instanceof Talk).map(o -> ((Talk) o).getCode()) .map(ConstraintMatch::getConstraintName).distinct().collect(toList());
.collect(joining(", ")) for (String constraintName : constraintNameList) {
+ "): " + constraintMatch.getScore().toShortString()) List<ConstraintMatch> filteredConstraintMatchList = constraintMatchSet.stream()
.collect(joining("\n ")); .filter(constraintMatch -> constraintMatch.getConstraintName().equals(constraintName))
.collect(toList());
Score sum = filteredConstraintMatchList.stream()
.map(ConstraintMatch::getScore)
.reduce(Score::add).orElse(HardSoftScore.ZERO);
String justificationTalkCodes = filteredConstraintMatchList.stream()
.flatMap(constraintMatch -> constraintMatch.getJustificationList().stream())
.filter(justification -> justification instanceof Talk && justification != talk)
.distinct().map(o -> ((Talk) o).getCode()).collect(joining(", "));
commentString.append("\n ").append(sum.toShortString())
.append(" for ").append(filteredConstraintMatchList.size())
.append(" ").append(constraintName).append("s")
.append("\n ").append(justificationTalkCodes);
}
}
commentString.append("\n\n");
} }
comment.setString(creationHelper.createRichTextString(commentString)); comment.setString(creationHelper.createRichTextString(commentString.toString()));
cell.setCellComment(comment); cell.setCellComment(comment);
} }
cell.setCellValue(talkList.stream().map(stringFunction).collect(joining("\n"))); cell.setCellValue(talkList.stream().map(stringFunction).collect(joining("\n")));
Expand Down

0 comments on commit ab54c0f

Please sign in to comment.