optapy / optapy

OptaPy is an AI constraint solver for Python to optimize planning and scheduling problems.

Home Page:https://www.optapy.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Pinned planning entity results in NullPointerException

mmmvvvppp opened this issue · comments

With the current main branch, I've run into a bug with a pinned planning entity.

Error is reported as:

21:39:01.401 [main        ] INFO  Construction Heuristic phase (0) ended: time spent (25), best score (-2init/0hard/-2soft), score calculation speed (2500/sec), step total (2).
Traceback (most recent call last):
  File "DefaultSolver.java", line 209, in org.optaplanner.core.impl.solver.DefaultSolver.solve
Exception: Java Exception

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/mmmvvvppp/workspaces/optapy_crash/venv/lib/python3.10/site-packages/optapy/optaplanner_api_wrappers.py", line 384, in solve
    return _unwrap_java_object(self._java_solve(wrapped_problem))
java.lang.java.lang.NullPointerException: java.lang.NullPointerException: Cannot invoke "org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore.getInitScore()" because "subtrahend" is null

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/mmmvvvppp/workspaces/optapy_crash/main.py", line 52, in <module>
    main()
  File "/Users/mmmvvvppp/workspaces/optapy_crash/main.py", line 46, in main
    solution = solve_tool(solution)
  File "/Users/mmmvvvppp/workspaces/optapy_crash/main.py", line 22, in solve_tool
    solution = solver.solve(problem)
  File "/Users/mmmvvvppp/workspaces/optapy_crash/venv/lib/python3.10/site-packages/optapy/optaplanner_api_wrappers.py", line 391, in solve
    raise RuntimeError(error_message) from e
RuntimeError: An error occurred during solving. This can occur when functions take the wrong number of parameters (ex: a setter that does not take exactly one parameter) or by a function returning an incompatible return type (ex: returning a str in a filter, which expects a bool). This can also occur when an exception is raised when evaluating constraints/getters/setters.

Minimal example builds on #154 but hardcodes two of the PlanningEntities to be pinned based on the planning_id
https://github.com/mmmvvvppp/optapy166

Also note that my more complex local version does not seem to report the NullPointerException, but does yield the supremely broad "RuntimeError", so it's possible I've not completely captured the issue I'm seeing locally.

Also note that this issue appears to be present from 8.23.0a0 onwards.

I looked at your example, it not a bug, but you fed OptaPy (and thus OptaPlanner) an invalid model: you pinned two non-nullable entities to None, meaning Local Search cannot start (as Local Search requires all entities to be initialized). If you make the planning variable nullable, the issue disappears. The issue also disappears if you keep the entities not nullable and assign them the NullTool:

  tn1g = ToolNeed("A", get_glues(), "job1glues", 1, 2, selected_tool=NullTool())
  tn1l = ToolNeed("B", get_locks(), "job1locks", 1, 2, selected_tool=NullTool())

That being said, the error message could be better.

Thanks for the reply Christopher. I'll need to go back and investigate what's happening on my end then. I'm not pinning a nulled planning variable as far as I know. I would certainly appreciate more descriptive errors being passed from OptaPlanner as I'm often completely clueless as to the root cause with the above error message.

Unfortunately, jpype-project/jpype#1047 prevents this, since the cause of an exception is lost when transferring from Java to CPython (and depending on where the exception occurred, it might be wrapped).

Hi Chris, I'm going to close this issue for now. I was unable to reproduce the error with the simplified implementation, but I did fix it on my end with a more complex implementation. I think the issue was that the call to solve the @planning_solution was being executed in a secondary thread. I re-architected my solution to call .solve(problem) from the main thread of the application and that seemed to resolve the issue. I wish I was able to reproduce, but I'll update this issue if I'm able to at some point in the future.