├── 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 |
--------------------------------------------------------------------------------