java.lang.IllegalStateException: Error occurred when wrapping object

176 Views Asked by At

Here is my problem to solve using optapy.

@problem_fact
class Room:
    id: int
    name: str

    def __init__(self, id, name):
        self.id = id
        self.name = name

    @planning_id
    def get_id(self):
        return self.id

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"


@problem_fact
class Timeslot:
    id: int
    day_of_week: str
    start_time: datetime.time
    end_time: datetime.time

    def __init__(self, id, day_of_week, start_time, end_time):
        self.id = id
        self.day_of_week = day_of_week
        self.start_time = start_time
        self.end_time = end_time
    
    
                       
    @planning_id
    def get_id(self):
        return self.id
    
    def set_value(self, id):
        self.id = id
        
    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )
@problem_fact
class Base:
    pass

@planning_entity
class Slot(Base):
    def __init__(self, timeslot=None):
        self.timeslot = timeslot
        # self.timeslot1 = timeslot1
        
    @optapy.planning_variable(Base, value_range_provider_refs=['timeslotRangeLSEntity', 'timeslotRangeLBEntity'],
                              graph_type=PlanningVariableGraphType.CHAINED)
    def get_timeslot(self):
        return self.timeslot

    def set_timeslot(self, new_timeslot):
        self.timeslot = new_timeslot
    
   
@planning_entity
class Lesson(Slot):
    id: int
    subject: str
    teacher: str
    student_group: str
    timeslot: Timeslot
    room: Room

    def __init__(self, id, subject, teacher, student_group,timeslot=None, room=None):
        self.id = id
        self.subject = subject
        self.teacher = teacher
        self.student_group = student_group
        self.timeslot = timeslot
        self.room = room
    
    @planning_id
    def get_id(self):
        return self.id
    
    @planning_variable(Room, ["roomRange"])
    def get_room(self):
        return self.room

    def set_room(self, new_room):
        self.room = new_room
        
    def __str__(self):
        return (
            f"Lesson("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )

@planning_entity
class Lab(Slot):
    id: int
    subject: str
    teacher: str
    student_group: str
    timeslot: Timeslot
    room: Room

    def __init__(self, id, subject, teacher, student_group,timeslot=None, room=None):
        self.id = id
        self.subject = subject
        self.teacher = teacher
        self.student_group = student_group
        self.timeslot = timeslot
        self.room = room
    
    @planning_id
    def get_id(self):
        return self.id
    
    @planning_variable(Room, ["roomRange"])
    def get_room(self):
        return self.room

    def set_room(self, new_room):
        self.room = new_room

    def __str__(self):
        return (
            f"Lab("
            f"id={self.id}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )
def format_list(a_list):
    return ',\n'.join(map(str, a_list))


@planning_solution
class TimeTable:
    timeslot_list: list[Timeslot]
    # timeslot_list1: list[Timeslot]
    room_list: list[Room]
    lesson_list: list[Lesson]
    lab_list: list[Lab]
    score: HardSoftScore

    def __init__(self, timeslot_list, room_list, lesson_list,lab_list, score=None):
        self.timeslot_list = timeslot_list
        # self.timeslot_list1 = timeslot_list1
        self.room_list = room_list
        self.lesson_list = lesson_list
        self.lab_list = lab_list
        self.score = score
    

    @problem_fact_collection_property(Room)
    @value_range_provider("roomRange")
    def get_room_list(self):
        return self.room_list

    @planning_entity_collection_property(Slot)
    @value_range_provider("timeslotRangeLSEntity")
    def get_lesson_list(self):
        return self.lesson_list

    @planning_entity_collection_property(Slot)
    @value_range_provider("timeslotRangeLBEntity")
    def get_lab_list(self):
        return self.lab_list

    @planning_score(HardSoftScore)
    def get_score(self):
        return self.score

    def set_score(self, score):
        self.score = score

    def __str__(self):
        return (
            f"TimeTable("
            f"timeslot_list={format_list(self.timeslot_list)},\n"
            # f"timeslot_list1={format_list(self.timeslot_list1)},\n"
            f"room_list={format_list(self.room_list)},\n"
            f"lesson_list={format_list(self.lesson_list)},\n"
            f"lab_list={format_list(self.lab_list)},\n"
            f"score={str(self.score.toString()) if self.score is not None else 'None'}"
            f")"
        )


def generate_problem():
    timeslot_list = [
        Timeslot(1, "MONDAY", time(hour=8, minute=30), time(hour=9, minute=30)),
        Timeslot(2, "MONDAY", time(hour=9, minute=30), time(hour=10, minute=30)),
        Timeslot(3, "MONDAY", time(hour=10, minute=30), time(hour=11, minute=30)),
        Timeslot(4, "MONDAY", time(hour=13, minute=30), time(hour=14, minute=30)),
        Timeslot(5, "MONDAY", time(hour=14, minute=30), time(hour=15, minute=30)),
        Timeslot(6, "TUESDAY", time(hour=10, minute=30), time(hour=11, minute=30)),
        Timeslot(7, "TUESDAY", time(hour=13, minute=30), time(hour=14, minute=30)),
        Timeslot(8, "TUESDAY", time(hour=14, minute=30), time(hour=15, minute=30)),
        Timeslot(9, "TUESDAY", time(hour=15, minute=30), time(hour=16, minute=30)),
        Timeslot(10, "TUESDAY", time(hour=16, minute=30), time(hour=17, minute=30)),
        Timeslot(11, "MONDAY", time(hour=15, minute=30), time(hour=17, minute=30)),
        Timeslot(12, "TUESDAY", time(hour=8, minute=30), time(hour=10, minute=30))
    ]
    # timeslot_list1 = [
        
    # ]
    room_list = [
        Room(1, "Room A"),
        Room(2, "Room B"),
        Room(3, "Room C"),
        Room(4, "Room D")
    ]
    
    lesson_list = [
        Lesson(1, "Math", "A. Turing", "9th grade"),
        Lesson(2, "Math", "A. Turing", "9th grade"),
        Lesson(3, "Physics", "M. Curie", "9th grade"),
        Lesson(4, "Chemistry", "M. Curie", "9th grade"),
        Lesson(5, "Biology", "C. Darwin", "9th grade"),
        Lesson(6, "History", "I. Jones", "9th grade"),
        Lesson(7, "English", "I. Jones", "9th grade"),
        Lesson(8, "English", "I. Jones", "9th grade"),
        Lesson(9, "Spanish", "P. Cruz", "9th grade"),
        Lesson(10, "Spanish", "P. Cruz", "9th grade"),
        Lesson(11, "Math", "A. Turing", "10th grade"),
        Lesson(12, "Math", "A. Turing", "10th grade"),
        Lesson(13, "Math", "A. Turing", "10th grade"),
        Lesson(14, "Physics", "M. Curie", "10th grade"),
        Lesson(15, "Chemistry", "M. Curie", "10th grade"),
        Lesson(16, "French", "M. Curie", "10th grade"),
        Lesson(17, "Geography", "C. Darwin", "10th grade"),
        Lesson(18, "History", "I. Jones", "10th grade"),
        Lesson(19, "English", "P. Cruz", "10th grade"),
        Lesson(20, "Spanish", "P. Cruz", "10th grade")
        
    ]
    
    lab_list = [
        Lab(21, "LAB", "Selva", "9th grade"),
        Lab(22, "LAB", "Selva", "10th grade")
    ]
    
    lesson = lesson_list[0]
    lesson.set_timeslot(timeslot_list[0])
    lesson.set_room(room_list[0])
    
    lab = lab_list[0]
    lab.set_timeslot(timeslot_list[10])
    lab.set_room(room_list[3])

    return TimeTable(timeslot_list, room_list, lesson_list,lab_list)

Here I used Base class(@problem_fact) and extended the abstract class as Slot(@planning_entity). Here I declared the timeslot as a common for two @planning_entity(one is Lab another one is Lesson). I am passing 2 different timeslot range for those two @planning_entity.

When i used to solve this problem i am getting below error!

java.lang.IllegalStateException: Error occurred when wrapping object (Lab(id=21, timeslot=Timeslot(id=11, day_of_week=MONDAY, start_time=15:30:00, end_time=17:30:00), room=Room(id=4, name=Room D), teacher=Selva, subject=LAB, student_group=9th grade)).

Kindly help me to solve this! Thanks

2

There are 2 best solutions below

2
Christopher Chianelli On

Your model is incorrect: you have a chained @planning_variable in Slot without an anchor value range ('timeslotRangeLSEntity' and 'timeslotRangeLBEntity' correspond to Lesson and Lab respectively, which are both planning entities that extend Slot, which cannot be used as an anchor). I am guessing you want TimeSlot to be your anchor. However, currently, it does not extend Base, so you need to modify TimeSlot to extend Base.

However, you are also hitting an OptaPlanner bug: having multiple planning entity classes in a chained model will throw a class cast exception (https://issues.redhat.com/browse/PLANNER-2798). Until the bug is fixed, you need to workaround it. What this mean in your scenario is that Lab and Lesson need to be merged into one class, and in order to distinguish them, you need to use a field on the class. This modified domain should work:

import datetime
from datetime import time

import optapy
import optapy.config
from optapy.score import HardSoftScore
from optapy.types import PlanningVariableGraphType

@optapy.problem_fact
class Room:
    id: int
    name: str

    def __init__(self, id, name):
        self.id = id
        self.name = name

    @optapy.planning_id
    def get_id(self):
        return self.id

    def __str__(self):
        return f"Room(id={self.id}, name={self.name})"


@optapy.problem_fact
class Base:
    pass


@optapy.problem_fact
class Timeslot(Base):
    id: int
    day_of_week: str
    start_time: datetime.time
    end_time: datetime.time

    def __init__(self, id, day_of_week, start_time, end_time):
        self.id = id
        self.day_of_week = day_of_week
        self.start_time = start_time
        self.end_time = end_time
    
                       
    @optapy.planning_id
    def get_id(self):
        return self.id
    
    def set_value(self, id):
        self.id = id
        
    def __str__(self):
        return (
                f"Timeslot("
                f"id={self.id}, "
                f"day_of_week={self.day_of_week}, "
                f"start_time={self.start_time}, "
                f"end_time={self.end_time})"
        )

    
   
@optapy.planning_entity
class LessonOrLab(Base):
    id: int
    kind: str
    subject: str
    teacher: str
    student_group: str
    timeslot: Base
    room: Room

    def __init__(self, id, kind, subject, teacher, student_group,timeslot=None, room=None):
        self.id = id
        self.subject = subject
        self.teacher = teacher
        self.student_group = student_group
        self.timeslot = timeslot
        self.room = room
    
    @optapy.planning_id
    def get_id(self):
        return self.id
    
    @optapy.planning_variable(Base, value_range_provider_refs=['timeslotRange', 'lessonOrLabRange'],
                              graph_type=PlanningVariableGraphType.CHAINED)
    def get_timeslot(self):
        return self.timeslot

    def set_timeslot(self, new_timeslot):
        self.timeslot = new_timeslot

    @optapy.planning_variable(Room, ["roomRange"])
    def get_room(self):
        return self.room

    def set_room(self, new_room):
        self.room = new_room
        
    def __str__(self):
        return (
            f"LessonOrLab("
            f"id={self.id}, "
            f"kind={self.kind}, "
            f"timeslot={self.timeslot}, "
            f"room={self.room}, "
            f"teacher={self.teacher}, "
            f"subject={self.subject}, "
            f"student_group={self.student_group}"
            f")"
        )

def format_list(a_list):
    return ',\n'.join(map(str, a_list))


@optapy.planning_solution
class TimeTable:
    timeslot_list: list[Timeslot]
    room_list: list[Room]
    lesson_or_lab_list: list[LessonOrLab]
    score: HardSoftScore

    def __init__(self, timeslot_list, room_list, lesson_or_lab_list, score=None):
        self.timeslot_list = timeslot_list
        self.room_list = room_list
        self.lesson_or_lab_list = lesson_or_lab_list
        self.score = score
    

    @optapy.problem_fact_collection_property(Room)
    @optapy.value_range_provider("roomRange")
    def get_room_list(self):
        return self.room_list

    @optapy.problem_fact_collection_property(Timeslot)
    @optapy.value_range_provider("timeslotRange")
    def get_timeslot_list(self):
        return self.timeslot_list

    @optapy.planning_entity_collection_property(LessonOrLab)
    @optapy.value_range_provider("lessonOrLabRange")
    def get_lesson_list(self):
        return self.lesson_or_lab_list

    @optapy.planning_score(HardSoftScore)
    def get_score(self):
        return self.score

    def set_score(self, score):
        self.score = score

    def __str__(self):
        return (
            f"TimeTable("
            f"timeslot_list={format_list(self.timeslot_list)},\n"
            f"room_list={format_list(self.room_list)},\n"
            f"lesson_or_lab_list={format_list(self.lesson_or_lab_list)},\n"
            f"score={str(self.score.toString()) if self.score is not None else 'None'}"
            f")"
        )


def generate_problem():
    timeslot_list = [
        Timeslot(1, "MONDAY", time(hour=8, minute=30), time(hour=9, minute=30)),
        Timeslot(2, "MONDAY", time(hour=9, minute=30), time(hour=10, minute=30)),
        Timeslot(3, "MONDAY", time(hour=10, minute=30), time(hour=11, minute=30)),
        Timeslot(4, "MONDAY", time(hour=13, minute=30), time(hour=14, minute=30)),
        Timeslot(5, "MONDAY", time(hour=14, minute=30), time(hour=15, minute=30)),
        Timeslot(6, "TUESDAY", time(hour=10, minute=30), time(hour=11, minute=30)),
        Timeslot(7, "TUESDAY", time(hour=13, minute=30), time(hour=14, minute=30)),
        Timeslot(8, "TUESDAY", time(hour=14, minute=30), time(hour=15, minute=30)),
        Timeslot(9, "TUESDAY", time(hour=15, minute=30), time(hour=16, minute=30)),
        Timeslot(10, "TUESDAY", time(hour=16, minute=30), time(hour=17, minute=30)),
        Timeslot(11, "MONDAY", time(hour=15, minute=30), time(hour=17, minute=30)),
        Timeslot(12, "TUESDAY", time(hour=8, minute=30), time(hour=10, minute=30))
    ]
    # timeslot_list1 = [
        
    # ]
    room_list = [
        Room(1, "Room A"),
        Room(2, "Room B"),
        Room(3, "Room C"),
        Room(4, "Room D")
    ]
    
    lesson_or_lab_list = [
        LessonOrLab(1, "Lesson", "Math", "A. Turing", "9th grade"),
        LessonOrLab(2, "Lesson", "Math", "A. Turing", "9th grade"),
        LessonOrLab(3, "Lesson", "Physics", "M. Curie", "9th grade"),
        LessonOrLab(4, "Lesson", "Chemistry", "M. Curie", "9th grade"),
        LessonOrLab(5, "Lesson", "Biology", "C. Darwin", "9th grade"),
        LessonOrLab(6, "Lesson", "History", "I. Jones", "9th grade"),
        LessonOrLab(7, "Lesson", "English", "I. Jones", "9th grade"),
        LessonOrLab(8, "Lesson", "English", "I. Jones", "9th grade"),
        LessonOrLab(9, "Lesson", "Spanish", "P. Cruz", "9th grade"),
        LessonOrLab(10, "Lesson", "Spanish", "P. Cruz", "9th grade"),
        LessonOrLab(11, "Lesson", "Math", "A. Turing", "10th grade"),
        LessonOrLab(12, "Lesson", "Math", "A. Turing", "10th grade"),
        LessonOrLab(13, "Lesson", "Math", "A. Turing", "10th grade"),
        LessonOrLab(14, "Lesson", "Physics", "M. Curie", "10th grade"),
        LessonOrLab(15, "Lesson", "Chemistry", "M. Curie", "10th grade"),
        LessonOrLab(16, "Lesson", "French", "M. Curie", "10th grade"),
        LessonOrLab(17, "Lesson", "Geography", "C. Darwin", "10th grade"),
        LessonOrLab(18, "Lesson", "History", "I. Jones", "10th grade"),
        LessonOrLab(19, "Lesson", "English", "P. Cruz", "10th grade"),
        LessonOrLab(20, "Lesson", "Spanish", "P. Cruz", "10th grade"),
        LessonOrLab(21, "Lab", "LAB", "Selva", "9th grade"),
        LessonOrLab(22, "Lab", "LAB", "Selva", "10th grade")
    ]
    
    lesson = lesson_or_lab_list[0]
    lesson.set_timeslot(timeslot_list[0])
    lesson.set_room(room_list[0])
    
    lab = lesson_or_lab_list[-2]
    lab.set_timeslot(timeslot_list[10])
    lab.set_room(room_list[3])

    return TimeTable(timeslot_list, room_list, lesson_or_lab_list)
6
Alejandro Gómez Montoya On

I executed your Domain (Christopher) with the following constraints:

    def room_conflict(constraint_factory: ConstraintFactory):
        # A room can accommodate at most one lesson at the same time.
        return constraint_factory \
            .for_each(LessonOrLab) \
            .join(LessonOrLab,
                  # ... in the same timeslot ...
                  Joiners.equal(lambda lesson: lesson.timeslot),
                  # ... in the same room ...
                  Joiners.equal(lambda lesson: lesson.room),
                  # form unique pairs
                  Joiners.less_than(lambda lesson: lesson.id)
                  ) \
            .penalize("Room conflict", HardSoftScore.ONE_HARD)
    
    
    def teacher_conflict(constraint_factory: ConstraintFactory):
        # A teacher can teach at most one lesson at the same time.
        return constraint_factory \
            .for_each(LessonOrLab) \
            .join(LessonOrLab,
                  Joiners.equal(lambda lesson: lesson.timeslot),
                  Joiners.equal(lambda lesson: lesson.teacher),
                  Joiners.less_than(lambda lesson: lesson.id)
                  ) \
            .penalize("Teacher conflict", HardSoftScore.ONE_HARD)
    
    
    def student_group_conflict(constraint_factory: ConstraintFactory):
        # A student can attend at most one lesson at the same time.
        return constraint_factory \
            .for_each(LessonOrLab) \
            .join(LessonOrLab,
                  Joiners.equal(lambda lesson: lesson.timeslot),
                  Joiners.equal(lambda lesson: lesson.student_group),
                  Joiners.less_than(lambda lesson: lesson.id)
                  ) \
            .penalize("Student group conflict", HardSoftScore.ONE_HARD)

However, the solution just assign two LessonOrLab:

|------------|------------|------------|------------|------------|
|            | Room A     | Room B     | Room C     | Room D     | 
|------------|------------|------------|------------|------------|
| MON 08:30: | LAB        |            |            |            | 
|            | Selva      |            |            |            | 
|            | 10th grade |            |            |            | 
|------------|------------|------------|------------|------------|
| MON 09:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| MON 10:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| MON 13:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| MON 14:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| TUE 10:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| TUE 13:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| TUE 14:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| TUE 15:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| TUE 16:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|
| MON 15:30: |            |            |            | LAB        | 
|            |            |            |            | P. Cruz    | 
|            |            |            |            | 10th grade | 
|------------|------------|------------|------------|------------|
| TUE 08:30: |            |            |            |            | 
|            |            |            |            |            | 
|            |            |            |            |            | 
|------------|------------|------------|------------|------------|