Optapy领域定义帮助。出现错误: java.lang.VerifyError: 操作数栈上的错误类型

huangapple go评论98阅读模式
英文:

Optapy domain definitions help. Getting error: java.lang.VerifyError: Bad type on operand stack

问题

我正在尝试编写一个飞行员排班项目,其中需要分配飞行员和副驾驶员到航班("Duty")。我使用Python是因为客户已经在Python方面有一些投资。

我正在基于optapy员工排班快速入门来开展这个POC。

问题出现在我的domain.py文件中,尝试初始化我的Availability类时。具体地说,在包装它的@optapy.problem_fact装饰器中出现了问题。optapy\annotations.py, 第585行

错误如下:

  1. 异常已发生: java.lang.VerifyError(注意: 显示了完整的异常跟踪,但执行已暂停在: _run_module_as_main
  2. java.lang.VerifyError: 操作数栈上的错误类型
  3. 异常详情:
  4. 位置:
  5. org/jpyinterpreter/user/enum/Enum/__new__$$2.invoke(Lorg/jpyinterpreter/user/domain/AvailabilityType;Lorg/optaplanner/jpyinterpreter/PythonLikeObject;)Lorg/optaplanner/jpyinterpreter/PythonLikeObject; @897: invokestatic
  6. 原因:
  7. 类型 'org/optaplanner/jpyinterpreter/PythonLikeObject'(当前帧,堆栈[1])无法分配给 'org/optaplanner/jpyinterpreter/types/PythonLikeType'
  8. 当前帧:
  9. bci: @897
  10. 标志: { }
  11. 本地变量: { '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' }
  12. 堆栈: { 'org/optaplanner/jpyinterpreter/PythonLikeObject', 'org/optaplanner/jpyinterpreter/PythonLikeObject', 'org/optaplanner/jpyinterpreter/PythonLikeObject' }
  13. 字节码:
  14. 0000000: b200 5a3a 0b2b 4e2c 3a04 2ac0 0002 b400
  15. ... ... ...

如果您需要关于特定问题的帮助,请提供更多详细信息,以便我能更好地理解并提供更具体的建议。

英文:

I am trying to write a pilot rostering project, where pilots and copilots need to be assigned to flights ("Duty"). I'm using python because there are existing python investments at the client.

I'm basing this POC off of the optapy Employee Scheduling quickstart.

The code is crashing in my domain.py, while trying to init my Availability class.
Specifically, in the @optapy.problem_fact decorator wrapping it. optapy\annotations.py, line 585

  1. File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\PythonClassTranslator.java", line 292, in org.optaplanner.jpyinterpreter.PythonClassTranslator.translatePythonClass
  2. Exception: Java Exception
  3. The above exception was the direct cause of the following exception:
  4. 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
  5. out = PythonClassTranslator.translatePythonClass(python_compiled_class)
  6. 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
  7. out = translate_python_class_to_java_class(raw_type)
  8. 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
  9. convert_to_java_python_like_object(map_value, instance_map))
  10. 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
  11. static_attributes_map.put(attribute[0], convert_to_java_python_like_object(attribute[1]))
  12. File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\optapy\optaplanner_java_interop.py", line 1050, in compile_and_get_class
  13. parent_class = translate_python_class_to_java_class(python_class).getJavaClass()
  14. File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\optapy\optaplanner_java_interop.py", line 1063, in _generate_problem_fact_class
  15. parent_class = compile_and_get_class(python_class)
  16. File "C:\Users\andre\AppData\Local\Programs\Python\Python39\Lib\site-packages\optapy\annotations.py", line 585, in problem_fact
  17. out.__optapy_java_class = _generate_problem_fact_class(fact_class)
  18. File "C:\Users\andre\Desktop\Pilot Rosterer 3000\domain.py", line 131, in <module>
  19. class Availability:

The error is as following:

  1. Exception has occurred: java.lang.VerifyError (note: full exception trace is shown but execution is paused at: _run_module_as_main)
  2. java.lang.VerifyError: Bad type on operand stack
  3. Exception Details:
  4. Location:
  5. org/jpyinterpreter/user/enum/Enum/__new__$$2.invoke(Lorg/jpyinterpreter/user/domain/AvailabilityType;Lorg/optaplanner/jpyinterpreter/PythonLikeObject;)Lorg/optaplanner/jpyinterpreter/PythonLikeObject; @897: invokestatic
  6. Reason:
  7. Type 'org/optaplanner/jpyinterpreter/PythonLikeObject' (current frame, stack[1]) is not assignable to 'org/optaplanner/jpyinterpreter/types/PythonLikeType'
  8. Current Frame:
  9. bci: @897
  10. flags: { }
  11. 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' }
  12. stack: { 'org/optaplanner/jpyinterpreter/PythonLikeObject', 'org/optaplanner/jpyinterpreter/PythonLikeObject', 'org/optaplanner/jpyinterpreter/PythonLikeObject' }
  13. Bytecode:
  14. 0000000: b200 5a3a 0b2b 4e2c 3a04 2ac0 0002 b400
  15. ... ... ...

domain.py

  1. import optapy
  2. import optapy.types
  3. import optapy.score
  4. import datetime
  5. import enum
  6. class Route:
  7. name: str
  8. duration: int
  9. base: str
  10. def __init__(self, name: str = None, duration: int = None, base: str = None):
  11. self.name = name
  12. self.duration = duration
  13. self.base = base
  14. class AvailabilityType(enum.Enum):
  15. DESIRED = 'DESIRED'
  16. UNDESIRED = 'UNDESIRED'
  17. UNAVAILABLE = 'UNAVAILABLE'
  18. @staticmethod
  19. def list():
  20. return list(map(lambda at: at, AvailabilityType))
  21. @optapy.problem_fact
  22. class Pilot:
  23. name: str
  24. skill_set: list[str]
  25. home_base: str
  26. duties: list # list[Duty]
  27. def __init__(self, name: str = None, skill_set: list[str] = None, home_base: str = None, duties: list = None):
  28. self.name = name
  29. self.skill_set = skill_set
  30. self.home_base = home_base
  31. if duties is None:
  32. self.duties = []
  33. else:
  34. self.duties = duties
  35. def get_total_hours(self): # flight hours
  36. dt = datetime.timedelta()
  37. for duty in self.duties:
  38. if duty.work_type != "Flying": continue # skip non-flight duties
  39. dt += duty.end - duty.start
  40. return dt.seconds/3600 + dt.days*24
  41. def get_todays_hours(self, date: datetime.date):
  42. dt = datetime.timedelta()
  43. for duty in self.duties:
  44. if duty.work_type != "Flying": continue # skip non-flight duties
  45. if duty.start.date() != date: continue # skip duties from other days
  46. dt += duty.end - duty.start # not taking into account flights over midnight. TODO: fix
  47. return dt.seconds/3600 + dt.days*24
  48. def get_total_overtime_hours(self):
  49. days = dict()
  50. for duty in self.duties:
  51. if duty.work_type != "Flying": continue # skip non-flight duties
  52. day = duty.start.date()
  53. days[day] = days.get(day, datetime.timedelta()) + duty.end - duty.start
  54. total_overtime = datetime.timedelta()
  55. MAX_FLIGHT_HOURS_ALLOWED = datetime.timedelta(hours=10)
  56. for day in days:
  57. if day > MAX_FLIGHT_HOURS_ALLOWED:
  58. total_overtime += day - MAX_FLIGHT_HOURS_ALLOWED
  59. return total_overtime.seconds/3600 + total_overtime.days*24
  60. def __str__(self):
  61. return f'Pilot(name={self.name})'
  62. def to_dict(self):
  63. return {
  64. 'name': self.name,
  65. 'skill_set': self.skill_set,
  66. 'home_base': self.home_base,
  67. 'duties': self.duties
  68. }
  69. def duty_pinning_filter(solution, duty):
  70. return not solution.schedule_state.is_draft(duty)
  71. @optapy.planning_entity(pinning_filter=duty_pinning_filter)
  72. @optapy.planning_pin
  73. class Duty:
  74. id: int
  75. start: datetime.datetime
  76. end: datetime.datetime
  77. work_type: str
  78. detail: str
  79. required_skill: str
  80. pilot: Pilot
  81. # 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
  82. bases: list[str] # locaiotn(s) from which the duty can be performed
  83. 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):
  84. self.id = id
  85. self.start = start
  86. self.end = end
  87. self.work_type = work_type
  88. self.detail = detail
  89. self.required_skill = required_skill
  90. self.pilot = pilot
  91. self.bases = bases
  92. @optapy.planning_id
  93. def get_id(self):
  94. return self.id
  95. def __str__(self):
  96. 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})'
  97. def to_dict(self):
  98. return {
  99. 'id': self.id,
  100. 'work_type': self.work_type,
  101. 'start': self.start.isoformat(),
  102. 'end': self.end.isoformat(),
  103. 'detail': self.detail,
  104. 'required_skill': self.required_skill,
  105. 'pilot': self.pilot.to_dict() if self.pilot is not None else None,
  106. 'bases': self.bases
  107. }
  108. # ============================================================================================
  109. # This is to get around the circular reference problem.
  110. # The optapy decorators cannot refence Duty/Pilot before the classes are instantiated,
  111. # but the classes rely on eachother being instantiated first before they can instatiated
  112. # themselves. Hence the circular reference issue.
  113. @optapy.planning_list_variable(Duty, ['duties_list'])
  114. def get_duties(self):
  115. return self.duties
  116. def set_duties(self, duties):
  117. self.duties = duties
  118. @optapy.planning_variable(Pilot, value_range_provider_refs=['pilot_range'])
  119. def get_pilot(self):
  120. return self.pilot
  121. def set_pilot(self, pilot):
  122. self.pilot = pilot
  123. Pilot.get_duties = get_duties
  124. Pilot.set_duties = set_duties
  125. Duty.get_pilot = get_pilot
  126. Duty.set_pilot = set_pilot
  127. # ============================================================================================
  128. @optapy.problem_fact
  129. class Availability:
  130. pilot: Pilot
  131. date: datetime.date
  132. availability_type: AvailabilityType
  133. def __init__(self, pilot: Pilot = None, date: datetime.date = None, availability_type: AvailabilityType = None):
  134. self.pilot = pilot
  135. self.date = date
  136. self.availability_type = availability_type
  137. def __str__(self):
  138. return f'Availability(pilot={self.pilot}, date={self.date}, availability_type={self.availability_type})'
  139. def to_dict(self):
  140. return {
  141. 'pilot': self.pilot.to_dict(),
  142. 'date': self.date.isoformat(),
  143. 'availability_type': self.availability_type.value
  144. }
  145. class ScheduleState:
  146. publish_length: int
  147. draft_length: int
  148. first_draft_date: datetime.date
  149. last_historic_date: datetime.date
  150. def __init__(self, publish_length: int = None, draft_length: int = None, first_draft_date: datetime.date = None, last_historic_date: datetime.date = None):
  151. self.publish_length = publish_length
  152. self.draft_length = draft_length
  153. self.first_draft_date = first_draft_date
  154. self.last_historic_date = last_historic_date
  155. def is_draft(self, duty):
  156. return duty.start >= datetime.datetime.combine(self.first_draft_date, datetime.time.min)
  157. def to_dict(self):
  158. return {
  159. 'publish_length': self.publish_length,
  160. 'draft_length': self.draft_length,
  161. 'first_draft_date': self.first_draft_date.isoformat(),
  162. 'last_historic_date': self.last_historic_date.isoformat()
  163. }
  164. @optapy.planning_solution
  165. class PilotSchedule:
  166. schedule_state: ScheduleState
  167. availability_list: list[Availability]
  168. pilot_list: list[Pilot]
  169. duty_list: list[Duty]
  170. solver_status: optapy.types.SolverStatus
  171. score: optapy.score.SimpleScore
  172. def __init__(self, schedule_state, availability_list, pilot_list, duty_list, solver_status, score=None):
  173. self.pilot_list = pilot_list
  174. self.availability_list = availability_list
  175. self.schedule_state = schedule_state
  176. self.duty_list = duty_list
  177. self.solver_status = solver_status
  178. self.score = score
  179. @optapy.problem_fact_collection_property(Pilot)
  180. @optapy.value_range_provider('pilot_range')
  181. def get_pilot_list(self):
  182. return self.pilot_list
  183. @optapy.problem_fact_collection_property(Availability)
  184. def get_availability_list(self):
  185. return self.availability_list
  186. @optapy.planning_entity_collection_property(Duty)
  187. def get_duty_list(self):
  188. return self.duty_list
  189. @optapy.planning_score(optapy.score.HardSoftScore)
  190. def get_score(self):
  191. return self.score
  192. def set_score(self, score):
  193. self.score = score
  194. def to_dict(self):
  195. return {
  196. 'pilot_list': list(map(lambda pilot: pilot.to_dict(), self.pilot_list)),
  197. 'availability_list': list(map(lambda availability: availability.to_dict(), self.availability_list)),
  198. 'schedule_state': self.schedule_state.to_dict(),
  199. 'duty_list': list(map(lambda duty: duty.to_dict(), self.duty_list)),
  200. 'solver_status': self.solver_status.toString(),
  201. 'score': self.score.toString(),
  202. }

答案1

得分: 1

这是OptaPy的一个错误(请参阅https://github.com/optapy/optapy/issues/146)。特别是,当翻译一个enum.Enum类时,似乎是因为AvailabilityAvailabilityType进行了类型注解而引起的(AvailabilityType是一个枚举)。移除类型注解可能会修复这个问题(因为那样AvailabilityType不会被翻译,直到解决,这更宽容一些(因为翻译会导致错误,它将被翻译为指向CPython类的指针)。当问题得到修复时,将更新此答案。

英文:

This is a bug with OptaPy (see https://github.com/optapy/optapy/issues/146). In particular, it seems to be caused when translating an enum.Enum class (which is caused because Availability has type annotation for AvailabilityType, an enum). Removing the type annotation might fix the issue (since then AvailabilityType will not be translated until solving, which is more forgiving (since the translation results in an error, it will be translated as a pointer to a CPython class)). Will update this answer when the issue is fixed.

答案2

得分: 0

从Python 3.9.0升级到3.11.1解决了我的问题。

英文:

Updating from Python 3.9.0 to 3.11.1 solved the issue for me.

huangapple
  • 本文由 发表于 2023年2月6日 17:27:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75359455.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定