Bael 801 (#5150)
* BAEL-801 A Guide to OptaPlanner * BAEL-801 Optaplanner per Editor Review * BAEL-801 Fixed parent pom merge issue * BAEL-801 Fixed parent pom merge issue * BAEL-801 Added logback to suppress debug logging causing build failures * BAEL-801 Updated per editor review * BAEL-801 Removed static variables * BAEL-801 - Updated per Senior Editor review. Moved classes to Drools module. * BAEL-801 - Updated per Senior Editor review. Moved classes to Drools module. * BAEL-801 - Deleted duplicate class.
This commit is contained in:
parent
3dcdc30c94
commit
b48458d3fd
@ -48,12 +48,18 @@
|
|||||||
<artifactId>poi-ooxml</artifactId>
|
<artifactId>poi-ooxml</artifactId>
|
||||||
<version>${apache-poi-version}</version>
|
<version>${apache-poi-version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.optaplanner</groupId>
|
||||||
|
<artifactId>optaplanner-core</artifactId>
|
||||||
|
<version>${opta-planner-version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<http-component-version>4.4.6</http-component-version>
|
<http-component-version>4.4.6</http-component-version>
|
||||||
<drools-version>7.4.1.Final</drools-version>
|
<drools-version>7.4.1.Final</drools-version>
|
||||||
<apache-poi-version>3.13</apache-poi-version>
|
<apache-poi-version>3.13</apache-poi-version>
|
||||||
|
<opta-planner-version>7.10.0.Final</opta-planner-version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.baeldung.drools.optaplanner;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
|
||||||
|
import org.optaplanner.core.api.domain.solution.PlanningScore;
|
||||||
|
import org.optaplanner.core.api.domain.solution.PlanningSolution;
|
||||||
|
import org.optaplanner.core.api.domain.solution.drools.ProblemFactCollectionProperty;
|
||||||
|
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
|
||||||
|
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@PlanningSolution
|
||||||
|
public class CourseSchedule {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger("CourseSchedule");
|
||||||
|
|
||||||
|
private List<Integer> roomList;
|
||||||
|
private List<Integer> periodList;
|
||||||
|
private List<Lecture> lectureList;
|
||||||
|
private HardSoftScore score;
|
||||||
|
|
||||||
|
public CourseSchedule(){
|
||||||
|
roomList = new ArrayList<>();
|
||||||
|
periodList = new ArrayList<>();
|
||||||
|
lectureList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ValueRangeProvider(id = "availableRooms")
|
||||||
|
@ProblemFactCollectionProperty
|
||||||
|
public List<Integer> getRoomList() {
|
||||||
|
return roomList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ValueRangeProvider(id = "availablePeriods")
|
||||||
|
@ProblemFactCollectionProperty
|
||||||
|
public List<Integer> getPeriodList() {
|
||||||
|
return periodList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PlanningEntityCollectionProperty
|
||||||
|
public List<Lecture> getLectureList() {
|
||||||
|
return lectureList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PlanningScore
|
||||||
|
public HardSoftScore getScore() {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScore(HardSoftScore score) {
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printCourseSchedule() {
|
||||||
|
lectureList.stream()
|
||||||
|
.map(c -> "Lecture in Room " + c.getRoomNumber().toString() + " during Period " + c.getPeriod().toString())
|
||||||
|
.forEach(k -> logger.info(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.baeldung.drools.optaplanner;
|
||||||
|
|
||||||
|
import org.optaplanner.core.api.domain.entity.PlanningEntity;
|
||||||
|
import org.optaplanner.core.api.domain.variable.PlanningVariable;
|
||||||
|
|
||||||
|
@PlanningEntity
|
||||||
|
public class Lecture {
|
||||||
|
|
||||||
|
private Integer roomNumber;
|
||||||
|
private Integer period;
|
||||||
|
|
||||||
|
@PlanningVariable(valueRangeProviderRefs = {"availablePeriods"})
|
||||||
|
public Integer getPeriod() {
|
||||||
|
return period;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PlanningVariable(valueRangeProviderRefs = {"availableRooms"})
|
||||||
|
public Integer getRoomNumber() {
|
||||||
|
return roomNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPeriod(Integer period) {
|
||||||
|
this.period = period;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomNumber(Integer roomNumber) {
|
||||||
|
this.roomNumber = roomNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.baeldung.drools.optaplanner;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import org.optaplanner.core.api.score.Score;
|
||||||
|
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
|
||||||
|
import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator;
|
||||||
|
|
||||||
|
public class ScoreCalculator implements EasyScoreCalculator<CourseSchedule> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Score calculateScore(CourseSchedule courseSchedule) {
|
||||||
|
int hardScore = 0;
|
||||||
|
int softScore = 0;
|
||||||
|
|
||||||
|
HashSet<String> occupiedRooms = new HashSet<>();
|
||||||
|
for (Lecture lecture : courseSchedule.getLectureList()) {
|
||||||
|
if(lecture.getPeriod() != null && lecture.getRoomNumber() != null) {
|
||||||
|
String roomInUse = lecture.getPeriod().toString() + ":" + lecture.getRoomNumber().toString();
|
||||||
|
if (occupiedRooms.contains(roomInUse)) {
|
||||||
|
hardScore += -1;
|
||||||
|
} else {
|
||||||
|
occupiedRooms.add(roomInUse);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hardScore += -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return HardSoftScore.valueOf(hardScore, softScore);
|
||||||
|
}
|
||||||
|
}
|
14
drools/src/main/resources/courseSchedule.drl
Normal file
14
drools/src/main/resources/courseSchedule.drl
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package com.baeldung.drools.optaplanner
|
||||||
|
|
||||||
|
import com.baeldung.drools.optaplanner.Lecture;
|
||||||
|
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder;
|
||||||
|
|
||||||
|
global HardSoftScoreHolder scoreHolder;
|
||||||
|
|
||||||
|
rule "noNullRoomPeriod"
|
||||||
|
when
|
||||||
|
Lecture( roomNumber == null );
|
||||||
|
Lecture( period == null );
|
||||||
|
then
|
||||||
|
scoreHolder.addHardConstraintMatch(kcontext, -1);
|
||||||
|
end
|
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<solver>
|
||||||
|
<scanAnnotatedClasses/>
|
||||||
|
|
||||||
|
<scoreDirectorFactory>
|
||||||
|
<scoreDrl>courseSchedule.drl</scoreDrl>
|
||||||
|
</scoreDirectorFactory>
|
||||||
|
|
||||||
|
<termination>
|
||||||
|
<secondsSpentLimit>10</secondsSpentLimit>
|
||||||
|
</termination>
|
||||||
|
</solver>
|
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<solver>
|
||||||
|
<scanAnnotatedClasses/>
|
||||||
|
|
||||||
|
<scoreDirectorFactory>
|
||||||
|
<easyScoreCalculatorClass>com.baeldung.drools.optaplanner.ScoreCalculator</easyScoreCalculatorClass>
|
||||||
|
</scoreDirectorFactory>
|
||||||
|
|
||||||
|
<termination>
|
||||||
|
<secondsSpentLimit>10</secondsSpentLimit>
|
||||||
|
</termination>
|
||||||
|
</solver>
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.baeldung.drools.optaplanner;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.optaplanner.core.api.solver.Solver;
|
||||||
|
import org.optaplanner.core.api.solver.SolverFactory;
|
||||||
|
|
||||||
|
public class OptaPlannerUnitTest {
|
||||||
|
|
||||||
|
static CourseSchedule unsolvedCourseSchedule;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void setUp() {
|
||||||
|
|
||||||
|
unsolvedCourseSchedule = new CourseSchedule();
|
||||||
|
|
||||||
|
for(int i = 0; i < 10; i++){
|
||||||
|
unsolvedCourseSchedule.getLectureList().add(new Lecture());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsolvedCourseSchedule.getPeriodList().addAll(Arrays.asList(new Integer[] { 1, 2, 3 }));
|
||||||
|
unsolvedCourseSchedule.getRoomList().addAll(Arrays.asList(new Integer[] { 1, 2 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenCustomJavaSolver() {
|
||||||
|
|
||||||
|
SolverFactory<CourseSchedule> solverFactory = SolverFactory.createFromXmlResource("courseScheduleSolverConfiguration.xml");
|
||||||
|
Solver<CourseSchedule> solver = solverFactory.buildSolver();
|
||||||
|
CourseSchedule solvedCourseSchedule = solver.solve(unsolvedCourseSchedule);
|
||||||
|
|
||||||
|
Assert.assertNotNull(solvedCourseSchedule.getScore());
|
||||||
|
Assert.assertEquals(-4, solvedCourseSchedule.getScore().getHardScore());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenDroolsSolver() {
|
||||||
|
|
||||||
|
SolverFactory<CourseSchedule> solverFactory = SolverFactory.createFromXmlResource("courseScheduleSolverConfigDrools.xml");
|
||||||
|
Solver<CourseSchedule> solver = solverFactory.buildSolver();
|
||||||
|
CourseSchedule solvedCourseSchedule = solver.solve(unsolvedCourseSchedule);
|
||||||
|
|
||||||
|
Assert.assertNotNull(solvedCourseSchedule.getScore());
|
||||||
|
Assert.assertEquals(0, solvedCourseSchedule.getScore().getHardScore());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user