APS开源源码解读: 排程工具 optaplanner
抽象层次非常好,广义优化工具。用于排产没有复杂的落地示例
- https://github.com/apache/incubator-kie-optaplanner/blob/main/optaplanner-examples/src/main/java/org/optaplanner/examples/projectjobscheduling/app/ProjectJobSchedulingApp.java
- https://github.com/eugenp/tutorials/tree/master/timefold-solver
- https://github.com/kisszhu/aps
安装
- java
- maven
配置
- xml配置
- solutionClass
- entityClass
- constraintProviderClass
- 约束设置
- termination: 5min
- constructionHeuristic: FIRST_FIT
- first fit
- localSearch:
也即是说,先定义对象“entityClass”, 转化为约束“constraintProviderClass”,然后运用 constructionHeuristic + localSearch的方式进行求解
其中,一个整体的任务叫做project, 资源有可再生,非可再生。
工序叫做Job,job跟着若干project。每个工序有自己的资源,ResourceRequirement. 执行模式Execution Mode. 分配allocation.
- resourceRequirement和allocation都要设置execution mode
- 每个工序JOb, 有自己的resourceRequirement, executation mode, allocation
基本概念
- PlanningSolution
- 定义Problem,以及解
- planning entity
- Allocation
- planing variable
- executionMode
- delay
- shadow variable
- predecessorsDoneDate
- https://www.optaplanner.org/docs/optaplanner/latest/shadow-variable/shadow-variable.html
- planning score
- 核心的优化算法
约束
比如排产中的工序依赖关系
import org.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore;
import org.timefold.solver.core.api.score.stream.ConstraintProvider;
import org.timefold.solver.core.api.score.stream.Constraint;
import org.timefold.solver.core.api.score.stream.ConstraintStream;
import org.timefold.solver.core.api.score.stream.Joiners;public class JobShopConstraintProvider implements ConstraintProvider {@Overridepublic Constraint[] defineConstraints(ConstraintFactory constraintFactory) {return new Constraint[] {// Ensure operations follow the sequence within each jobconstraintFactory.from(Operation.class).join(Operation.class, Joiners.filteringEach(otherOp -> otherOp.getJob().equals(op.getJob()) && otherOp.getSequence() == op.getSequence() + 1)).penalize("Operations must follow sequence",HardSoftScore.ONE_HARD,(op, otherOp) -> 1),// Ensure machine constraints are respectedconstraintFactory.from(Operation.class).join(Operation.class, Joiners.filteringEach((op1, op2) ->op1.getMachine().equals(op2.getMachine()) &&op1.getEndTime() > op2.getStartTime() &&op1.getStartTime() < op2.getEndTime() &&!op1.equals(op2))).penalize("Machine cannot process two operations at once",HardSoftScore.ONE_HARD,(op1, op2) -> 1)};}
}
官方示例
入口在APP的main
public static void main(String[] args) {prepareSwingEnvironment();new ProjectJobSchedulingApp().init();}
init
public void init() {init(null, true);}public void init(Component centerForComponent, boolean exitOnClose) {solutionBusiness = createSolutionBusiness();solverAndPersistenceFrame = new SolverAndPersistenceFrame<>(solutionBusiness, createSolutionPanel(),createExtraActions());solverAndPersistenceFrame.setDefaultCloseOperation(exitOnClose ? WindowConstants.EXIT_ON_CLOSE : WindowConstants.DISPOSE_ON_CLOSE);solverAndPersistenceFrame.init(centerForComponent);solverAndPersistenceFrame.setVisible(true);}
其中,solution business
- SolverFactory.createFromXmlResource建立了solver
public SolutionBusiness<Solution_, ?> createSolutionBusiness() {SolutionBusiness<Solution_, ?> solutionBusiness = new SolutionBusiness<>(this,SolverFactory.createFromXmlResource(solverConfigResource));solutionBusiness.setDataDir(determineDataDir(dataDirName));solutionBusiness.setSolutionFileIO(createSolutionFileIO());solutionBusiness.setImporters(createSolutionImporters());solutionBusiness.setExporters(createSolutionExporters());solutionBusiness.updateDataDirs();return solutionBusiness;}
在APP类继承的solution中,示例采用的是schedule,也就是planningsolution,作为问题和排产结果
package org.optaplanner.examples.projectjobscheduling.domain;import java.util.List;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.score.buildin.hardmediumsoft.HardMediumSoftScore;
import org.optaplanner.examples.common.domain.AbstractPersistable;
import org.optaplanner.examples.projectjobscheduling.domain.resource.Resource;@PlanningSolution
public class Schedule extends AbstractPersistable {private List<Project> projectList;private List<Job> jobList;private List<ExecutionMode> executionModeList;private List<Resource> resourceList;private List<ResourceRequirement> resourceRequirementList;private List<Allocation> allocationList;private HardMediumSoftScore score;public Schedule() {}public Schedule(long id) {super(id);}@ProblemFactCollectionPropertypublic List<Project> getProjectList() {return projectList;}public void setProjectList(List<Project> projectList) {this.projectList = projectList;}@ProblemFactCollectionPropertypublic List<Job> getJobList() {return jobList;}public void setJobList(List<Job> jobList) {this.jobList = jobList;}@ProblemFactCollectionPropertypublic List<ExecutionMode> getExecutionModeList() {return executionModeList;}public void setExecutionModeList(List<ExecutionMode> executionModeList) {this.executionModeList = executionModeList;}@ProblemFactCollectionPropertypublic List<Resource> getResourceList() {return resourceList;}public void setResourceList(List<Resource> resourceList) {this.resourceList = resourceList;}@ProblemFactCollectionPropertypublic List<ResourceRequirement> getResourceRequirementList() {return resourceRequirementList;}public void setResourceRequirementList(List<ResourceRequirement> resourceRequirementList) {this.resourceRequirementList = resourceRequirementList;}@PlanningEntityCollectionPropertypublic List<Allocation> getAllocationList() {return allocationList;}public void setAllocationList(List<Allocation> allocationList) {this.allocationList = allocationList;}@PlanningScorepublic HardMediumSoftScore getScore() {return score;}public void setScore(HardMediumSoftScore score) {this.score = score;}// ************************************************************************// Complex methods// ************************************************************************}
Timefold 示例
Solver job接受到problem,开始run
@Deprecated(forRemoval = true, since = "1.6.0")default SolverJob<Solution_, ProblemId_> solve(ProblemId_ problemId,Solution_ problem, Consumer<? super Solution_> finalBestSolutionConsumer,BiConsumer<? super ProblemId_, ? super Throwable> exceptionHandler) {SolverJobBuilder<Solution_, ProblemId_> builder = solveBuilder().withProblemId(problemId).withProblem(problem);if (finalBestSolutionConsumer != null) {builder.withFinalBestSolutionConsumer(finalBestSolutionConsumer);}if (exceptionHandler != null) {builder.withExceptionHandler(exceptionHandler);}return builder.run();}
solverStatus = SolverStatus.SOLVING_ACTIVE;// Create the consumer thread pool only when this solver job is active.consumerSupport = new ConsumerSupport<>(getProblemId(), bestSolutionConsumer, finalBestSolutionConsumer,firstInitializedSolutionConsumer, exceptionHandler, bestSolutionHolder);Solution_ problem = problemFinder.apply(problemId);// add a phase lifecycle listener that unlock the solver status lock when solving startedsolver.addPhaseLifecycleListener(new UnlockLockPhaseLifecycleListener());// add a phase lifecycle listener that consumes the first initialized solutionsolver.addPhaseLifecycleListener(new FirstInitializedSolutionPhaseLifecycleListener(consumerSupport));solver.addEventListener(this::onBestSolutionChangedEvent);final Solution_ finalBestSolution = solver.solve(problem);consumerSupport.consumeFinalBestSolution(finalBestSolution);return finalBestSolution;
理解
-
https://www.optaplanner.org/docs/optaplanner/latest/shadow-variable/shadow-variable.html
-
build_solver/ default_solver_factory
public Solver<Solution_> buildSolver(SolverConfigOverride<Solution_> configOverride) {Objects.requireNonNull(configOverride, "Invalid configOverride (null) given to SolverFactory.");var isDaemon = Objects.requireNonNullElse(solverConfig.getDaemon(), false);var solverScope = new SolverScope<Solution_>();var monitoringConfig = solverConfig.determineMetricConfig();solverScope.setMonitoringTags(Tags.empty());var metricsRequiringConstraintMatchSet = Collections.<SolverMetric> emptyList();if (!monitoringConfig.getSolverMetricList().isEmpty()) {solverScope.setSolverMetricSet(EnumSet.copyOf(monitoringConfig.getSolverMetricList()));metricsRequiringConstraintMatchSet = solverScope.getSolverMetricSet().stream().filter(SolverMetric::isMetricConstraintMatchBased).filter(solverScope::isMetricEnabled).toList();} else {solverScope.setSolverMetricSet(EnumSet.noneOf(SolverMetric.class));}var environmentMode = solverConfig.determineEnvironmentMode();var constraintMatchEnabled = !metricsRequiringConstraintMatchSet.isEmpty() || environmentMode.isAsserted();if (constraintMatchEnabled && !environmentMode.isAsserted()) {LOGGER.info("Enabling constraint matching as required by the enabled metrics ({}). This will impact solver performance.",metricsRequiringConstraintMatchSet);}var innerScoreDirector = scoreDirectorFactory.buildScoreDirector(true, constraintMatchEnabled);solverScope.setScoreDirector(innerScoreDirector);solverScope.setProblemChangeDirector(new DefaultProblemChangeDirector<>(innerScoreDirector));var moveThreadCount = resolveMoveThreadCount(true);var bestSolutionRecaller = BestSolutionRecallerFactory.create().<Solution_> buildBestSolutionRecaller(environmentMode);var randomFactory = buildRandomFactory(environmentMode);var configPolicy = new HeuristicConfigPolicy.Builder<>(environmentMode,moveThreadCount,solverConfig.getMoveThreadBufferSize(),solverConfig.getThreadFactoryClass(),solverConfig.getNearbyDistanceMeterClass(),randomFactory.createRandom(),scoreDirectorFactory.getInitializingScoreTrend(),solutionDescriptor,ClassInstanceCache.create()).build();var basicPlumbingTermination = new BasicPlumbingTermination<Solution_>(isDaemon);var termination = buildTerminationConfig(basicPlumbingTermination, configPolicy, configOverride);var phaseList = buildPhaseList(configPolicy, bestSolutionRecaller, termination);return new DefaultSolver<>(environmentMode, randomFactory, bestSolutionRecaller, basicPlumbingTermination,termination, phaseList, solverScope,moveThreadCount == null ? SolverConfig.MOVE_THREAD_COUNT_NONE : Integer.toString(moveThreadCount));}
solver的主流程
@Overridepublic final Solution_ solve(Solution_ problem) {if (problem == null) {throw new IllegalArgumentException("The problem (" + problem + ") must not be null.");}// No tags for these metrics; they are globalLongTaskTimer solveLengthTimer = Metrics.more().longTaskTimer(SolverMetric.SOLVE_DURATION.getMeterId());Counter errorCounter = Metrics.counter(SolverMetric.ERROR_COUNT.getMeterId());solverScope.setBestSolution(problem);solverScope.setSolver(this);outerSolvingStarted(solverScope);boolean restartSolver = true;while (restartSolver) {LongTaskTimer.Sample sample = solveLengthTimer.start();try {// solvingStarted will call registerSolverSpecificMetrics(), since// the solverScope need to be fully initialized to calculate the// problem's scale metricssolvingStarted(solverScope);runPhases(solverScope);solvingEnded(solverScope);} catch (Exception e) {errorCounter.increment();solvingError(solverScope, e);throw e;} finally {sample.stop();unregisterSolverSpecificMetrics();}restartSolver = checkProblemFactChanges();}outerSolvingEnded(solverScope);return solverScope.getBestSolution();}
- run_phase /abstract_solver
protected void runPhases(SolverScope<Solution_> solverScope) {if (!solverScope.getSolutionDescriptor().hasMovableEntities(solverScope.getScoreDirector())) {logger.info("Skipped all phases ({}): out of {} planning entities, none are movable (non-pinned).",phaseList.size(), solverScope.getWorkingEntityCount());return;}Iterator<Phase<Solution_>> it = phaseList.iterator();while (!solverTermination.isSolverTerminated(solverScope) && it.hasNext()) {Phase<Solution_> phase = it.next();phase.solve(solverScope);// If there is a next phase, it starts from the best solution, which might differ from the working solution.// If there isn't, no need to planning clone the best solution to the working solution.if (it.hasNext()) {solverScope.setWorkingSolutionFromBestSolution();}}}
-
solver外面的phase, PhaseFactory
-
dostep
局部搜索在当前解上尝试多个移动,并选择最佳的被接受的移动作为这一步。A step is the winning Move。在每一步,它尝试所有选定的移动,除非是选定的step,否则它不会进一步研究那个解。这就是局部搜索具有很高可扩展性的原因之一。
private void doStep(CustomStepScope<Solution_> stepScope, CustomPhaseCommand<Solution_> customPhaseCommand) {InnerScoreDirector<Solution_, ?> scoreDirector = stepScope.getScoreDirector();customPhaseCommand.changeWorkingSolution(scoreDirector);calculateWorkingStepScore(stepScope, customPhaseCommand);solver.getBestSolutionRecaller().processWorkingSolutionDuringStep(stepScope);}
- 决定下一步
- A MoveSelector which selects the possible moves of the current solution. See the chapter move and neighborhood selection.
- An Acceptor which filters out unacceptable moves.
- A Forager which gathers accepted moves and picks the next step from them.
<localSearch><unionMoveSelector>...</unionMoveSelector><acceptor>...</acceptor><forager>...</forager></localSearch>
从底向上看,理解可能的move。如果是entity+value组合,或者是entity和entity进行新的组合。也许这就是叫做组合优化的原因?
相关文章:

APS开源源码解读: 排程工具 optaplanner
抽象层次非常好,广义优化工具。用于排产没有复杂的落地示例 https://github.com/apache/incubator-kie-optaplanner/blob/main/optaplanner-examples/src/main/java/org/optaplanner/examples/projectjobscheduling/app/ProjectJobSchedulingApp.javahttps://github…...

AMEYA360:村田量产用于汽车市场的高可靠性0603M铜电极负温度系数NTC热敏电阻
株式会社村田制作所开发了0603M尺寸(0.60.30.3mm)铜电极负温度系数(NTC)热敏电阻,型号分别是“NCU03XH103F6SRL”和“NCU03XH103F60RL”,该新品扩充了NCU系列的产品尺寸阵容,满足了汽车市场应用中电路板的高密度化和小型化、以及对电子部件的…...

代码随想录第十天|150.逆波兰表达式求值 239.滑动窗口的最大值 347.前K个高频元素
150.逆波兰表达式求解 思路:做过 使用stoi :字符串转数字 class Solution { public:int cal(int num1,int num2,char c){int res;if(c){resnum1num2;}if(c-){resnum2-num1;}if(c*){resnum1*num2;}if(c/){resnum2/num1;}return res;}int evalRPN(vector…...

[阅读笔记]《解读基金—我的投资观与实践》— 季凯帆
📢博客主页:https://loewen.blog.csdn.net📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢本文由 丶布布原创,首发于 CSDN,转载注明出处🙉📢现…...

2.3之前
1. 2. freertos基础时钟:freertos自动的采用systick定时器,作为freertos基础时钟,systick定时器只有定时中断功能,1ms中断一次。...

处理器基础知识——cache
本文节选自书籍《大话处理器:处理器基础知识读本》 PDF版本可以访问我的网盘通过网盘分享的文件:大话处理器:处理器基础知识读本.pdf 提取码: 1234 0 什么是 Cache 随处可见的Cache–技术来源于生活 使用电脑的人对 Cachc 并不会陌生&#…...

操作系统的运行环境
1.处理器的运行模式 目态 也叫用户态, 执行非特权指令:不能直接访问系统中的软硬件资源,仅仅可以访问用户地址空间。 用户应用程序运行在目态。 管态 也叫内核态, 可执行除访管指令外的任意指令,包括特权指令&…...

如何在 Selenium 中获取网络调用请求?
引言 捕获网络请求对于理解网站的工作方式以及传输的数据至关重要。Selenium 作为一种 Web 自动化工具,可以用于捕获网络请求。本文将讨论如何使用 Selenium 在 Java 中捕获网络请求并从网站检索数据。 我们可以使用浏览器开发者工具轻松捕获网络请求或日志。大多数现代 Web…...

IP学习——oneday
1.什么是网络?为什么需要网络? 空间,时间;传统的邮件传输要考虑到距离,网络解决了空间距离(太远)、解决了时间问题(旧音乐等) 云:面向客户的虚拟化服务 运营商公司主营…...

2024 年高教社杯全国大学生数学建模竞赛 C 题 农作物的种植策略(详细思路+matlab代码+python代码+论文范例)
持续更新中,2024年数学建模比赛思路代码论文都会发布到专栏内,只需订阅一次! 完整论文+代码+数据结果链接在文末! 一、第一问 问题描述:假定各种农作物未来的预期销售量、种植成本、亩产量和销售价格相对于 2023 年保持稳定,每季种植的农作物在当季销售。如果某种作物每…...

软件工程知识点总结(1):软件工程概述
1 什么是软件? 定义:计算机系统中的程序及其文档。 ——程序是计算机任务的处理对象和处理规模的描述; ——文档是为了便于了解程序所需要的阐明性资料。 2 软件的特点? 软件是无形的,不可见的逻辑实体 ——它的正确与…...

热烈庆祝中国科学技术大学建校六六周年
卡西莫多的诗文集2022-2024.9月6-校庆国庆专版 欢迎分享 通过网盘分享的文件:卡西莫多的诗文集2022-2024.9月6-A5-校庆国庆专版.pdf 链接: 百度网盘 请输入提取码 提取码: umpm...

iptables持久化命令:netfilter-persistent save
在Linux上,使用netfilter-persistent命令可以保存iptables防火墙规则,确保它们在系统重启后仍然有效。以下是如何使用netfilter-persistent来保存iptables规则的步骤: 打开终端:首先,你需要打开Linux系统的终端。保存…...

elementUI table 给表头添加气泡显示(鼠标悬浮显示注释)
elementUI table 给表头添加气泡显示(鼠标悬浮显示注释) 前言:文档显示:(使用插槽,我看看到底是怎么个事儿)文档代码:修改后的效果:页面效果: 前言: 公司出现…...

Web3社交新经济,与 SOEX 实现无缝交易的高级安全性
出于充分的理由,安全性是交易中至关重要的考虑因素。每个人都应该确保自己的资金在交易时是安全的。由于 SOEX 充当您与交易所的最佳连接,因此必须强调的是,该系统不会引发任何安全问题。 &a…...

Python和MATLAB(Java)及Arduino和Raspberry Pi(树莓派)点扩展函数导图
🎯要点 反卷积显微镜图像算法微珠图像获取显微镜分辨率基于像素、小形状、高斯混合等全视野建模基于探测器像素经验建模荧光成像算法模型傅里叶方法计算矢量点扩展函数模型天文空间成像重建二维高斯拟合天体图像伽马射线能量和视场中心偏移角标量矢量模型盲解卷积和…...

使用isolation: isolate声明隔离混合模式
在CSS中,isolation 属性与混合模式(如 mix-blend-mode 和 background-blend-mode)并不直接相关,但它确实可以影响元素如何与其他元素进行渲染,尤其是在涉及到堆叠上下文(stacking contexts)和复…...

93. UE5 GAS RPG 应用负面效果表现
在上一篇文章里,我们实现了添加负面效果GE,并且在添加GE时,也会给角色应用一个负面效果标签作为标识。在这一篇里,我们将通过负面效果标签标识,应用角色身上展现对应的负面效果的表现。 我们将在这篇文章里添加一个自定…...

TCP 和 UDP 区别
UDP UDP(用户数据报协议,User Datagram Protocol)是一种无连接的网络传输协议,提供了简单的消息传送服务。UDP位于传输层,允许应用程序向其他主机发送封装在IP数据报中的消息,而无需先建立连接。由于UDP不…...

免费2024柜台租赁经营合同范本模板下载分享
今天看到这个合同范本都拿来卖钱,我直接分享出来2024年最新的范本模板随便下,免费的 柜台租赁经营合同GF—2013—0603.docx: https://url51.ctfile.com/f/20096151-1353625109-4285d2?p1605 (访问密码: 1605) 柜台租赁经营合同GF—2013—0603.pdf: https://url51.ctfile.com/…...

模型和算力看板:Compute DashBoard
AGI 之路 AGI(通用人工智能)是整个计算机科学的圣杯,算力的增长和模型能力的提升(算法和数据)缺一不可。作为一个新质生产力,构建一个合理的评价体系是常用的方法论。针对模型和算力的评价,有类…...

Python加载 TorchScript 格式的 ResNet18 模型分类该模型进行预测并输出预测的类别和置信度
首先加载预训练的 ResNet18 模型。将模型设置为评估模式,以确保特定层(如 Dropout 和 BatchNorm)在评估时具有确定性的行为。创建一个形状为 (1, 3, 224, 224) 的随机张量作为示例输入。使用 torch.jit.trace 函数追踪模型在给定示例输入上的…...

学习笔记--MybatisPlus
官网:MyBatis-Plus 🚀 为简化开发而生 快速入门 入门案例 引入MybatisPlus的起步依赖 定义Mapper 问题: MybatisPlus中Invalid bound statement (not found): com.itheima.mp.mapper.UserMapper.insert 一定要指定实体类!&am…...

【机器学习】XGBoost的用法和参数解释
一、XGBoost的用法 流程: 代码案例: 二、XGBoost的几大参数 1、一般参数,用于集成算法本身 ①n_estimators 集成算法通过在数据上构建多个弱 评估器,汇总所有弱评估器的建模结果,以获取比单个模型更好的回归或分类…...

Vivado 约束
步骤5:保存约束 约束管理是设计流程的重要一步,Vivado设计套件 为您提供了在现有约束文件中添加新约束、覆盖的灵活性 现有约束,或创建新的约束文件以跟踪设计更改或完成 缺少约束。 您为设计创建了一些定时异常,但这些异常仅存在…...

如何在Excel中创建一个VBA宏,并设置一个按钮来执行这个宏
下面是一个详细的步骤指南 步骤1:创建VBA宏 1. 打开Excel并按 Alt F11 打开VBA编辑器。 2. 在VBA编辑器中,选择 Insert > Module 来插入一个新的模块。 3. 将以下代码粘贴到模块中: vba Sub CreateNewSheet() 声明一个工作表对象Dim …...

H3C SR-MPLS通过OSPF通告SID配置
首先在配置前理解几个基本概念 Prefix SID配置 统一分配和配置(全局规划)loopback和prefix sidPrefix SIDSRGB Base(16000)index Adj SID自动生成 对应SR节点间的互联链路SR节点本地标识,从设备本地Segment池中动态…...

JS面试真题 part2
JS面试真题 part2 6、typeof 与 instanceof 区别7、JavaScript原型,原型链?有什么特点8、说说你对作用域链的理解9、谈谈this对象的理解10、说说new操作符具体干了什么 6、typeof 与 instanceof 区别 自己回答: typeof:用来判断数…...

python 下载excel 添加水印
Python 在 Excel 中添加水印 https://zhuanlan.zhihu.com/p/499239298 生成图片 from PIL import Image, ImageDraw, ImageFont import numpy as np import matplotlib.pyplot as plt# 创建一个新的白色图片 img Image.new(RGB, (200, 100), color(255, 255, 255))# 指定中…...

CosyVoice:开源强大的 AI 语音合成工具
在当今科技飞速发展的时代,AI 语音合成技术正逐渐改变着我们的生活。今天,就为大家介绍一款卓越的语音合成工具——CosyVoice。 一、安装步骤 克隆和安装: 克隆仓库:git clone --recursive https://github.com/FunAudioLLM/Cos…...