Optapy领域定义报错java.lang.VerifyError:操作数栈类型错误
Optapy中@problem_fact装饰Availability类时触发java.lang.VerifyError错误
我正在开发一个飞行员排班项目,需将飞行员与副驾驶分配至航班(称为“Duty”),因客户已有Python技术投入,故采用Python开发。本POC基于Optapy员工调度快速入门示例。
代码在初始化Availability类时崩溃,具体发生在包裹该类的@optapy.problem_fact装饰器中,对应文件optapy\annotations.py第585行。
错误栈
File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\PythonClassTranslator.java", line 292, in org.optaplanner.jpyinterpreter.PythonClassTranslator.translatePythonClass Exception: Java Exception The above exception was the direct cause of the following exception: File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\jpyinterpreter\python_to_java_bytecode_translator.py", line 1220, in translate_python_class_to_java_class out = PythonClassTranslator.translatePythonClass(python_compiled_class) File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\jpyinterpreter\python_to_java_bytecode_translator.py", line 422, in convert_to_java_python_like_object out = translate_python_class_to_java_class(raw_type) File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\jpyinterpreter\python_to_java_bytecode_translator.py", line 399, in convert_to_java_python_like_object convert_to_java_python_like_object(map_value, instance_map)) File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\jpyinterpreter\python_to_java_bytecode_translator.py", line 1193, in translate_python_class_to_java_class static_attributes_map.put(attribute[0], convert_to_java_python_like_object(attribute[1])) File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\optapy\optaplanner_java_interop.py", line 1050, in compile_and_get_class parent_class = translate_python_class_to_java_class(python_class).getJavaClass() File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\optapy\optaplanner_java_interop.py", line 1063, in _generate_problem_fact_class parent_class = compile_and_get_class(python_class) File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\optapy\annotations.py", line 585, in problem_fact out.__optapy_java_class = _generate_problem_fact_class(fact_class) File "C:\Users\andre\Desktop\Pilot Rosterer 3000\domain.py", line 131, in <module> class Availability:
具体错误信息
Exception has occurred: java.lang.VerifyError (note: full exception trace is shown but execution is paused at: _run_module_as_main) java.lang.VerifyError: Bad type on operand stack Exception Details: Location: org/jpyinterpreter/user/enum/Enum/__new__$$2.invoke(Lorg/jpyinterpreter/user/domain/AvailabilityType;Lorg/optaplanner/jpyinterpreter/PythonLikeObject;)Lorg/optaplanner/jpyinterpreter/PythonLikeObject; @897: invokestatic Reason: Type 'org/optaplanner/jpyinterpreter/PythonLikeObject' (current frame, stack[1]) is not assignable to 'org/optaplanner/jpyinterpreter/types/PythonLikeType' Current Frame: bci: @897 flags: { } locals: { 'org/jpyinterpreter/user/enum/Enum/__new__$$2', 'org/jpyinterpreter/user/domain/AvailabilityType', 'org/optaplanner/jpyinterpreter/PythonLikeObject', 'org/jpyinterpreter/user/domain/AvailabilityType', 'org/optaplanner/jpyinterpreter/PythonLikeObject', top, 'org/optaplanner/jpyinterpreter/types/PythonNone', top, top, top, null, 'org/optaplanner/jpyinterpreter/types/collections/PythonLikeTuple', top, top, top, top, top, 'java/lang/Object', 'org/optaplanner/jpyinterpreter/PythonLikeObject' } stack: { 'org/optaplanner/jpyinterpreter/PythonLikeObject', 'org/optaplanner/jpyinterpreter/PythonLikeObject', 'org/optaplanner/jpyinterpreter/PythonLikeObject' } Bytecode: 0000000: b200 5a3a 0b2b 4e2c 3a04 2ac0 0002 b400 ... ... ...
相关代码(domain.py)
import optapy import optapy.types import optapy.score import datetime import enum class Route: name: str duration: int base: str def __init__(self, name: str = None, duration: int = None, base: str = None): self.name = name self.duration = duration self.base = base class AvailabilityType(enum.Enum): DESIRED = 'DESIRED' UNDESIRED = 'UNDESIRED' UNAVAILABLE = 'UNAVAILABLE' @staticmethod def list(): return list(map(lambda at: at, AvailabilityType)) @optapy.problem_fact class Pilot: name: str skill_set: list[str] home_base: str duties: list # list[Duty] def __init__(self, name: str = None, skill_set: list[str] = None, home_base: str = None, duties: list = None): self.name = name self.skill_set = skill_set self.home_base = home_base if duties is None: self.duties = [] else: self.duties = duties def get_total_hours(self): # flight hours dt = datetime.timedelta() for duty in self.duties: if duty.work_type != "Flying": continue # skip non-flight duties dt += duty.end - duty.start return dt.seconds/3600 + dt.days*24 def get_todays_hours(self, date: datetime.date): dt = datetime.timedelta() for duty in self.duties: if duty.work_type != "Flying": continue # skip non-flight duties if duty.start.date() != date: continue # skip duties from other days dt += duty.end - duty.start # not taking into account flights over midnight. TODO: fix return dt.seconds/3600 + dt.days*24 def get_total_overtime_hours(self): days = dict() for duty in self.duties: if duty.work_type != "Flying": continue # skip non-flight duties day = duty.start.date() days[day] = days.get(day, datetime.timedelta()) + duty.end - duty.start total_overtime = datetime.timedelta() MAX_FLIGHT_HOURS_ALLOWED = datetime.timedelta(hours=10) for day in days: if day > MAX_FLIGHT_HOURS_ALLOWED: total_overtime += day - MAX_FLIGHT_HOURS_ALLOWED return total_overtime.seconds/3600 + total_overtime.days*24 def __str__(self): return f'Pilot(name={self.name})' def to_dict(self): return { 'name': self.name, 'skill_set': self.skill_set, 'home_base': self.home_base, 'duties': self.duties } def duty_pinning_filter(solution, duty): return not solution.schedule_state.is_draft(duty) @optapy.planning_entity(pinning_filter=duty_pinning_filter) @optapy.planning_pin class Duty: id: int start: datetime.datetime end: datetime.datetime work_type: str detail: str required_skill: str pilot: Pilot # coPilot: Pilot # REMOVED: No longer complicating duties with 2 pilots, rather just creating seperate pilot duties and copilot duties for each route. This allows us to model duties other than flights bases: list[str] # locaiotn(s) from which the duty can be performed def __init__(self, id: int = None, start: datetime.datetime = None, end: datetime.datetime = None, work_type: str = None, detail: str = None, required_skill: str = None, pilot: Pilot = None, bases: list[str] = None): self.id = id self.start = start self.end = end self.work_type = work_type self.detail = detail self.required_skill = required_skill self.pilot = pilot self.bases = bases @optapy.planning_id def get_id(self): return self.id def __str__(self): return f'Duty:{self.id}\t | {self.work_type}, detail={self.detail}, pilot={self.pilot}, start={self.start}, end={self.end}, required_skill={self.required_skill}, bases={self.bases})' def to_dict(self): return { 'id': self.id, 'work_type': self.work_type, 'start': self.start.isoformat(), 'end': self.end.isoformat(), 'detail': self.detail, 'required_skill': self.required_skill, 'pilot': self.pilot.to_dict() if self.pilot is not None else None, 'bases': self.bases } # ============================================================================================ # This is to get around the circular reference problem. # The optapy decorators cannot refence Duty/Pilot before the classes are instantiated, # but the classes rely on eachother being instantiated first before they can instatiated # themselves. Hence the circular reference issue. @optapy.planning_list_variable(Duty, ['duties_list']) def get_duties(self): return self.duties def set_duties(self, duties): self.duties = duties @optapy.planning_variable(Pilot, value_range_provider_refs=['pilot_range']) def get_pilot(self): return self.pilot def set_pilot(self, pilot): self.pilot = pilot Pilot.get_duties = get_duties Pilot.set_duties = set_duties Duty.get_pilot = get_pilot Duty.set_pilot = set_pilot # ============================================================================================ @optapy.problem_fact class Availability: pilot: Pilot date: datetime.date availability_type: AvailabilityType def __init__(self, pilot: Pilot = None, date: datetime.date = None, availability_type: AvailabilityType = None): self.pilot = pilot self.date = date self.availability_type = availability_type def __str__(self): return f'Availability(pilot={self.pilot}, date={self.date}, availability_type={self.availability_type})' def to_dict(self): return { 'pilot': self.pilot.to_dict(), 'date': self.date.isoformat(), 'availability_type': self.availability_type.value } class ScheduleState: publish_length: int draft_length: int first_draft_date: datetime.date last_historic_date: datetime.date def __init__(self, publish_length: int = None, draft_length: int = None, first_draft_date: datetime.date = None, last_historic_date: datetime.date = None): self.publish_length = publish_length self.draft_length = draft_length self.first_draft_date = first_draft_date self.last_historic_date = last_historic_date def is_draft(self, duty): return duty.start >= datetime.datetime.combine(self.first_draft_date, datetime.time.min) def to_dict(self): return { 'publish_length': self.publish_length, 'draft_length': self.draft_length, 'first_draft_date': self.first_draft_date.isoformat(), 'last_historic_date': self.last_historic_date.isoformat() } @optapy.planning_solution class PilotSchedule: schedule_state: ScheduleState availability_list: list[Availability] pilot_list: list[Pilot] duty_list: list[Duty] solver_status: optapy.types.SolverStatus score: optapy.score.SimpleScore def __init__(self, schedule_state, availability_list, pilot_list, duty_list, solver_status, score=None): self.pilot_list = pilot_list self.availability_list = availability_list self.schedule_state = schedule_state self.duty_list = duty_list self.solver_status = solver_status self.score = score @optapy.problem_fact_collection_property(Pilot) @optapy.value_range_provider('pilot_range') def get_pilot_list(self): return self.pilot_list @optapy.problem_fact_collection_property(Availability) def get_availability_list(self): return self.availability_list @optapy.planning_entity_collection_property(Duty) def get_duty_list(self): return self.duty_list @optapy.planning_score(optapy.score.HardSoftScore) def get_score(self): return self.score def set_score(self, score): self.score = score def to_dict(self): return { 'pilot_list': list(map(lambda pilot: pilot.to_dict(), self.pilot_list)), 'availability_list': list(map(lambda availability: availability.to_dict(), self.availability_list)), 'schedule_state': self.schedule_state.to_dict(), 'duty_list': list(map(lambda duty: duty.to_dict(), self.duty_list)), 'solver_status': self.solver_status.toString(), 'score': self.score.toString(), }
内容的提问来源于stack exchange,提问作者Andrew M
相关产品推荐
相关产品推荐

