Interface SolverManager<Solution_,ProblemId_>

Type Parameters:
Solution_ - the solution type, the class with the PlanningSolution annotation
ProblemId_ - the ID type of a submitted problem, such as Long or UUID.
All Superinterfaces:
AutoCloseable
All Known Implementing Classes:
DefaultSolverManager

public interface SolverManager<Solution_,ProblemId_> extends AutoCloseable
A SolverManager solves multiple planning problems of the same domain, asynchronously without blocking the calling thread.

To create a SolverManager, use create(SolverFactory, SolverManagerConfig). To solve a planning problem, call solve(Object, Function, Consumer) or solveAndListen(Object, Function, Consumer).

These methods are thread-safe unless explicitly stated otherwise.

Internally a SolverManager manages a thread pool of solver threads (which call Solver.solve(Object)) and consumer threads (to handle the BestSolutionChangedEvents).

To learn more about problem change semantics, please refer to the ProblemChange Javadoc.

  • Method Details

    • create

      static <Solution_, ProblemId_> SolverManager<Solution_,ProblemId_> create(SolverConfig solverConfig)
      Use a SolverConfig to build a SolverManager.

      When using ScoreManager too, use create(SolverFactory) instead so they reuse the same SolverFactory instance.

      Type Parameters:
      Solution_ - the solution type, the class with the PlanningSolution annotation
      ProblemId_ - the ID type of a submitted problem, such as Long or UUID
      Parameters:
      solverConfig - never null
      Returns:
      never null
    • create

      static <Solution_, ProblemId_> SolverManager<Solution_,ProblemId_> create(SolverConfig solverConfig, SolverManagerConfig solverManagerConfig)
      Use a SolverConfig and a SolverManagerConfig to build a SolverManager.

      When using ScoreManager too, use create(SolverFactory, SolverManagerConfig) instead so they reuse the same SolverFactory instance.

      Type Parameters:
      Solution_ - the solution type, the class with the PlanningSolution annotation
      ProblemId_ - the ID type of a submitted problem, such as Long or UUID.
      Parameters:
      solverConfig - never null
      solverManagerConfig - never null
      Returns:
      never null
    • create

      static <Solution_, ProblemId_> SolverManager<Solution_,ProblemId_> create(SolverFactory<Solution_> solverFactory)
      Use a SolverFactory to build a SolverManager.
      Type Parameters:
      Solution_ - the solution type, the class with the PlanningSolution annotation
      ProblemId_ - the ID type of a submitted problem, such as Long or UUID
      Parameters:
      solverFactory - never null
      Returns:
      never null
    • create

      static <Solution_, ProblemId_> SolverManager<Solution_,ProblemId_> create(SolverFactory<Solution_> solverFactory, SolverManagerConfig solverManagerConfig)
      Type Parameters:
      Solution_ - the solution type, the class with the PlanningSolution annotation
      ProblemId_ - the ID type of a submitted problem, such as Long or UUID.
      Parameters:
      solverFactory - never null
      solverManagerConfig - never null
      Returns:
      never null
    • solve

      default SolverJob<Solution_,ProblemId_> solve(ProblemId_ problemId, Solution_ problem)
      Submits a planning problem to solve and returns immediately. The planning problem is solved on a solver Thread, as soon as one is available. To retrieve the final best solution, use SolverJob.getFinalBestSolution().

      In server applications, it's recommended to use solve(Object, Function, Consumer) instead, to avoid loading the problem going stale if solving can't start immediately. To listen to intermediate best solutions too, use solveAndListen(Object, Function, Consumer) instead.

      Defaults to logging exceptions as an error.

      To stop a solver job before it naturally terminates, call SolverJob.terminateEarly().

      Parameters:
      problemId - never null, a ID for each planning problem. This must be unique. Use this problemId to terminate the solver early,
      problem - never null, a PlanningSolution usually with uninitialized planning variables
      Returns:
      never null
    • solve

      default SolverJob<Solution_,ProblemId_> solve(ProblemId_ problemId, Solution_ problem, Consumer<? super Solution_> finalBestSolutionConsumer)
      As defined by solve(Object, Object).
      Parameters:
      problemId - never null, a ID for each planning problem. This must be unique. Use this problemId to terminate the solver early, to get the status or if the problem changes while solving.
      problem - never null, a PlanningSolution usually with uninitialized planning variables
      finalBestSolutionConsumer - sometimes null, called only once, at the end, on a consumer thread
      Returns:
      never null
    • solve

      default SolverJob<Solution_,ProblemId_> solve(ProblemId_ problemId, Solution_ problem, Consumer<? super Solution_> finalBestSolutionConsumer, BiConsumer<? super ProblemId_,? super Throwable> exceptionHandler)
      As defined by solve(Object, Object).
      Parameters:
      problemId - never null, a ID for each planning problem. This must be unique. Use this problemId to terminate the solver early, to get the status or if the problem changes while solving.
      problem - never null, a PlanningSolution usually with uninitialized planning variables
      finalBestSolutionConsumer - sometimes null, called only once, at the end, on a consumer thread
      exceptionHandler - sometimes null, called if an exception or error occurs. If null it defaults to logging the exception as an error.
      Returns:
      never null
    • solve

      default SolverJob<Solution_,ProblemId_> solve(ProblemId_ problemId, Function<? super ProblemId_,? extends Solution_> problemFinder, Consumer<? super Solution_> finalBestSolutionConsumer)
      Submits a planning problem to solve and returns immediately. The planning problem is solved on a solver Thread, as soon as one is available.

      When the solver terminates, the finalBestSolutionConsumer is called once with the final best solution, on a consumer Thread, as soon as one is available. To listen to intermediate best solutions too, use solveAndListen(Object, Function, Consumer) instead.

      Defaults to logging exceptions as an error.

      To stop a solver job before it naturally terminates, call terminateEarly(Object).

      Parameters:
      problemId - never null, a ID for each planning problem. This must be unique. Use this problemId to terminate the solver early, to get the status or if the problem changes while solving.
      problemFinder - never null, a function that returns a PlanningSolution, usually with uninitialized planning variables
      finalBestSolutionConsumer - sometimes null, called only once, at the end, on a consumer thread
      Returns:
      never null
    • solve

      SolverJob<Solution_,ProblemId_> solve(ProblemId_ problemId, Function<? super ProblemId_,? extends Solution_> problemFinder, Consumer<? super Solution_> finalBestSolutionConsumer, BiConsumer<? super ProblemId_,? super Throwable> exceptionHandler)
      Parameters:
      problemId - never null, a ID for each planning problem. This must be unique. Use this problemId to terminate the solver early, to get the status or if the problem changes while solving.
      problemFinder - never null, function that returns a PlanningSolution, usually with uninitialized planning variables
      finalBestSolutionConsumer - sometimes null, called only once, at the end, on a consumer thread
      exceptionHandler - sometimes null, called if an exception or error occurs. If null it defaults to logging the exception as an error.
      Returns:
      never null
    • solveAndListen

      default SolverJob<Solution_,ProblemId_> solveAndListen(ProblemId_ problemId, Function<? super ProblemId_,? extends Solution_> problemFinder, Consumer<? super Solution_> bestSolutionConsumer)
      Submits a planning problem to solve and returns immediately. The planning problem is solved on a solver Thread, as soon as one is available.

      When the solver finds a new best solution, the bestSolutionConsumer is called every time, on a consumer Thread, as soon as one is available (taking into account any throttling waiting time), unless a newer best solution is already available by then (in which case skip ahead discards it).

      Defaults to logging exceptions as an error.

      To stop a solver job before it naturally terminates, call terminateEarly(Object).

      Parameters:
      problemId - never null, a ID for each planning problem. This must be unique. Use this problemId to terminate the solver early, to get the status or if the problem changes while solving.
      problemFinder - never null, a function that returns a PlanningSolution, usually with uninitialized planning variables
      bestSolutionConsumer - never null, called multiple times, on a consumer thread
      Returns:
      never null
    • solveAndListen

      default SolverJob<Solution_,ProblemId_> solveAndListen(ProblemId_ problemId, Function<? super ProblemId_,? extends Solution_> problemFinder, Consumer<? super Solution_> bestSolutionConsumer, BiConsumer<? super ProblemId_,? super Throwable> exceptionHandler)
      Parameters:
      problemId - never null, a ID for each planning problem. This must be unique. Use this problemId to terminate the solver early, to get the status or if the problem changes while solving.
      problemFinder - never null, function that returns a PlanningSolution, usually with uninitialized planning variables
      bestSolutionConsumer - never null, called multiple times, on a consumer thread
      exceptionHandler - sometimes null, called if an exception or error occurs. If null it defaults to logging the exception as an error.
      Returns:
      never null
    • solveAndListen

      SolverJob<Solution_,ProblemId_> solveAndListen(ProblemId_ problemId, Function<? super ProblemId_,? extends Solution_> problemFinder, Consumer<? super Solution_> bestSolutionConsumer, Consumer<? super Solution_> finalBestSolutionConsumer, BiConsumer<? super ProblemId_,? super Throwable> exceptionHandler)
      As defined by solveAndListen(Object, Function, Consumer).

      The final best solution is delivered twice: first to the bestSolutionConsumer when it is found and then again to the finalBestSolutionConsumer when the solver terminates. Do not store the solution twice. This allows for use cases that only process the Score first (during best solution changed events) and then store the solution upon termination.

      Parameters:
      problemId - never null, an ID for each planning problem. This must be unique. Use this problemId to terminate the solver early, to get the status or if the problem changes while solving.
      problemFinder - never null, function that returns a PlanningSolution, usually with uninitialized planning variables
      bestSolutionConsumer - never null, called multiple times, on a consumer thread
      finalBestSolutionConsumer - sometimes null, called only once, at the end, on a consumer thread. That final best solution is already consumed by the bestSolutionConsumer earlier.
      exceptionHandler - sometimes null, called if an exception or error occurs. If null it defaults to logging the exception as an error.
      Returns:
      never null
    • getSolverStatus

      SolverStatus getSolverStatus(ProblemId_ problemId)
      Returns if the Solver is scheduled to solve, actively solving or not.

      Returns SolverStatus.NOT_SOLVING if the solver already terminated or if the problemId was never added. To distinguish between both cases, use SolverJob.getSolverStatus() instead. Here, that distinction is not supported because it would cause a memory leak.

      Parameters:
      problemId - never null, a value given to solve(Object, Function, Consumer) or solveAndListen(Object, Function, Consumer)
      Returns:
      never null
    • addProblemChange

      CompletableFuture<Void> addProblemChange(ProblemId_ problemId, ProblemChange<Solution_> problemChange)
      Schedules a ProblemChange to be processed by the underlying Solver and returns immediately. If the solver already terminated or the problemId was never added, throws an exception. The same applies if the underlying Solver is not in the SolverStatus.SOLVING_ACTIVE state.
      Parameters:
      problemId - never null, a value given to solve(Object, Function, Consumer) or solveAndListen(Object, Function, Consumer)
      problemChange - never null
      Returns:
      completes after the best solution containing this change has been consumed.
      Throws:
      IllegalStateException - if there is no solver actively solving the problem associated with the problemId
    • terminateEarly

      void terminateEarly(ProblemId_ problemId)
      Terminates the solver or cancels the solver job if it hasn't (re)started yet.

      Does nothing if the solver already terminated or the problemId was never added. To distinguish between both cases, use SolverJob.terminateEarly() instead. Here, that distinction is not supported because it would cause a memory leak.

      Waits for the termination or cancellation to complete before returning. During termination, a bestSolutionConsumer could still be called. When the solver terminates, the finalBestSolutionConsumer is executed with the latest best solution. These consumers run on a consumer thread independently of the termination and may still run even after this method returns.

      Parameters:
      problemId - never null, a value given to solve(Object, Function, Consumer) or solveAndListen(Object, Function, Consumer)
    • close

      void close()
      Terminates all solvers, cancels all solver jobs that haven't (re)started yet and discards all queued ProblemChanges. Releases all thread pool resources.

      No new planning problems can be submitted after calling this method.

      Specified by:
      close in interface AutoCloseable