Rewrote the matching algorithm which didnt work.
This commit is contained in:
parent
b7816cb7da
commit
3661061ed0
src
main/java/se/su/dsv/scipro/match
test/java/se/su/dsv/scipro/match
@ -22,143 +22,83 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
|
||||
private Weights weights;
|
||||
|
||||
@Override
|
||||
public Result match(List<Availability> supervisorAvailability,
|
||||
List<ProjectIdea> unmatchedProjectIdeas, Weights weights) {
|
||||
List<Match> matchList = new ArrayList<Match>();
|
||||
|
||||
this.weights = weights;
|
||||
public Result match(List<Availability> supervisorAvailability, List<ProjectIdea> unmatchedProjectIdeas, Weights weights) {
|
||||
this.weights = weights;
|
||||
List<Pair> pairList = new ArrayList<Pair>();
|
||||
List<Match> matchList = new ArrayList<Match>();
|
||||
|
||||
List<String> availableProjectClasses = getAvailableProjectClass(unmatchedProjectIdeas, supervisorAvailability);
|
||||
|
||||
HashMap<String, List<ProjectIdea>> sortedProjectIdeas = getSortedProjectIdeas(availableProjectClasses, unmatchedProjectIdeas);
|
||||
HashMap<String, List<Availability>> sortedAvailability = getSortedAvailability(availableProjectClasses, supervisorAvailability);
|
||||
logger.info("SortedAvail.size: " + sortedAvailability.size());
|
||||
logger.info("sortedProjIdeas.size: " + sortedProjectIdeas.size());
|
||||
for (String projectClassCode : availableProjectClasses) {
|
||||
logger.info("Checking class:" + projectClassCode);
|
||||
matchList.addAll(matchProjectIdeas(sortedProjectIdeas.get(projectClassCode), sortedAvailability.get(projectClassCode)));
|
||||
}
|
||||
logger.info("Matchlist.size: " + matchList.size());
|
||||
while(!unmatchedProjectIdeas.isEmpty()) {
|
||||
pairList.clear();
|
||||
matchProjectIdeas(unmatchedProjectIdeas, supervisorAvailability, pairList);
|
||||
Collections.sort(pairList);
|
||||
if(!pairList.isEmpty()) {
|
||||
Pair foundPair = pairList.get(0);
|
||||
for(Availability availability : supervisorAvailability) {
|
||||
if(availability.getSupervisor().equals(foundPair.getMatch().getSupervisor())) {
|
||||
if(availability.getNumCapable() > availability.getNumMatched()) {
|
||||
availability.setNumMatched(availability.getNumMatched() + 1);
|
||||
matchList.add(foundPair.getMatch());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there are unmatched bachelor theses and unmatched master supervisors match them
|
||||
List<ProjectIdea> projectIdeaList = sortedProjectIdeas.get(ProjectClass.BACHELOR);
|
||||
List<Availability> availabilityList = sortedAvailability.get(ProjectClass.MASTER);
|
||||
|
||||
if (projectIdeaList != null && availabilityList != null) {
|
||||
if (!projectIdeaList.isEmpty()
|
||||
&& !availabilityList.isEmpty()) {
|
||||
matchList.addAll(matchProjectIdeas(projectIdeaList, availabilityList));
|
||||
}
|
||||
}
|
||||
unmatchedProjectIdeas = getUnmatchedProjectIdeas(matchList, unmatchedProjectIdeas);
|
||||
return new Result(matchList, unmatchedProjectIdeas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take all ProjectIdeas and remove those who have been matched
|
||||
* @param matchList the list
|
||||
* @param unmatchedProjectIdeas unmatched ideas
|
||||
* @return List<ProjectIdea>
|
||||
*/
|
||||
private List<ProjectIdea> getUnmatchedProjectIdeas(List<Match> matchList,
|
||||
List<ProjectIdea> unmatchedProjectIdeas) {
|
||||
for (Match match : matchList) {
|
||||
ProjectIdea matchedProjectIdea = match.getProjectIdea();
|
||||
Iterator<ProjectIdea> projectIdeaIterator = unmatchedProjectIdeas.iterator();
|
||||
while (projectIdeaIterator.hasNext()) {
|
||||
ProjectIdea unmatchedProjectIdea = projectIdeaIterator.next();
|
||||
if (matchedProjectIdea.equals(unmatchedProjectIdea)) {
|
||||
projectIdeaIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return unmatchedProjectIdeas;
|
||||
Iterator<ProjectIdea> projectIdeaIterator = unmatchedProjectIdeas.iterator();
|
||||
while(projectIdeaIterator.hasNext()) {
|
||||
ProjectIdea projectIdea = projectIdeaIterator.next();
|
||||
if(projectIdea.equals(foundPair.getMatch().getProjectIdea())) {
|
||||
projectIdeaIterator.remove();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new Result(matchList, unmatchedProjectIdeas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match project ideas with supervisors (based on availability) and return the best match.
|
||||
* @param projectIdeaList project ideas that should be matched
|
||||
* @param availabilityList supervisors that should be matched
|
||||
* @return List<Match> the best matches are returned
|
||||
*/
|
||||
private List<Match> matchProjectIdeas(List<ProjectIdea> projectIdeaList, List<Availability> availabilityList) {
|
||||
List<Match> matchList = new ArrayList<Match>();
|
||||
|
||||
Iterator<ProjectIdea> projectIdeaIterator = projectIdeaList.iterator();
|
||||
while (projectIdeaIterator.hasNext()) {
|
||||
ProjectIdea projectIdea = projectIdeaIterator.next();
|
||||
logger.info("Matching project idea:" + projectIdea);
|
||||
Pair matchPair = null;
|
||||
Iterator<Availability> availabilityIterator = availabilityList.iterator();
|
||||
while (availabilityIterator.hasNext()) {
|
||||
Availability availability = availabilityIterator.next();
|
||||
* @param pairList the set
|
||||
*/
|
||||
private void matchProjectIdeas(List<ProjectIdea> projectIdeaList, List<Availability> availabilityList, List<Pair> pairList) {
|
||||
for (ProjectIdea projectIdea : projectIdeaList) {
|
||||
logger.info("Matching project idea:" + projectIdea);
|
||||
for(Availability availability : availabilityList) {
|
||||
logger.info("Matching project idea with supervisor:" + availability.getSupervisor());
|
||||
|
||||
if (!availability.isAvailable()) {
|
||||
availabilityIterator.remove();
|
||||
logger.info("Not an available supervisor");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(availability.getProjectClass().toString().equalsIgnoreCase(ProjectClass.BACHELOR) &&
|
||||
projectIdea.getProjectClass().toString().equalsIgnoreCase(ProjectClass.MASTER)) {
|
||||
logger.info("A bachelor supervisor cannot handle master ideas.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isPossibleSupervisor(projectIdea, availability.getSupervisor())) {
|
||||
logger.info("Not possible supervisor");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(matchPair == null){
|
||||
Match match = new Match(); // create a new match
|
||||
match.setSupervisor(availability.getSupervisor());
|
||||
match.setProjectIdea(projectIdea);
|
||||
matchPair = new Pair(match, new Availability(null, 1L, 1, new ProjectClass()));
|
||||
}
|
||||
|
||||
matchPair = getBestMatch(matchPair, availability);
|
||||
pairList.add(getPair(projectIdea, availability));
|
||||
}
|
||||
if (matchPair != null && matchPair.getMatch().getPoints() != -1) {
|
||||
matchList.add(matchPair.getMatch());
|
||||
projectIdeaIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return matchList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the best match, the old one or the new one with supervisor
|
||||
* @param oldMatchPair the match pair
|
||||
* @param projectIdea projectIdea
|
||||
* @param availability the availability
|
||||
* @return Pair
|
||||
*/
|
||||
private Pair getBestMatch(final Pair oldMatchPair, Availability availability) {
|
||||
Match oldMatch = oldMatchPair.getMatch();
|
||||
Availability oldAvailability = oldMatchPair.getAvailability();
|
||||
|
||||
private Pair getPair(ProjectIdea projectIdea, Availability availability) {
|
||||
Match match = new Match();
|
||||
match.setProjectIdea(oldMatch.getProjectIdea());
|
||||
match.setProjectIdea(projectIdea);
|
||||
match.setSupervisor(availability.getSupervisor());
|
||||
|
||||
match = calculateScore(match);
|
||||
|
||||
if (match.getPoints() > oldMatch.getPoints()) {
|
||||
|
||||
availability.setNumMatched(availability.getNumMatched() + 1);
|
||||
oldAvailability.setNumMatched(oldAvailability.getNumMatched() - 1);
|
||||
return new Pair(match, availability);
|
||||
|
||||
} else if (match.getPoints() == oldMatch.getPoints()) {
|
||||
|
||||
if (availability.getAvailability() > oldAvailability.getAvailability()) {
|
||||
|
||||
availability.setNumMatched(availability.getNumMatched() + 1);
|
||||
oldAvailability.setNumMatched(oldAvailability.getNumMatched() - 1);
|
||||
return new Pair(match, availability);
|
||||
|
||||
} else {
|
||||
return oldMatchPair;
|
||||
}
|
||||
} else {
|
||||
return oldMatchPair;
|
||||
}
|
||||
return new Pair(match, availability);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -192,9 +132,7 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
|
||||
*/
|
||||
private boolean isNotRejectedBySupervisor(ProjectIdea projectIdea, Employee supervisor) {
|
||||
for (Match oldMatch : projectIdea.getMatchHistory()) {
|
||||
if (
|
||||
//oldMatch.getSupervisor() != null && oldMatch.getSupervisor().equals(supervisor) && we are not interested in who is the supervisor, we are interested in who is rejectedBy
|
||||
oldMatch.getRejectedBy() != null && oldMatch.getRejectedBy().equals(supervisor.getUser()) &&
|
||||
if (oldMatch.getRejectedBy() != null && oldMatch.getRejectedBy().equals(supervisor.getUser()) &&
|
||||
oldMatch.getStatus() != null && oldMatch.getStatus().equals(Match.Status.REJECTED)) {
|
||||
return false;
|
||||
}
|
||||
@ -252,91 +190,13 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
|
||||
match.setPoints(points);
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param availableProjectClasses the list with available project classes
|
||||
* @param supervisorAvailability the list with available supervisors
|
||||
* @return Supervisors availability sorted on ProjectClasses.code
|
||||
*/
|
||||
private HashMap<String, List<Availability>> getSortedAvailability(
|
||||
List<String> availableProjectClasses,
|
||||
List<Availability> supervisorAvailability) {
|
||||
HashMap<String, List<Availability>> sortedAvailability = new HashMap<String, List<Availability>>();
|
||||
|
||||
for (String projectClassCode : availableProjectClasses) {
|
||||
sortedAvailability.put(projectClassCode, new ArrayList<Availability>());
|
||||
}
|
||||
|
||||
for (Availability availability : supervisorAvailability) {
|
||||
sortedAvailability.get(availability.getProjectClass().getCode()).add(availability);
|
||||
}
|
||||
|
||||
//start Tom+Anton test
|
||||
//List<Availability> bachelorAvailabilities = sortedAvailability.get(ProjectClass.BACHELOR) != null ?
|
||||
// sortedAvailability.get(ProjectClass.BACHELOR) : new ArrayList<Availability>();
|
||||
List<Availability> bachelorAvailabilities = sortedAvailability.get(ProjectClass.BACHELOR);
|
||||
if (bachelorAvailabilities != null)
|
||||
for (Availability av : supervisorAvailability) {
|
||||
if(!bachelorAvailabilities.contains(av))
|
||||
bachelorAvailabilities.add(av);
|
||||
}
|
||||
//sortedAvailability.put(ProjectClass.BACHELOR, bachelorAvailabilities);
|
||||
//end T+A
|
||||
|
||||
return sortedAvailability;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param availableProjectClasses the project classes that exists, regardless of there is a match or not,
|
||||
* that is ok because the List with project ideas will be empty in case no project class match
|
||||
* @param unmatchedProjectIdeaList the unmatched project ideas
|
||||
* @return unmatched ProjectIdeas sorted on ProjectClasses.code
|
||||
*/
|
||||
private HashMap<String, List<ProjectIdea>> getSortedProjectIdeas(
|
||||
List<String> availableProjectClasses,
|
||||
List<ProjectIdea> unmatchedProjectIdeaList) {
|
||||
HashMap<String, List<ProjectIdea>> sortedProjectIdeas = new HashMap<String, List<ProjectIdea>>();
|
||||
|
||||
for (String projectClassCode : availableProjectClasses) {
|
||||
sortedProjectIdeas.put(projectClassCode, new ArrayList<ProjectIdea>());
|
||||
}
|
||||
|
||||
for (ProjectIdea projectIdea : unmatchedProjectIdeaList) {
|
||||
sortedProjectIdeas.get(projectIdea.getProjectClass().getCode()).add(projectIdea);
|
||||
}
|
||||
|
||||
return sortedProjectIdeas;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param unmatchedProjectIdeas a list of unmatched project ideas
|
||||
* @param supervisorAvailability list of available supervisors
|
||||
* @return all available ProjectClass codes
|
||||
*/
|
||||
private List<String> getAvailableProjectClass(
|
||||
List<ProjectIdea> unmatchedProjectIdeas, List<Availability> supervisorAvailability) {
|
||||
List<String> availableProjectClasses = new ArrayList<String>();
|
||||
for (ProjectIdea projectIdea : unmatchedProjectIdeas) {
|
||||
if (!availableProjectClasses.contains(projectIdea.getProjectClass().getCode())) {
|
||||
availableProjectClasses.add(projectIdea.getProjectClass().getCode());
|
||||
}
|
||||
}
|
||||
|
||||
for (Availability availability : supervisorAvailability) {
|
||||
if (!availableProjectClasses.contains(availability.getProjectClass().getCode())) {
|
||||
availableProjectClasses.add(availability.getProjectClass().getCode());
|
||||
}
|
||||
}
|
||||
return availableProjectClasses;
|
||||
}
|
||||
|
||||
private class Pair {
|
||||
private class Pair implements Comparable<Pair> {
|
||||
private Match match;
|
||||
private Availability availability;
|
||||
|
||||
public Pair(Match match, Availability availability) {
|
||||
public Pair(Match match, Availability availability
|
||||
) {
|
||||
this.match = match;
|
||||
this.availability = availability;
|
||||
}
|
||||
@ -348,5 +208,17 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
|
||||
public Availability getAvailability() {
|
||||
return availability;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Pair otherPair) {
|
||||
if(match.getPoints() > otherPair.getMatch().getPoints()) {
|
||||
return -1;
|
||||
} else if(otherPair.getMatch().getPoints() > match.getPoints()) {
|
||||
return 1;
|
||||
} else {
|
||||
return availability.compareTo(otherPair.getAvailability());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import se.su.dsv.scipro.data.dataobjects.ProjectClass;
|
||||
/**
|
||||
* A class that specifies how available a supervisor is(in terms of thesis supervision)
|
||||
*/
|
||||
public class Availability implements Serializable{
|
||||
public class Availability implements Serializable, Comparable<Availability> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -53,6 +53,17 @@ public class Availability implements Serializable{
|
||||
public void setNumMatched(Long num) {
|
||||
numMatched = num;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Availability availability) {
|
||||
if(getAvailability() > availability.getAvailability()) {
|
||||
return -1;
|
||||
} else if(availability.getAvailability() > getAvailability()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -21,7 +21,7 @@ import se.su.dsv.scipro.data.dataobjects.User;
|
||||
@Cacheable(true)
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
@Table(name="matchings")
|
||||
public class Match extends DomainObject {
|
||||
public class Match extends DomainObject implements Comparable<Match> {
|
||||
|
||||
public static enum Type {
|
||||
PRE_APPROVED,
|
||||
@ -169,6 +169,18 @@ public class Match extends DomainObject {
|
||||
", dateCreated=" + (getDateCreated() != null ? getDateCreated() :"") + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Match otherMatch) {
|
||||
if(points > otherMatch.getPoints()) {
|
||||
return -1;
|
||||
} else if(otherMatch.getPoints() > points) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
@ -500,6 +500,7 @@ public class TestGreedyMatchingAlgorithm {
|
||||
Employee bachelorSupervisor2 = createSupervisor("David", "Hallberg", languages);
|
||||
supervisorAvailability.add(new Availability(masterSupervisor, 0L, 1, bachelorProjectClass));
|
||||
supervisorAvailability.add(new Availability(bachelorSupervisor2, 0L, 1, bachelorProjectClass));
|
||||
addKeyWords(bachelorSupervisor2, bachelorProjectIdea, createKeyword(keywordTypeWord, "Design", false));
|
||||
unmatchedProjectIdeas.add(bachelorProjectIdea);
|
||||
Result result = new GreedyMatchingAlgorithm().match(supervisorAvailability, unmatchedProjectIdeas, weights);
|
||||
assertTrue(result.matches.size() > 0);
|
||||
@ -560,7 +561,6 @@ public class TestGreedyMatchingAlgorithm {
|
||||
@Rollback
|
||||
/* test that a master which has filled up his slot for bachelor but has slots left for master can supervise a bachelor idea */
|
||||
public void testIncreaseSlotForMasterSupervisor_v2() {
|
||||
/*
|
||||
Employee bachelorSupervisor2 = createSupervisor("David", "Hallberg", languages);
|
||||
supervisorAvailability.add(new Availability(masterSupervisor, 3L, 3, bachelorProjectClass));
|
||||
supervisorAvailability.add(new Availability(masterSupervisor, 3L, 4, masterProjectClass));
|
||||
@ -571,11 +571,29 @@ public class TestGreedyMatchingAlgorithm {
|
||||
masterProjectIdea.setPreferredSupervisor(masterSupervisor);
|
||||
addKeyWords(masterSupervisor, masterProjectIdea, createKeyword(keywordTypeWord, "UML", false));
|
||||
Result result = new GreedyMatchingAlgorithm().match(supervisorAvailability, unmatchedProjectIdeas, weights);
|
||||
assertTrue(result.matches.size() > 0);
|
||||
assertTrue(result.matches.get(0).getProjectIdea().equals(masterProjectIdea));
|
||||
assertTrue(result.matches.get(0).getSupervisor().equals(masterSupervisor));
|
||||
assertTrue(result.matches.size() > 0);
|
||||
boolean foundMasterProjIdea = false;
|
||||
boolean foundMasterSuperVisor= false;
|
||||
|
||||
boolean foundBachelorProjIdea = false;
|
||||
boolean foundBachelorSuperVisor= false;
|
||||
|
||||
for(Match match : result.matches) {
|
||||
if(match.getProjectIdea().equals(masterProjectIdea) && match.getSupervisor().equals(masterSupervisor)) {
|
||||
foundMasterProjIdea = true;
|
||||
foundMasterSuperVisor = true;
|
||||
}
|
||||
|
||||
if(match.getProjectIdea().equals(bachelorProjectIdea) && match.getSupervisor().equals(bachelorSupervisor2)) {
|
||||
foundBachelorProjIdea = true;
|
||||
foundBachelorSuperVisor = true;
|
||||
}
|
||||
}
|
||||
assertTrue(foundMasterProjIdea);
|
||||
assertTrue(foundBachelorProjIdea);
|
||||
assertTrue(foundBachelorSuperVisor);
|
||||
assertTrue(foundMasterSuperVisor);
|
||||
assertTrue(result.unmatched.size() == 0);
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user