[rules-dev] Planner big user impacting changes: declarative metamodel
Michael Anstis
michael.anstis at gmail.com
Fri May 27 16:39:25 EDT 2011
Phew! I made it to the end of the email ;)
All very interest Geoffrey, but have you explained the purpose of the
annotations? Why must I now annotate things, what value is it bringing?
I don't, personally, have any problem with them - there are many libraries
that use them - but their purpose is well understood: e.g. @Entity,
@Resource etc
Perhaps I missed something?
With kind regards
Mike
On 27 May 2011 11:13, Geoffrey De Smet <ge0ffrey.spam at gmail.com> wrote:
> Hi guys
>
> For Drools Planner 5.3.0 (not the upcoming release)
> I am working on a separate branch [1] to allow Planner to understand your
> domain model better.
> *This will force some big changes upon you as a user*, but it will also
> allow many new features.
> Reading and replying to this mail is your chance to steer those changes,
> and verify that they are a good thing for your implementation too.
> I'll push those changes to master in a day or 2 ... unless someone finds a
> good reason not too.
>
> Any feed-back, especially on concept names, is welcome.
>
> *The Bad News*
>
> You'd have to do some serious upgrading changes. Although I am confident
> this can be done in an hour or 2.
> Here is the upgrading recipe as in github. Please go through to this list
> to understand the impact of these changes.
> Once the changes are on master, I 'll update the reference manual.
>
>
> [MAJOR] You need to define your solution class in the configuration now:
> Before in *SolverConfig.xml and *BenchmarkConfig.xml:
> <localSearchSolver>
> <scoreDrl>...</scoreDrl>
> After in *SolverConfig.xml and *BenchmarkConfig.xml:
> <localSearchSolver>
>
> <solutionClass>org.drools.planner.examples.curriculumcourse.domain.CurriculumCourseSchedule</solutionClass>
> <scoreDrl>...</scoreDrl>
>
> [RECOMMENDED] Understand the concept of a "planning entity" class.
> The class (or classes) that change during planning (and do not implement
> Solution) are a planning entity.
> For example: ShiftAssignment, BedDesignation, Queen, CloudAssignment, ...
> The other domain classes are considered normal planning facts,
> for example Shift, Employee, Bed, Room, Department, ...
> They do not change during planning (at least not without pausing the
> solver).
> Read the manual to understand the "planning entity" concept better.
>
> [MAJOR] You need to define your planning entity class(es) in the
> configuration now:
> Before in *SolverConfig.xml and *BenchmarkConfig.xml:
> <localSearchSolver>
> <solutionClass>....</solutionClass>
> <scoreDrl>...</scoreDrl>
> After in *SolverConfig.xml and *BenchmarkConfig.xml:
> <localSearchSolver>
> <solutionClass>....</solutionClass>
>
> <planningEntityClass>org.drools.planner.examples.curriculumcourse.domain.Lecture</planningEntityClass>
> <scoreDrl>...</scoreDrl>
>
> [MAJOR] You need to annotate your planning entity class(es) with the
> @PlanningEntity annotation
> Before in *.java:
> public class Lecture ... {
> ...
> }
> After in *.java:
> @PlanningEntity
> public class Lecture ... {
> ...
> }
>
> [RECOMMENDED] Understand the concept of a "planning variable" property.
> The property (or properties) on a planning entity class that are changed
> (through their setter) during planning
> are planning variables.
> For example: ShiftAssignment.getEmployee(), BedDesignation.getBed(),
> Queen.getY(), ...
> Note that most planning entities have 1 property which defines the planning
> entity
> and that property is NOT a planning variable.
> For example: ShiftAssignment.getShift(), BedDesignation.getAdmissionPart(),
> Queen.getX(), ...
> Read the manual to understand the "planning variable" concept better.
>
> [MAJOR] You need to annotate your planning variable property(ies) with the
> @PlanningVariable annotation.
> Furthermore, you need to annotate a @ValueRange* annotation on to define
> the allowed values.
> Commonly, you 'll use @ValueRangeFromSolutionProperty which specifies a
> property name on the solution
> which returns a collection of the allowed values for that variable.
> Before in *.java:
> @PlanningEntity
> public class Lecture ... {
>
> private Course course;
> private int lectureIndexInCourse;
>
> // Changed by moves, between score calculations.
> private Period period;
> private Room room;
>
> public Course getCourse() {...}
> public void setCourse(Course course) {...}
>
> public int getLectureIndexInCourse() {...}
> public void setLectureIndexInCourse(int lectureIndexInCourse) {...}
>
> public Period getPeriod() {...}
> public void setPeriod(Period period) {...}
>
> public Room getRoom() {...}
> public void setRoom(Room room) {...}
>
> ...
>
> public int getStudentSize() {
> return course.getStudentSize();
> }
>
> public Day getDay() {
> return period.getDay();
> }
>
> }
> After in *.java:
> @PlanningEntity
> public class Lecture ... {
>
> private Course course;
> private int lectureIndexInCourse;
>
> // Changed by moves, between score calculations.
> private Period period;
> private Room room;
>
> // This is not a PlanningVariable: it defines the planning entity
> public Course getCourse() {...}
> public void setCourse(Course course) {...}
>
> // This is not a PlanningVariable: it defines the planning entity
> public int getLectureIndexInCourse() {...}
> public void setLectureIndexInCourse(int lectureIndexInCourse) {...}
>
> @PlanningVariable
> @ValueRangeFromSolutionProperty(propertyName = "periodList")
> public Period getPeriod() {...}
> public void setPeriod(Period period) {...}
>
> @PlanningVariable
> @ValueRangeFromSolutionProperty(propertyName = "roomList")
> public Room getRoom() {...}
> public void setRoom(Room room) {...}
>
> ...
>
> // This is not a PlanningVariable: no setter
> public int getStudentSize() {
> return course.getStudentSize();
> }
>
> // This is not a PlanningVariable: no setter
> public Day getDay() {
> return period.getDay();
> }
>
> }
>
> [MAJOR] Annotate every property on your Solution that returns a collection
> of planning entities
> with @PlanningEntityCollectionProperty.
> Before in *.java:
> public class CurriculumCourseSchedule ... implements Solution<...> {
>
> private List<Lecture> lectureList;
>
> ...
>
> public List<Lecture> getLectureList() {...}
> public void setLectureList(List<Lecture> lectureList) {...}
>
> }
> After in *.java:
> public class CurriculumCourseSchedule ... implements Solution<...> {
>
> private List<Lecture> lectureList;
>
> ...
>
> @PlanningEntityCollectionProperty
> public List<Lecture> getLectureList() {...}
> public void setLectureList(List<Lecture> lectureList) {...}
>
> }
>
> [MAJOR] The method getFacts() has been removed from the Solution interface.
> Annotate every property that returns a fact or fact collection with the
> @PlanningFactProperty
> or @PlanningFactCollectionProperty annotation respectively,
> except those already annotated with @PlanningEntityCollectionProperty.
> Properties annotated with these annotations are inserted into the working
> memory as facts:
> - @PlanningFactProperty
> - @PlanningFactCollectionProperty: each element in the collection
> - @PlanningEntityCollectionProperty: each planning entity in the collection
> that is initialized
> Remove the getFacts() method.
> Before in *.java:
> public class ... implements Solution<...> {
>
> private InstitutionalWeighting institutionalWeighting;
>
> private List<Teacher> teacherList;
> private List<Curriculum> curriculumList;
> ...
> private List<UnavailablePeriodConstraint>
> unavailablePeriodConstraintList;
>
> private List<Lecture> lectureList;
>
> private HardAndSoftScore score;
>
> ...
>
> public String getName() {...}
>
> public InstitutionalWeighting getInstitutionalWeighting() {...}
>
> public List<Teacher> getTeacherList() {...}
>
> public List<Curriculum> getCurriculumList() {...}
>
> ...
>
> public List<UnavailablePeriodConstraint>
> getUnavailablePeriodConstraintList() {...}
>
> @PlanningEntityCollectionProperty
> public List<Lecture> getLectureList() {...}
>
> public ...Score getScore() {...}
>
> public Collection<? extends Object> getFacts() {
> List<Object> facts = new ArrayList<Object>();
> facts.addAll(teacherList);
> facts.addAll(curriculumList);
> ...
> facts.addAll(unavailablePeriodConstraintList);
> if (isInitialized()) {
> facts.addAll(lectureList);
> }
> facts.addAll(calculateTopicConflictList());
> return facts;
> }
>
> public List<TopicConflict> calculateTopicConflictList() {...}
>
> }
> After in *.java:
> public class ... implements Solution<...> {
>
> private InstitutionalWeighting institutionalWeighting;
>
> private List<Teacher> teacherList;
> private List<Curriculum> curriculumList;
> ...
> private List<UnavailablePeriodConstraint>
> unavailablePeriodConstraintList;
>
> private List<Lecture> lectureList;
>
> private HardAndSoftScore score;
>
> ...
>
> // This is not a PlanningFactProperty: the name is inserted into
> the working memory
> public String getName() {...}
>
> @PlanningFactProperty
> public InstitutionalWeighting getInstitutionalWeighting() {...}
>
> @PlanningFactCollectionProperty
> public List<Teacher> getTeacherList() {...}
>
> @PlanningFactCollectionProperty
> public List<Curriculum> getCurriculumList() {...}
>
> ...
>
> @PlanningFactCollectionProperty
> public List<UnavailablePeriodConstraint>
> getUnavailablePeriodConstraintList() {...}
>
> // This is not a PlanningFactCollectionProperty: it is a
> PlanningEntityCollectionProperty
> @PlanningEntityCollectionProperty
> public List<Lecture> getLectureList() {...}
>
> // This is not a PlanningFactProperty: the score is inserted into
> the working memory
> public ...Score getScore() {...}
>
> // renamed from calculateTopicConflictList because these are also
> facts needed in the working memory
> @PlanningFactCollectionProperty
> public List<TopicConflict> getTopicConflictList() {...}
>
> }
>
> [RECOMMEND] A planning entity is considered uninitialized if one if at
> least on of its planning variables is null.
> Therefor it's now possible to start from a partially initialized solution,
> for example during real-time re-planning as new facts events come in.
>
> [MAJOR] The StartingSolutionInitializer no longer has a
> isSolutionInitialized(AbstractSolverScope) method
> Before in *StartingSolutionInitializer.java:
> public class ...StartingSolutionInitializer extends
> AbstractStartingSolutionInitializer {
>
> @Override
> public boolean isSolutionInitialized(AbstractSolverScope
> abstractSolverScope) {
> ...
> }
>
> ...
>
> }
> After in *StartingSolutionInitializer.java:
> public class ...StartingSolutionInitializer extends
> AbstractStartingSolutionInitializer {
>
> ...
>
> }
>
> [MAJOR] The planning entity collection in the Solution can never be null,
> but some (or all) of its planning entity's can be uninitialized.
> So create them before setting the starting solution, instead of in your
> StartingSolutionInitializer.
> Before in *.java:
> public class ... {
>
> public void ...() {
> CurriculumCourseSchedule schedule = new
> CurriculumCourseSchedule();
> schedule.setTeacherList(teacherList);
> schedule.setCourseList(courseList);
> ...
> solver.setStartingSolution(schedule);
> }
>
> }
> After in *.java:
> public class ... {
>
> public void ...() {
> CurriculumCourseSchedule schedule = new
> CurriculumCourseSchedule();
> schedule.setTeacherList(teacherList);
> schedule.setCourseList(courseList);
> ...
>
> schedule.setLectureList(createLectureList(schedule.getCourseList()));
> solver.setStartingSolution(schedule);
> }
>
> private List<Lecture> createLectureList(List<Course> courseList) {
> List<Lecture> lectureList = new
> ArrayList<Lecture>(courseList.size());
> long id = 0L;
> for (Course course : courseList) {
> for (int i = 0; i < course.getLectureSize(); i++) {
> Lecture lecture = new Lecture();
> lecture.setId((long) id);
> id++;
> lecture.setCourse(course);
> // Make sure to set all non PlanningVariable properties
> lecture.setLectureIndexInCourse(i);
> // Notice that we lave the PlanningVariable properties
> on null
> lectureList.add(lecture);
> }
> }
> return lectureList;
> }
>
> }
>
> [RECOMMENDED] Remove the isInitialized() from Solution if you copied that
> from the examples.
> Before in *.java:
> public class ... implements Solution<...> {
>
> public boolean isInitialized() {
> return (lectureList != null);
> }
>
> ...
>
> }
> After in *.java:
> public class ... implements Solution<...> {
>
> ...
>
> }
>
> *
> The Good News*
>
> I already have written a brute force solver (only useful for very very
> small toy problems of course).
> In time, I 'll write a branch and bound solver (only useful for very small
> toy problems of course).
>
> I 'll write generic, high-quality StartingSolutionInitializers that work on
> any program,
> such as First Fit Decreasing and Cheapest Insertion.
> A good StartingSolutionInitializer is really important to get a good result
> from Planner.
> Currently writing a StartingSolutionInitializer was a bit of a black art.
> Some users use a highly under optimized version or - even worse - none at
> all.
>
> Phasing. This will be fun.
> You 'll be able to do configure this really easily:
> Phase 1 = First Fit Decreasing (for initialization)
> Phase 2 = Simulated Annealing (after initialization)
> Phase 3 = Tabu search (when things get really hard)
> Notice that a StartingSolutionInitializer is just a phase.
>
> [1] https://github.com/droolsjbpm/drools-planner/pull/2/files
>
> --
> With kind regards,
> Geoffrey De Smet
>
>
> _______________________________________________
> rules-dev mailing list
> rules-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-dev/attachments/20110527/25d51750/attachment-0001.html
More information about the rules-dev
mailing list