[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