计划任务的开始时间晚于结束时间

问题描述 投票:0回答:1

我正在通过 optaPlanner(版本 8.9.1.final)为 162 个生产任务制定时间计划。我的计划希望这些任务在一些不同的生产设备上执行,并在一个月内执行(12/01/2023 和 12/31/2023 之间),这是我的 Java 代码:

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.common.util.oConvertUtils;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.lookup.PlanningId;
import org.optaplanner.core.api.domain.variable.PlanningVariable;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@PlanningEntity
@Data
@EqualsAndHashCode(of = {"id"})
@TableName("produce_order_task")
public class ProduceOrderTask implements Serializable {

    private static final long serialVersionUID = -480523240175919145L;

    @PlanningId
    @TableId(type = IdType.ASSIGN_ID)
    private String id;

    @PlanningVariable(valueRangeProviderRefs = "allEquipments")
    private ProduceEquipment produceEquipment;

    @PlanningVariable(valueRangeProviderRefs = "taskTimeRange")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime startDate;

    @PlanningVariable(valueRangeProviderRefs = "taskTimeRange")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime endDate;

    @PlanningVariable(valueRangeProviderRefs = "allWorkCenters")
    private ProduceEmployee produceEmployee;
    
    private String taskName;

}
import org.apache.commons.lang3.StringUtils;
import org.jeecg.modules.produce.planning.domain.*;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.optaplanner.core.api.score.stream.Constraint;
import org.optaplanner.core.api.score.stream.ConstraintCollectors;
import org.optaplanner.core.api.score.stream.ConstraintFactory;
import org.optaplanner.core.api.score.stream.ConstraintProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import static org.optaplanner.core.api.score.stream.Joiners.equal;
import static org.optaplanner.core.api.score.stream.Joiners.filtering;

@Component
public class ProduceConstraintProvider implements ConstraintProvider {

    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{
                mismatchEquipmentSkill(constraintFactory),
                taskStartTimeNotBeforeEndTime(constraintFactory)
        };
    }

    /**
     * A produce task can only execute on a produce equipment whose name contains this task name.
     *
     * @param constraintFactory ConstraintFactory instance
     * @return A Constraint that penalize a solution when a produce task executes on a produce equipment whose name does NOT contains this task name.
     */
    protected Constraint mismatchEquipmentSkill(ConstraintFactory constraintFactory) {
        return constraintFactory
                .from(ProduceOrderTask.class)
                .join(ProduceEquipment.class, equal(ProduceOrderTask::getEquipId, ProduceEquipment::getId))
                .filter((task, equipment) -> !equipment.getSkill().contains(task.getTaskName()))
                .penalize("mismatchEquipmentSkill", HardSoftScore.ofHard(10));
    }

    /**
     * A produce task's start date must be before its end date.
     *
     * @param constraintFactory ConstraintFactory instance
     * @return A Constraint that penalize a solution when a produce task's start date is NOT before its end date.
     */
    protected Constraint taskStartTimeNotBeforeEndTime(ConstraintFactory constraintFactory) {
        return constraintFactory
                .from(ProduceOrderTask.class)
                .filter(task ->
                        task.getStartDate() != null
                        && task.getEndDate() != null
                        && !task.getStartDate().isBefore(task.getEndDate()))
                .penalize("taskStartTimeNotBeforeEndTime", HardSoftScore.ofHard(1000));
    }
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
import org.optaplanner.core.api.domain.solution.PlanningScore;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty;
import org.optaplanner.core.api.domain.valuerange.CountableValueRange;
import org.optaplanner.core.api.domain.valuerange.ValueRangeFactory;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.optaplanner.core.api.solver.SolverStatus;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

@Slf4j
@EqualsAndHashCode(of = {"id"})
@NoArgsConstructor
@AllArgsConstructor
@PlanningSolution
@Data
public class ProducePlanningSolution implements Serializable {

    private static final long serialVersionUID = 3257608858882617194L;

    private String id;

    private LocalDateTime producePlanningStartTime;

    private LocalDateTime producePlanningEndTime;

    @ValueRangeProvider(id = "allEquipments")
    @ProblemFactCollectionProperty
    private List<ProduceEquipment> produceEquipments;

    @ValueRangeProvider(id = "taskTimeRange")
    public CountableValueRange<LocalDateTime> getTaskTimeRange() {
        return ValueRangeFactory.createLocalDateTimeValueRange(
                LocalDateTime.parse(""2023-12-01T08:00:00), LocalDateTime.parse("2023-12-31T23:59:59"), 1, ChronoUnit.Hours);
    }

    @PlanningEntityCollectionProperty
    private List<ProduceOrderTask> produceOrderTasks;

    @PlanningScore
    private HardSoftScore hardSoftScore;
}

但是我失败了。 optaplanner完成后,在最佳解决方案中,我发现有7个生产任务,其开始日期晚于结束日期。我很困惑,谁能帮助我?

我尝试更改 optaplanner.solver.termination.spent-limit 和 optaplanner.solver.termination.spent-limit.unimproved-spent-limit 以获得更好的解决方案,但它没有用。我想知道为什么这7个生产任务的开始日期和结束日期总是错误的,我想知道如何得到正确的解决方案?

time optaplanner planning
1个回答
0
投票
  1. 您的约束是否按照您的想法行事?为每一个编写一个单元测试。请参阅 timefold-quickstarts 存储库中的操作方法。
  2. 确实有更好的解决方案吗?要求它在非常小的数据集上运行暴力破解。如果有的话,它会找到它。
  3. 是否存在分数损坏的情况?使用环境模式 FULL_ASSERT 临时运行一次(这会减慢解决问题的速度,不要提交)。
© www.soinside.com 2019 - 2024. All rights reserved.