├── README.md ├── doc └── demo1 ├── .gitignore ├── src └── main │ ├── resources │ ├── taskassignmentConfiguration.xml │ └── taskAssignmentDools.drl │ └── java │ └── com │ └── zhl │ └── aps │ └── optaplanner │ ├── Machine.java │ ├── AbstractPersistable.java │ ├── Task.java │ ├── TaskAssignment.java │ └── App.java └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | # aps 2 | -------------------------------------------------------------------------------- /doc/demo1: -------------------------------------------------------------------------------- 1 | 1、条件: 2 | 按照工单、产品、设备(切换产品间隔)、员工、当日工作日历 进行生产 3 | 2、目标: 4 | (最常见)总工单按时交付率最大 5 | (其他)单设备切换产品的频率最小(需要考虑单台设备切产品时存在3-5小时的间隔,该间隔属于设备属性) 6 | 3、环境: 7 | 单产品多步骤生产 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | *.war 5 | *.zip 6 | *.tar 7 | *.tar.gz 8 | 9 | # eclipse ignore 10 | .settings/ 11 | .project 12 | .classpath 13 | 14 | # idea ignore 15 | .idea/ 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # temp ignore 21 | *.log 22 | *.cache 23 | *.diff 24 | *.patch 25 | *.tmp 26 | *.java~ 27 | *.properties~ 28 | *.xml~ 29 | 30 | # system ignore 31 | .DS_Store 32 | Thumbs.db 33 | 34 | .metadata 35 | *.orig 36 | 37 | # web sources 38 | src/main/webapp/view/ 39 | 40 | ## commitlint 41 | node_modules/ 42 | package-lock.json -------------------------------------------------------------------------------- /src/main/resources/taskassignmentConfiguration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.zhl.aps.optaplanner.TaskAssignment 6 | com.zhl.aps.optaplanner.Task 7 | 8 | 9 | 10 | 11 | taskAssignmentDools.drl 12 | 13 | 14 | 15 | 16 | 10 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/resources/taskAssignmentDools.drl: -------------------------------------------------------------------------------- 1 | package com.zhl.aps.optaplanner; 2 | 3 | import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder; 4 | import com.zhl.aps.optaplanner.Task; 5 | import com.zhl.aps.optaplanner.Machine; 6 | import com.zhl.aps.optaplanner.TaskAssignment; 7 | 8 | global HardSoftScoreHolder scoreHolder; 9 | 10 | rule "yarnTypeMatch" 11 | when 12 | Task(machine != null, machine.yarnType != requiredYarnType) 13 | then 14 | scoreHolder.addHardConstraintMatch(kcontext, -10000); 15 | end 16 | 17 | rule "machineCapacity" 18 | when 19 | $machine : Machine($capacity : capacity) 20 | accumulate( 21 | Task( 22 | machine == $machine, 23 | $amount : amount); 24 | $amountTotal : sum($amount); 25 | $amountTotal > $capacity 26 | ) 27 | then 28 | scoreHolder.addHardConstraintMatch(kcontext, $capacity - $amountTotal); 29 | end 30 | 31 | rule "machineCost_used" 32 | when 33 | $machine : Machine($cost : cost) 34 | exists Task(machine == $machine) 35 | then 36 | scoreHolder.addSoftConstraintMatch(kcontext, -$cost); 37 | end -------------------------------------------------------------------------------- /src/main/java/com/zhl/aps/optaplanner/Machine.java: -------------------------------------------------------------------------------- 1 | package com.zhl.aps.optaplanner; 2 | 3 | /** 4 | * @program aps 5 | * @description:表示机台的实体类,它属于ProblemFact,在其中保存了在规划过程中会用到的属性,

6 | * 此类反映一个机台相关信息的属性:taskType-可处理的任务类型;capacity-当前机台的产能;cost-当前机台的成本 7 | * @author: meilong 8 | * @create: 2019/09/20 15:00 9 | */ 10 | public class Machine extends AbstractPersistable { 11 | 12 | private String yarnType; 13 | 14 | private Integer capacity; 15 | 16 | private Integer cost; 17 | 18 | public Machine(Long id, String yarnType, Integer capacity, Integer cost) { 19 | super(id); 20 | this.yarnType = yarnType; 21 | this.capacity = capacity; 22 | this.cost = cost; 23 | } 24 | 25 | public String getYarnType() { 26 | return yarnType; 27 | } 28 | 29 | public void setYarnType(String yarnType) { 30 | this.yarnType = yarnType; 31 | } 32 | 33 | public Integer getCapacity() { 34 | return capacity; 35 | } 36 | 37 | public void setCapacity(Integer capacity) { 38 | this.capacity = capacity; 39 | } 40 | 41 | public Integer getCost() { 42 | return cost; 43 | } 44 | 45 | public void setCost(Integer cost) { 46 | this.cost = cost; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/zhl/aps/optaplanner/AbstractPersistable.java: -------------------------------------------------------------------------------- 1 | package com.zhl.aps.optaplanner; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.apache.commons.lang3.builder.CompareToBuilder; 6 | import org.optaplanner.core.api.domain.lookup.PlanningId; 7 | 8 | /** 9 | * @program aps 10 | * @description:负责维护ID属性,对实体类的compareTo方法,toString方法进行重载 11 | * @author: meilong 12 | * @create: 2019/09/20 14:47 13 | */ 14 | public class AbstractPersistable implements Serializable, Comparable { 15 | 16 | protected Long id; 17 | 18 | protected AbstractPersistable() { 19 | } 20 | 21 | protected AbstractPersistable(Long id) { 22 | this.id = id; 23 | } 24 | 25 | @PlanningId 26 | public Long getId() { 27 | return id; 28 | } 29 | 30 | public void setId(Long id) { 31 | this.id = id; 32 | } 33 | 34 | @Override 35 | public int compareTo(AbstractPersistable other) { 36 | return new CompareToBuilder() 37 | .append(getClass().getName(), other.getClass().getName()) 38 | .append(id, other.id) 39 | .toComparison(); 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return getClass().getName().replaceAll(".*\\.", "") + "-" + id; 45 | } 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/main/java/com/zhl/aps/optaplanner/Task.java: -------------------------------------------------------------------------------- 1 | package com.zhl.aps.optaplanner; 2 | 3 | import org.optaplanner.core.api.domain.entity.PlanningEntity; 4 | import org.optaplanner.core.api.domain.variable.PlanningVariable; 5 | 6 | /** 7 | * @program aps 8 | * @description:Task,表示任务的实体类,它被注解为@PlanningEntity,它有三个属性:taskType-当前任务的类型;quantity-生产量;machine-任务将要被分配的机台.

9 | * 其中machine属性被注解为@PlanningVariable,表示规划过程中,这个属性的值将被plan的,即通过调整这个属性来得到不同的方案。 10 | * 另外,作为一个Planning Entity,它必须有一个ID属性,用于在规划运行过程中识别不同的对象,这个ID属性被注解为@PlanningId。 11 | * 本例中所有实体类都继承了一个通用的类 - AbstractPersistable,该父类负责维护此所有对象的ID。 12 | * Task类也继承于它,因此,将该类的ID属性注解为@PlanningId即可。另外作为Planning Entity,它必须有一无参构造函数,若你在此类实现了有参构造的话, 13 | * 需要显示地实现一个无参构造函数。 14 | * @author: meilong 15 | * @create: 2019/09/20 14:42 16 | */ 17 | @PlanningEntity 18 | public class Task extends AbstractPersistable { 19 | 20 | private String requiredYarnType; 21 | 22 | private Integer amount; 23 | 24 | private Machine machine; 25 | 26 | public Task() { 27 | } 28 | 29 | public Task(Long id, String requiredYarnType, Integer amount) { 30 | super(id); 31 | this.requiredYarnType = requiredYarnType; 32 | this.amount = amount; 33 | } 34 | 35 | public String getRequiredYarnType() { 36 | return requiredYarnType; 37 | } 38 | 39 | public void setRequiredYarnType(String requiredYarnType) { 40 | this.requiredYarnType = requiredYarnType; 41 | } 42 | 43 | public int getAmount() { 44 | return amount; 45 | } 46 | 47 | public void setAmount(int amount) { 48 | this.amount = amount; 49 | } 50 | 51 | @PlanningVariable(valueRangeProviderRefs = {"machineRange"}) 52 | public Machine getMachine() { 53 | return machine; 54 | } 55 | 56 | public void setMachine(Machine machine) { 57 | this.machine = machine; 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/com/zhl/aps/optaplanner/TaskAssignment.java: -------------------------------------------------------------------------------- 1 | package com.zhl.aps.optaplanner; 2 | 3 | import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty; 4 | import org.optaplanner.core.api.domain.solution.PlanningScore; 5 | import org.optaplanner.core.api.domain.solution.PlanningSolution; 6 | import org.optaplanner.core.api.domain.solution.drools.ProblemFactCollectionProperty; 7 | import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider; 8 | import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @program aps 14 | * @description:此类用来描述整个解决方案的固定类,它的结构描述了问题的各种信息,在Optaplanner术语中,在执行规划之前,它的对象被称作一个Problem,

15 | * 完成规划并获得输出之后,输出的TaskAssignment对象被称作一个Solution。它具有固定的特性要求:必须被注解为@PlanningSolution; 16 | * 本例中它至少有三个属性:machineList-机台列表,就是可以用于分配任务的机台;taskList-任务列表,这个属性需要被注解为@PlanningEntityCollectionPropery, 17 | * 还有一个是score属性,它用于在规划过程中对各种约束的违反情况进行打分,因为本例中存在了硬约束与软约束,因此我们使用的score为hardSoftScore。 18 | * @author: meilong 19 | * @create: 2019/09/20 15:16 20 | */ 21 | @PlanningSolution 22 | public class TaskAssignment extends AbstractPersistable { 23 | 24 | private HardSoftScore score; 25 | 26 | private List machineList; 27 | 28 | private List taskList; 29 | 30 | public TaskAssignment() { 31 | } 32 | 33 | public TaskAssignment(List machineList, List taskList) { 34 | //super(0); 35 | this.machineList = machineList; 36 | this.taskList = taskList; 37 | } 38 | 39 | @PlanningScore 40 | public HardSoftScore getScore() { 41 | return score; 42 | } 43 | 44 | public void setScore(HardSoftScore score) { 45 | this.score = score; 46 | } 47 | 48 | @ProblemFactCollectionProperty 49 | @ValueRangeProvider(id = "machineRange") 50 | public List getMachineList() { 51 | return machineList; 52 | } 53 | 54 | public void setMachineList(List machineList) { 55 | this.machineList = machineList; 56 | } 57 | 58 | @PlanningEntityCollectionProperty 59 | @ValueRangeProvider(id = "taskRange") 60 | public List getTaskList() { 61 | return taskList; 62 | } 63 | 64 | public void setTaskList(List taskList) { 65 | this.taskList = taskList; 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | org.optaplanner 7 | optaplanner 8 | 7.8.0.Final 9 | 10 | 11 | 4.0.0 12 | 13 | com.zhl 14 | aps 15 | jar 16 | 1.0-SNAPSHOT 17 | 18 | aps 19 | 20 | 21 | 1.8 22 | UTF-8 23 | UTF-8 24 | 25 | 26 | 27 | 28 | org.optaplanner 29 | optaplanner-core 30 | 31 | 32 | org.kie 33 | kie-api 34 | 35 | 36 | com.thoughtworks.xstream 37 | xstream 38 | 39 | 40 | ch.qos.logback 41 | logback-classic 42 | runtime 43 | 44 | 45 | 46 | 47 | install 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | 3.8.0 53 | 54 | ${java.version} 55 | ${java.version} 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-resources-plugin 61 | 3.1.0 62 | 63 | ${project.build.sourceEncoding} 64 | 65 | 66 | 67 | 68 | 69 | org.codehaus.mojo 70 | exec-maven-plugin 71 | 1.6.0 72 | 73 | false 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/main/java/com/zhl/aps/optaplanner/App.java: -------------------------------------------------------------------------------- 1 | package com.zhl.aps.optaplanner; 2 | 3 | import org.optaplanner.core.api.solver.Solver; 4 | import org.optaplanner.core.api.solver.SolverFactory; 5 | 6 | import java.io.InputStream; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * @program aps 13 | * @description: 14 | * @author: meilong 15 | * @create: 2019/09/20 15:36 16 | */ 17 | public class App { 18 | 19 | public static void main(String[] args) { 20 | startPlan(); 21 | } 22 | 23 | private static void startPlan() { 24 | List machines = getMachines(); 25 | List tasks = getTasks(); 26 | 27 | InputStream ins = App.class.getResourceAsStream("/taskassignmentConfiguration.xml"); 28 | SolverFactory solverFactory = SolverFactory.createFromXmlInputStream(ins); 29 | Solver solver = solverFactory.buildSolver(); 30 | TaskAssignment unAssignment = new TaskAssignment(machines, tasks); 31 | 32 | // 启动引擎 33 | TaskAssignment assigned = solver.solve(unAssignment); 34 | 35 | List machinesAssigned = assigned.getTaskList().stream().map(Task::getMachine).distinct().collect(Collectors.toList()); 36 | for (Machine machine : machinesAssigned) { 37 | System.out.println("\n" + machine + ":"); 38 | List tasksInMachine = assigned.getTaskList().stream().filter(x -> x.getMachine().equals(machine)).collect(Collectors.toList()); 39 | for (Task task : tasksInMachine) { 40 | System.out.println("->" + task); 41 | } 42 | } 43 | } 44 | 45 | private static List getMachines() { 46 | // 六个机台 47 | Machine m1 = new Machine(1L, "Type_A", 300, 100); 48 | Machine m2 = new Machine(2L, "Type_A", 1000, 100); 49 | Machine m3 = new Machine(3L, "TYPE_B", 1000, 300); 50 | Machine m4 = new Machine(4L, "TYPE_B", 1000, 100); 51 | Machine m5 = new Machine(5L, "Type_C", 1100, 100); 52 | Machine m6 = new Machine(6L, "Type_D", 900, 100); 53 | 54 | List machines = new ArrayList<>(); 55 | machines.add(m1); 56 | machines.add(m2); 57 | machines.add(m3); 58 | machines.add(m4); 59 | machines.add(m5); 60 | machines.add(m6); 61 | 62 | return machines; 63 | } 64 | 65 | private static List getTasks() { 66 | // 10个任务 67 | Task t1 = new Task(1L, "Type_A", 100); 68 | Task t2 = new Task(2L, "Type_A", 100); 69 | Task t3 = new Task(3L, "Type_A", 100); 70 | Task t4 = new Task(4L, "Type_A", 100); 71 | Task t5 = new Task(5L, "TYPE_B", 800); 72 | Task t6 = new Task(6L, "TYPE_B", 500); 73 | Task t7 = new Task(7L, "Type_C", 800); 74 | Task t8 = new Task(8L, "Type_C", 300); 75 | Task t9 = new Task(9L, "Type_D", 400); 76 | Task t10 = new Task(10L, "Type_D", 500); 77 | 78 | List tasks = new ArrayList(); 79 | tasks.add(t1); 80 | tasks.add(t2); 81 | tasks.add(t3); 82 | tasks.add(t4); 83 | tasks.add(t5); 84 | tasks.add(t6); 85 | tasks.add(t7); 86 | tasks.add(t8); 87 | tasks.add(t9); 88 | tasks.add(t10); 89 | 90 | return tasks; 91 | } 92 | } 93 | --------------------------------------------------------------------------------