【问题标题】:OptaPlanner returning empty solutionOptaPlanner 返回空解决方案
【发布时间】:2020-06-06 23:56:51
【问题描述】:

我正在尝试使用 OptaPlanner 解决问题,但程序返回给我并且解决方案为空。我已经按照这个例子来解决它:https://github.com/ge0ffrey/getting-started-guides/tree/gs-constraint-solving-ai-optaplanner/complete

我正在使用 SpringBoot JPA 集成。

这里有实现的代码:

  • 规划解决方案
@PlanningSolution
public class HorarioComidas {
    @ValueRangeProvider(id = "recetaRange")
    @ProblemFactCollectionProperty
    private List<Receta> recetaList;

    @ValueRangeProvider(id = "fechaSemanaRange")
    @ProblemFactCollectionProperty
    private List<FechaSemana> fechaSemanaList;

    @ValueRangeProvider(id = "comidaRange")
    @ProblemFactCollectionProperty
    private List<Comida> comidaList;

    @PlanningEntityCollectionProperty
    private List<UsuarioReceta> usuarioRecetas;

    @PlanningScore
    private HardSoftScore score;

    // Ignored by OptaPlanner, used by the UI to display solve or stop solving button
    private SolverStatus solverStatus;
...
}

  • OptaPlanner 服务
@Service
public class OptaPlannerService {
    @Autowired
    private HorarioComidasService horarioComidasService;
    @Autowired
    private SolverManager<HorarioComidas, Usuario> solverManager;
    @Autowired
    private ScoreManager<HorarioComidas> scoreManager;

    public HorarioComidas getTimeTable(Usuario usuario) {
        // Get the solver status before loading the solution
        // to avoid the race condition that the solver terminates between them
        SolverStatus solverStatus = getSolverStatus(usuario);
        HorarioComidas solution = horarioComidasService.findByUsuario(usuario);
        scoreManager.updateScore(solution); // Sets the score
        solution.setSolverStatus(solverStatus);
        return solution;
    }

    public void solve(Usuario usuario) {
        horarioComidasService.usuario = usuario;
        solverManager.solveAndListen(usuario, 
            horarioComidasService::findByUsuario, 
            horarioComidasService::save);
    }

    public SolverStatus getSolverStatus(Usuario usuario) {
        return solverManager.getSolverStatus(usuario);
    }

    public void stopSolving(Usuario usuario) {
        solverManager.terminateEarly(usuario);
    }
}
  • HorarioComidaService:

@Service
public class HorarioComidasService {
    @Autowired
    private UsuarioRecetaService usuarioRecetaService;
    @Autowired
    private RecetaService recetaService;
    public Usuario usuario;

    public HorarioComidas findByUsuario(Usuario usuario) {
        if (!usuarioRecetaService.findByUsuario(usuario).isEmpty()) {
            throw new IllegalStateException("No hay una lista de comida para este usuario.");
        }
        // Occurs in a single transaction, so each initialized lesson references the same timeslot/room instance
        // that is contained by the timeTable's timeslotList/roomList.
        return new HorarioComidas(recetaService.findAll(), usuarioRecetaService.findByUsuario(usuario), Arrays.asList(FechaSemana.values()), Arrays.asList(Comida.values()));
    }

    public void save(HorarioComidas horarioComidas) {
        for (UsuarioReceta usuarioReceta : horarioComidas.getUsuarioRecetas()) {
            usuarioReceta.setUsuario(usuario);
            usuarioRecetaService.create(usuarioReceta);
        }
    }
}

  • 调用 OptaPlanner 服务的函数:
    public void generarListaCompra(Usuario usuario) throws InterruptedException {
        optaPlannerService.solve(usuario);
        HorarioComidas horarioComidas = optaPlannerService.getTimeTable(usuario);
        while (horarioComidas.getSolverStatus() != SolverStatus.NOT_SOLVING) {
            // Quick polling (not a Test Thread Sleep anti-pattern)
            // Test is still fast on fast machines and doesn't randomly fail on slow machines.
            Thread.sleep(20L);
            horarioComidas = optaPlannerService.getTimeTable(usuario);
        }
    }
  • 约束提供者,但目前没有限制:
public class HorarioComidasConstraintProvider implements ConstraintProvider {
    @Autowired
    private IntoleranciaUsuarioService intoleranciaUsuarioService;
    @Autowired
    private IntoleranciaRecetaService intoleranciaRecetaService;

    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{};
    }
}
  • 控制台返回的内容:
    2020-06-04 14:12:42.186  INFO 10130 --- [  restartedMain] .ConditionEvaluationDeltaLoggingListener : 
Condition evaluation unchanged
    2020-06-04 14:21:37.238  INFO 10130 --- [pool-5-thread-1] o.o.core.impl.solver.DefaultSolver       : 
Solving started: time spent (3), best score (0hard/0soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
    2020-06-04 14:21:37.239  INFO 10130 --- [pool-5-thread-1] o.o.core.impl.solver.DefaultSolver       : Skipped all phases (2): out of 0 planning entities, none are movable (non-pinned).
    2020-06-04 14:21:37.239  INFO 10130 --- [pool-5-thread-1] o.o.core.impl.solver.DefaultSolver       : Solving ended: time spent (4), best score (0hard/0soft), score calculation speed (250/sec), phase total (2), environment mode (REPRODUCIBLE).

【问题讨论】:

  • horarioComidasService::save 方法中放置一个断点。那里的解决方案参数是空的吗?如果是这样,请在您的 horarioComidasService::findByUsuario 方法中放置一个断点,那里返回的解决方案是空的吗?
  • 我不明白为什么函数不调用 horarioComidasService::save 方法。我添加了一个名为 horarioComidaService 的新类,但我仍然遇到同样的问题。
  • 在输入和输出方法中设置断点,检查解决方案的目的是确认 optaplanner 确实做错了你认为它做错的事情。通常问题出在输入之前或输出之后的数据处理中,与 SolverManager 的工作无关。
  • 目前,我不知道我能做什么,我对此非常困惑,我不知道如何解决这个问题。我一直在关注这个例子,但我现在不知道该怎么做。
  • 调试时如何设置java断点:jetbrains.com/help/idea/using-breakpoints.html#

标签: java spring-data-jpa optaplanner


【解决方案1】:

我想最好添加一个简单的约束(奖励/惩罚)以允许求解器计算分数,这将有助于它猜测是否会有变化,请您更新您的帖子在解决之前和之后使用来自您的@PlanningSolution / Planning 实体(在您的情况下为 PlanningEntityCollectionProperty)的一些日志?这也有助于记录分数。

PS:在保存之前尝试覆盖“HorarioComidasService::save”以记录。

【讨论】:

  • 我有,但因为我有同样的问题,我删除了,所以我无条件尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
  • 2022-07-22
相关资源
最近更新 更多