[rules-dev] Planner big user impacting changes: declarative metamodel
Geoffrey De Smet
ge0ffrey.spam at gmail.com
Sun May 29 05:00:51 EDT 2011
After discussing with ubba, I 've decided to revert a small part of this
change:
@PlanningFactCollectionProperty (and @PlanningFactProperty) goes to
to trashcan
and the Solution.getFacts() method is reinstated (but shouldn't insert
the planning entities no more).
Op 29-05-11 10:22, Geoffrey De Smet schreef:
> Op 27-05-11 22:39, Michael Anstis schreef:
>> 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?
> The real value will be explained in the manual later and visible when
> we build stuff on this :)
> This mail is mainly to rattle people's cages:
> *can you live with the bad side of these changes or not?*
> Speak up now, before I go further on this path and there's no going back.
>
>>
>> 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
> Good point that I need to explain it better to open up the discussion.
> Basically, Planner needs to know what are you planning variables (of
> the planning entity classes) and what are allowed values of each
> planning variable (ignoring the non-build-in constraints).
> It's also the first step to declarative moves.
>>
>> Perhaps I missed something?
>>
>> With kind regards
>>
>> Mike
>>
>> On 27 May 2011 11:13, Geoffrey De Smet <ge0ffrey.spam at gmail.com
>> <mailto: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 <mailto:rules-dev at lists.jboss.org>
>> https://lists.jboss.org/mailman/listinfo/rules-dev
>>
>>
>>
>> _______________________________________________
>> rules-dev mailing list
>> rules-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-dev
>
> --
> With kind regards,
> Geoffrey De Smet
>
>
> _______________________________________________
> rules-dev mailing list
> rules-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-dev
--
With kind regards,
Geoffrey De Smet
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-dev/attachments/20110529/c4fc7402/attachment-0001.html
More information about the rules-dev
mailing list