在 Red Hat Process Automation Manager 中使用 Red Hat Business Optimizer 开发问题


Red Hat Process Automation Manager 7.10

摘要

本文档论述了如何在 Red Hat Process Automation Manager 中使用 Red Hat Business Optimizer 开发解析程序,以查找规划问题的最佳解决方案。

前言

作为商业决策和流程的开发人员,您可以使用红帽商业优化器开发规划问题的最佳解决方案。Red Hat Business Optimizer 是 Red Hat Process Automation Manager 的内置组件。您可以将 solvers 用作 Red Hat Process Automation Manager 中的服务的一部分,以优化具有特定限制的有限资源。

使开源包含更多

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。我们从这四个术语开始:master、slave、黑名单和白名单。由于此项工作十分艰巨,这些更改将在即将推出的几个发行版本中逐步实施。详情请查看 CTO Chris Wright 信息

部分 I. Red Hat Business Optimizer 入门

作为自定义规则开发人员,您可以使用 Red Hat Business Optimizer 来查找根据一组有限资源和特定限制规划问题的最佳解决方案。

使用本文档来开始使用 Red Hat Business Optimizer 开始开发问题。

第 1 章 Red Hat Business Optimizer 简介

Red Hat Business Optimizer 是一个轻量级、可嵌入的规划引擎,可优化规划问题。它帮助普通 Java 站有效地解决规划问题,它将优化 heuristics 和 metaheuristics 与非常有效的分数计算相结合。

例如,Red Hat Business Optimizer 帮助解决各种用例:

  • 员工/人员 :它有助于为 nurses 创建时间表并跟踪个人管理。
  • 指导 时间表:帮助安排较少活动、课程、技术和技术演示。
  • Shop Schedules :它跟踪库存装配行、机器队列规划和工作强制任务规划。
  • Cutting Stock :通过减少纸张和钢材等消耗来最小化浪费。

每个机构都面临规划问题;也就是说,它们为产品和服务提供有限的受限资源集合(如员工、资产、时间和销售)。

Red Hat Business Optimizer 是 Apache Software License 2.0 下的开源软件。它是 100% 纯 Java,在大多数 Java 虚拟机上运行。

1.1. 规划问题

规划问题 具有最佳目标,基于有限资源和特定限制。最佳目标可以是任意数量的事情,例如:

  • 最大化原位 - 最佳目标会导致最高的概率。
  • 最小化托管空间 - 最佳目标对环境的影响最小。
  • 最大化员工或客户的产品 - 优先选择员工或客户需求的最佳目标。

实现这些目标的能力取决于可用资源的数量。例如,以下资源可能会受限制:

  • 人员数量
  • 时间量
  • 预算
  • 物理资产,如 machinery, vehicles, computer, buildings 等

您还必须考虑与这些资源相关的特定限制,如个人工作时间、他们使用某些机器或设备间的兼容性的能力。

Red Hat Business Optimizer 帮助 Java 人员有效地解决约束问题。它将优化 heuristics 和 metaheuristics 与有效的分数计算相结合。

1.2. 规划问题中的 NP-completeness

提供的用例 可能是 NP-complete 或 NP-hard,这意味着适用以下语句:

  • 在合理的时间内,容易验证给定问题的解决方案。
  • 在合理的时间段内,无法简单查找问题的最佳解决方案。

这意味着您的问题可能比您预期的难度更大,因为这两种常见技术不会受到影响:

  • 禁止算法(即使更高级的变体)用时过长。
  • 一个快速算法,例如在 bin packing 问题 中,将放置在最大项目中,首先 返回来自于最佳解决方案。

通过使用高级优化算法,BUSINESS Optimizer 会在合理的时间为规划问题找到良好的解决方案。

1.3. 规划问题的解决方案

规划问题有很多解决方案。

几种解决方案类别:

可能的解决方案
可能的解决方案是任何解决方案,无论它是否会破坏任意数量的限制。规划问题通常具有大量可能的解决方案。其中许多解决方案都并不有用。
可行的解决方案
可行的解决方案是不会破坏任何(负)硬限制的解决方案。可行的解决方案数量相对于可能的解决方案数量。有时没有可行的解决方案。每个可行的解决方案都是可能的解决方案。
最佳解决方案
最佳解决方案是具有最高分数的解决方案。规划问题通常有几个最佳解决方案。它们始终至少有一个最佳解决方案,即使没有可行的解决方案,并且最佳解决方案不可行。
找到最佳解决方案
最佳解决方案是在给定时间内实现的最高分数的解决方案。最佳解决方案可能很可行,给定有足够的时间,它是一个最佳解决方案。

因此,可能的解决方案数量较大(如果正确计算),即使设置了小的数据也是如此。

planner-engine 分发文件夹中提供的示例中,大多数实例都有大量可能的解决方案。因为无法保证查找最佳解决方案,因此任何实施都被强制评估所有可能的解决方案的子集。

商业优化算法支持多种优化算法,以便有效地利用这一不大的解决方案。

根据用例,一些优化算法性能比其他算法更好,但无法提前知道。使用 Business Optimizer,您可以通过在几个 XML 或代码中更改 solver 配置来切换优化算法。

1.4. 有关规划问题的限制

通常,计划问题至少有两个级别的约束:

  • 一个 (负)硬限制 不能被破坏。

    例如,一个公司无法同时为两个不同的资源提供两个不同的项。

  • 如果可以避免,则 (负)软约束 不应中断。

    例如,Teacher A 不希望在每天的 afternoons 上参与。

有些问题也存在正限制:

  • 如果可能,应满足 正的软约束(或返回)。

    例如,Teacher B 与 Monday mornings 相似。

有些基本问题仅存在硬约束。有些问题有三个或更多级别的约束,如硬、中型和软限制。

这些限制定义了规划问题 的分数计算 (也称为适当的 功能)。规划问题的每个解决方案均以分数的形式进行评级。使用 Business Optimizer 时,分数约束使用面向对象的语言(如 Java)或 dols 规则编写。

这种类型的代码灵活且可扩展的。

第 2 章 在 Business Central 中使用 solvers: 一个员工的循环示例

您可以在 Business Central 中构建和部署 employee-rostering 示例项目。项目演示了如何创建所需的每个 Business Central 资产来解决移动规划问题,并使用 Red Hat Business Optimizer 来查找最佳解决方案。

您可以在 Business Central 中部署预配置的 employee-rostering 项目。或者,您可以使用 Business Central 创建项目。

注意

Business Central 中的 employee-rostering 示例项目不包括数据集。您必须使用 REST API 调用提供 XML 格式设置的数据。

2.1. 在 Business Central 中部署员工示例项目

Business Central 包括多个示例项目,可用于熟悉产品及其功能。员工示例项目经过设计和创建,以演示红帽业务优化器的过渡用例。使用以下步骤在 Business Central 中部署并运行员工示例。

先决条件

  • Red Hat Process Automation Manager 已下载并安装。有关安装选项,请参阅 规划 Red Hat Process Automation Manager 安装
  • 您已启动 Red Hat Process Automation Manager,如安装文档中所述,并且以具有 admin 权限的用户身份登录 Business Central。

流程

  1. 在 Business Central 中,点击 MenuDesignProjects
  2. 在预配置的 MySpace 空间中,点 Try Samples
  3. 从示例项目列表中选择 employee-rostering,然后单击右上角的 Ok 以导入项目。
  4. 在资产列表编译后,点 Build & Deploy 部署员工漏洞示例。

本文档的其余部分解释了每个项目资产及其配置。

2.2. 重新创建员工示例项目

employee rostering 示例项目是在 Business Central 中预先配置的项目。您可以在 第 2.1 节 “在 Business Central 中部署员工示例项目” 中了解如何部署此项目。

您可以创建员工示例"从 scratch"示例。您可以使用本示例中的工作流在 Business Central 中创建您自己的类似的项目。

2.2.1. 设置员工漏洞项目

要在 Business Central 中开始开发一个问题,您必须设置项目。

先决条件

  • Red Hat Process Automation Manager 已下载并安装。
  • 您已部署了 Business Central,并使用具有 admin 角色的用户登录。

流程

  1. MenuDesignProjectsAdd Project 在 Business Central 中创建一个新项目。
  2. Add Project 窗口中填写以下字段:

    • 名称:employee-rostering
    • 描述(可选):使用 Business Optimizer 提升问题优化。分配员工以根据其领导进行过渡。

    (可选)单击 Configure Advanced Options 以填充 组 ID工件 ID 和版本信息。

    • 组 IDemployeerostering
    • 工件 IDemployeerostering
    • Version:1.0.0-SNAPSHOT
  3. 单击 Add,将项目添加到 Business Central 项目存储库。

2.2.2. 问题事实和计划实体

员工规划问题中的每个域类被归类为以下之一:

  • 不相关的类:没有被任何分数约束使用。从计划角度来说,这些数据已过时。
  • 问题事实 类:由分数限制使用,但在规划过程中不会改变(只要问题保持不变),例如 ShiftEmployee。问题事实类的所有属性都是问题属性。
  • 计划实体 类:由分数约束使用,并在规划过程中更改,例如 ShiftAssignment。规划期间更改的属性是 规划变量。其他属性是问题属性。

    请询问以下问题:

  • 规划过程中发生了什么类变化?
  • 哪个类有我希望更改 Solver 的变量?

    该类是计划实体。

    规划实体类需要使用 @PlanningEntity 注释进行注解,或使用域设计器中的 Red Hat Business Optimizer dock 在 Business Central 中定义。

    每个计划实体类都有一个或多个 规划变量,还必须具有一个或多个定义属性。

    大多数用例都只有一个计划实体类,每个计划实体类只能有一个规划变量。

2.2.3. 为员工项目创建数据模型

使用本节创建在 Business Central 中运行员工示例项目所需的数据对象。

先决条件

流程

  1. 使用新项目,点项目视角中的 Data Object,或者点击 Add AssetData Object 来创建新项目对象。
  2. 命名第一个数据对象 Timeslot,然后选择 employeerostering.employeerostering 作为 Package

    确定

  3. Data Objects 视角中,点 +add 字段Timeslot 数据对象添加字段。
  4. id 字段中,键入 endTime
  5. 单击 Type 旁边的下拉菜单,再选择 LocalDateTime
  6. Create and continue 添加另一个字段。
  7. 添加另一个字段,其 id startTimeType LocalDateTime
  8. Create
  9. 点右上角的 Save,以保存 Timeslot 数据对象。
  10. 点右上角的 x 关闭 Data Objects 视角,并返回到 Assets 菜单。
  11. 使用前面的步骤,创建以下数据对象及其属性:

    表 2.1. 领导
    id类型

    name

    字符串

    表 2.2. employee
    id类型

    name

    字符串

    知识

    employeerostering.employeerostering.Skill[List]

    表 2.3. 移动
    id类型

    requiredSkill

    employeerostering.employeerostering.Skill

    timeslot

    employeerostering.employeerostering.Timeslot

    表 2.4. DayOffRequest
    id类型

    date

    LocalDate

    employee

    employeerostering.employeerostering.Employee

    表 2.5. ShiftAssignment
    id类型

    employee

    employeerostering.employeerostering.Employee

    shift

    employeerostering.employeerostering.Shift

有关创建数据对象的更多示例,请参阅开始使用决策服务。

2.2.3.1. 创建员工 roster 计划实体

为了解决员工的规划问题,您必须创建一个规划实体和解决方案。规划实体使用 Red Hat Business Optimizer dock 中提供的属性在域设计器中定义。

使用以下步骤将 ShiftAssignment 数据对象定义为员工的计划实体。

先决条件

流程

  1. 在项目 资产 菜单中,打开 ShiftAssignment 数据对象。
  2. Data Objects 视角中,点右侧的 Red Hat Business Optimizer icon 来打开 Red Hat Business Optimizer dock。
  3. 选择 Planning Entity
  4. ShiftAssignment 数据对象下的字段列表中选择 employee
  5. 在 Red Hat Business Optimizer dock 中,选择 Planning Variable

    Value Range Id 输入字段中,键入 employeeRange。这会在规划实体中添加 @ValueRangeProvider 注释,您可以通过单击设计器中的 Source 选项卡来查看该注释。

    规划变量的值范围通过 @ValueRangeProvider 注释定义。@ValueRangeProvider 注释始终具有属性 id,它由 @PlanningVariable 属性 valueRangeProviderRefs 引用。

  6. 关闭 dock 并点 Save 保存数据对象。
2.2.3.2. 创建员工 roster 规划解决方案

员工的 roster 问题依赖于定义的规划解决方案。规划解决方案使用 Red Hat Business Optimizer dock 中提供的属性在域设计器中定义。

先决条件

流程

  1. 使用标识符 EmployeeRoster 创建新数据对象。
  2. 创建以下字段:

    表 2.6. EmployeeRoster
    id类型

    dayOffRequestList

    employeerostering.employeerostering.DayOffRequest[List]

    shiftAssignmentList

    employeerostering.employeerostering.ShiftAssignment[List]

    shiftList

    employeerostering.employeerostering.Shift[List]

    skillList

    employeerostering.employeerostering.Skill[List]

    timeslotList

    employeerostering.employeerostering.Timeslot[List]

  3. Data Objects 视角中,点右侧的 Red Hat Business Optimizer icon 来打开 Red Hat Business Optimizer dock。
  4. 选择规划解决方案
  5. 将默认的 Hard soft score 保留为 Solution Score Type。这会在 EmployeeRoster 数据对象中自动生成 score 字段,其解决方案分数作为类型。
  6. 使用以下属性添加新字段:

    id类型

    employeeList

    employeerostering.employeerostering.Employee[List]

  7. 选择 employeeList 字段后,打开 Red Hat Business Optimizer dock 并选择 Planning Value Range Provider 复选框。

    id 字段中,键入 employeeRange。关闭 dock。

  8. 点右上角的 Save 保存资产。

2.2.4. 员工距离限制

员工障碍是一个规划问题。所有规划问题包括必须满足的限制才能找到最佳解决方案。

Business Central 中的 employee rostering 示例项目包括以下硬和软限制:

硬约束
  • 员工每天仅分配一个转换。
  • 需要特定员工的改变均会成为具有该特定领导员工的员工。
软限制
  • 所有员工都会被分配一个转换。
  • 如果员工要求一天关闭,则他们的转换将重新分配给其他员工。

硬和软限制在 Business Central 中定义,可使用自由格式的 DRL 设计程序或使用指导规则。

2.2.4.1. DRL (Drools Rule Language)规则

DRL (Drools Rule Language)规则是在 .drl 文本文件中直接定义的警报规则。这些 DRL 文件是最终呈现 Business Central 中所有其他规则资产的源。您可以在 Business Central 界面中创建和管理 DRL 文件,或使用 Red Hat CodeReady Studio 或其他集成开发环境(IDE)在外部创建它们。DRL 文件可以包含一个或多个规则,这些规则至少定义规则条件(when)和操作(then)。Business Central 中的 DRL 设计程序提供了 Java、DRL 和 XML 的语法突出显示。

DRL 文件由以下组件组成:

DRL 文件中的组件

package

import

function  // Optional

query  // Optional

declare   // Optional

global   // Optional

rule "rule name"
    // Attributes
    when
        // Conditions
    then
        // Actions
end

rule "rule2 name"

...
Copy to Clipboard

以下示例 DRL 规则决定 loan 应用程序决策服务的年龄限制:

loan 应用程序年龄限制的规则示例

rule "Underage"
  salience 15
  agenda-group "applicationGroup"
  when
    $application : LoanApplication()
    Applicant( age < 21 )
  then
    $application.setApproved( false );
    $application.setExplanation( "Underage" );
end
Copy to Clipboard

DRL 文件可以包含单个或多个规则、查询和功能,并可定义资源声明,如导入、全局和属性,这些属性由您的规则和查询分配和使用。DRL 软件包必须在 DRL 文件的顶部列出,规则通常最后列出。所有其他 DRL 组件都可以遵循任何顺序。

每个规则都必须在 rule 软件包中具有唯一名称。如果您在软件包中的任何 DRL 文件中使用相同的规则名称多次,则规则无法编译。始终使用双引号括起规则名称(规则"规则名称"),以防止可能编译错误,特别是在规则名称中使用空格时。

与 DRL 规则相关的所有数据对象都必须与 Business Central 中的 DRL 文件位于同一个项目中。默认情况下导入同一软件包中的资产。其他软件包中的现有资产可以使用 DRL 规则导入。

2.2.4.2. 使用 DRL 设计程序为员工定义限制

您可以使用 Business Central 中的自由格式 DRL 设计程序为员工创建约束定义。

使用这个流程创建一个 硬约束,其中没有分配在之前转换结束时开始 10 小时的转换。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDRL file
  3. DRL 文件名 字段中,键入 ComplexScoreRules
  4. 选择 employeerostering.employeerostering 软件包。
  5. 单击 +Ok 以创建 DRL 文件。
  6. 在 DRL 设计器的 Model 选项卡中,将 Employee10HourShiftSpace 规则定义为 DRL 文件:

    package employeerostering.employeerostering;
    
    rule "Employee10HourShiftSpace"
        when
            $shiftAssignment : ShiftAssignment( $employee : employee != null, $shiftEndDateTime : shift.timeslot.endTime)
            ShiftAssignment( this != $shiftAssignment, $employee == employee, $shiftEndDateTime <= shift.timeslot.endTime,
                    $shiftEndDateTime.until(shift.timeslot.startTime, java.time.temporal.ChronoUnit.HOURS) <10)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -1);
    end
    Copy to Clipboard
  7. Save 保存 DRL 文件。

有关创建 DRL 文件的更多信息,请参阅使用 DRL 规则设计决策服务

2.2.5. 使用指导规则为员工创建规则

您可以使用 Business Central 中的指导规则设计器,创建用于员工的硬和软限制的规则。

2.2.5.1. 指导规则

指导规则是您在 Business Central 中基于 UI 的指导规则设计人员创建的新规则,可帮助您完成规则创建过程。指导规则设计器根据所定义的规则的数据对象,为可接受的输入提供字段和选项。您定义的指导规则被编译到 drools 规则中,与其他规则资产一样。

与指导规则相关的所有数据对象都必须与指导规则位于同一个项目中。默认情况下导入同一软件包中的资产。创建必要的数据对象和指导规则后,您可以使用指导规则设计器的 Data Objects 选项卡来验证所有必需的数据对象是否已列出,或通过添加新 项目 来导入其他现有数据对象。

2.2.5.2. 创建指导规则以平衡员工移动号

BalanceEmployeesShiftNumber 指南规则会创建一个软约束,以确保以尽可能均匀地平衡为员工。它通过创建一个在转换分发较少时增加的分数损失来达到此目标。规则实施的分数公式使 Solver 以更均衡的方式分发转换。

BalanceEmployeesShiftNumber 指导规则

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDatacenter Rule
  3. 输入 BalanceEmployeesShiftNumber 作为 指导规则 名称,然后选择 employeerostering.employeerostering Package
  4. Ok 创建规则资产。
  5. WHEN 字段中的 5686 来添加 WHEN 条件。
  6. Add a condition to the rule 窗口中选择 Employee。单击 +Ok
  7. Employee 条件来修改约束,并添加变量名称 $employee
  8. 从 Accumulate 添加 WHEN 条件。

    1. From Accumulate 条件之上 ,单击 Click to add mode,然后从下拉列表中选择 Number 作为事实类型。
    2. 将变量名称 $shiftCount 添加到 Number 条件。
    3. From Accumulate 条件下 ,单击 Click to add mode,然后从下拉列表中选择 ShiftAssignment fact 类型。
    4. 将变量名称 $shiftAssignment 添加到 ShiftAssignment 事实类型。
    5. 再次点 ShiftAssignment 条件,然后从 Add a limit on a field 下拉列表中选择 employee
    6. employee 约束旁边的下拉列表中,选择 equal 等于
    7. 点击下拉按钮旁的 edit 图标添加变量,然后点击 Field value 窗口中的 Bound 变量
    8. 从下拉列表中选择 $employee
    9. Function 框中,键入 count ($shiftAssignment)
  9. wordpress N 字段中的 5686 来添加 wordpressN 条件。
  10. Add a new action 窗口中选择 Modify Soft Score。单击 +Ok

    1. 在框中键入以下表达式: -($shiftCount.intValue () 39)$shiftCount.intValue ())
  11. 单击右上角的 Validate,以检查所有规则条件是否有效。如果规则验证失败,请解决错误消息中描述的任何问题,检查规则中的所有组件,然后重试验证规则直到规则通过为止。
  12. Save 保存规则。

有关创建指导规则的更多信息 ,请参阅使用指导规则设计决策服务

2.2.5.3. 创建一个指导规则,每天不多于一个

OneEmployeeShiftPerDay 指南规则会创建一个硬约束,员工每天不会分配多个迁移。在 employee rostering 示例中,此约束是使用指导规则设计器创建的。

OneEmployeeShiftPerDay 专家规则

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDatacenter Rule
  3. 输入 OneEmployeeShiftPerDay 作为 指导规则 名称,然后选择 employeerostering.employeerostering Package
  4. Ok 创建规则资产。
  5. WHEN 字段中的 5686 来添加 WHEN 条件。
  6. Add a condition to the rule 窗口中选择 Free form DRL
  7. 在自由形式 DRL 框中键入以下条件:

    $shiftAssignment : ShiftAssignment( employee != null )
    		ShiftAssignment( this != $shiftAssignment , employee == $shiftAssignment.employee , shift.timeslot.startTime.toLocalDate() == $shiftAssignment.shift.timeslot.startTime.toLocalDate() )
    Copy to Clipboard

    此条件指出无法将转换分配给同一天已有另一个转换分配的员工。

  8. wordpress N 字段中的 5686 来添加 wordpressN 条件。
  9. Add a new action 窗口中选择 Add free form DRL
  10. 在自由形式 DRL 框中键入以下条件:

    scoreHolder.addHardConstraintMatch(kcontext, -1);
    Copy to Clipboard
  11. 单击右上角的 Validate,以检查所有规则条件是否有效。如果规则验证失败,请解决错误消息中描述的任何问题,检查规则中的所有组件,然后重试验证规则直到规则通过为止。
  12. Save 保存规则。

有关创建指导规则的更多信息 ,请参阅使用指导规则设计决策服务

2.2.5.4. 创建指导规则以匹配与迁移要求相关的问题

ShiftReqiredSkillsAreMet 指导规则会创建一个硬约束,以确保所有转换均被分配一个具有正确学习集的员工。在 employee rostering 示例中,此约束是使用指导规则设计器创建的。

ShiftRequiredSkillsAreMet 指导规则

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDatacenter Rule
  3. 输入 ShiftReqiredSkillsAreMet 作为 指导规则 名称,然后选择 employeerostering.employeerostering Package
  4. Ok 创建规则资产。
  5. WHEN 字段中的 5686 来添加 WHEN 条件。
  6. 在规则窗口中选择 ShiftAssignment。单击 +Ok
  7. ShiftAssignment 条件,然后从 Add a limits on a field 下拉列表中选择 employee
  8. 在设计人员中,单击 employee 旁边的下拉列表,然后选择 不是 null
  9. ShiftAssignment 条件,然后点 Expression 编辑器

    1. 在设计人员中,单击 [not bound] 以打开 Expression 编辑器,并将表达式绑定到变量 $requiredSkill。点 Set
    2. 在设计人员中,在 $requiredSkill 旁边,从第一个下拉列表中选择 move,然后从下一个下拉列表中选择 requiredSkill
  10. ShiftAssignment 条件,然后点 Expression 编辑器

    1. 在设计人员中,在 [not bound] 旁边,从第一个下拉列表中选择 employee,然后从下一下拉列表中选择 skills
    2. 接下来的下拉列表保留为 Choose
    3. 在下一个下拉菜单中,将 please choose 改为 excludes
    4. 点击 排除edit 图标,在 Field value 窗口中点击 New formula 按钮。
    5. 在公式框中输入 $requiredSkill
  11. wordpress N 字段中的 5686 来添加 wordpressN 条件。
  12. Add a new action 窗口中选择 Modify Hard Score。单击 +Ok
  13. 在 score 操作框中键入 -1
  14. 单击右上角的 Validate,以检查所有规则条件是否有效。如果规则验证失败,请解决错误消息中描述的任何问题,检查规则中的所有组件,然后重试验证规则直到规则通过为止。
  15. Save 保存规则。

有关创建指导规则的更多信息 ,请参阅使用指导规则设计决策服务

2.2.5.5. 创建指导规则来管理第二天请求

DayOffRequest 指导规则创建一个软限制。如果最初分配了转换的员工,这个约束允许被重新分配给另一员工。在 employee rostering 示例中,此约束是使用指导规则设计器创建的。

DayOffRequest 指导规则

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDatacenter Rule
  3. 输入 DayOffRequest 作为 指导规则 名称,然后选择 employeerostering.employeerostering Package
  4. Ok 创建规则资产。
  5. WHEN 字段中的 5686 来添加 WHEN 条件。
  6. Add a condition to the rule 窗口中选择 Free form DRL
  7. 在自由形式 DRL 框中键入以下条件:

    $dayOffRequest : DayOffRequest( )
    		ShiftAssignment( employee == $dayOffRequest.employee , shift.timeslot.startTime.toLocalDate() == $dayOffRequest.date )
    Copy to Clipboard

    此条件指出,如果将过渡分配给发出一天的员工,则员工就有可能被取消分配这个变化。

  8. wordpress N 字段中的 5686 来添加 wordpressN 条件。
  9. Add a new action 窗口中选择 Add free form DRL
  10. 在自由形式 DRL 框中键入以下条件:

    scoreHolder.addSoftConstraintMatch(kcontext, -100);
    Copy to Clipboard
  11. 单击右上角的 Validate,以检查所有规则条件是否有效。如果规则验证失败,请解决错误消息中描述的任何问题,检查规则中的所有组件,然后重试验证规则直到规则通过为止。
  12. Save 保存规则。

有关创建指导规则的更多信息 ,请参阅使用指导规则设计决策服务

2.2.6. 为员工创建 solver 配置

您可以在 Business Central 中创建和编辑 Solver 配置。Solver 配置设计器会创建一个解析器配置,可在项目部署后运行。

先决条件

  • Red Hat Process Automation Manager 已下载并安装。
  • 您已为员工创建并配置了所有相关资产。

流程

  1. 在 Business Central 中,点击 MenuProjects,然后点击您的项目打开它。
  2. Assets 视角中,点 Add AssetSolver configuration
  3. Create new Solver 配置 窗口中,为您的 Solver 输入名称 EmployeeRosteringSolverConfig 并点 Ok

    这将打开 Solver 配置 设计器。

  4. Score Director Factory 配置部分中,定义包含评分规则定义的 KIE 基础。员工示例项目使用 defaultKieBase

    1. 选择 KIE 基础中定义的 KIE 会话之一。员工示例项目使用 defaultKieSession
  5. 单击右上角的 Validate,以检查 Score Director Factory 配置是否正确。如果验证失败,请解决错误消息中描述的任何问题,然后重试验证直到配置通过为止。
  6. Save 保存 Solver 配置。

2.2.7. 为员工排班项目配置 Solver 终止

您可以将 Solver 配置为在指定时间后终止。默认情况下,计划引擎被授予无限时间来解决问题实例。

employee rostering 示例项目被设置为运行 30 秒。

先决条件

流程

  1. Assets 视角打开 EmployeeRosteringSolverConfig。这将打开 Solver 配置 设计器。
  2. Termination 部分中,点 Add 在所选逻辑组中创建新的 termination 元素。
  3. 从下拉列表中选择 Time consumed 终止类型。这在终止配置中作为输入字段添加。
  4. 使用 time 元素旁的箭头来调整到 30 秒的时间。
  5. 单击右上角的 Validate,以检查 Score Director Factory 配置是否正确。如果验证失败,请解决错误消息中描述的任何问题,然后重试验证直到配置通过为止。
  6. Save 保存 Solver 配置。

2.3. 使用 REST API 访问解析器

部署或重新创建示例解析程序后,您可以使用 REST API 访问它。

您必须使用 REST API 注册一个 solver 实例。然后,您可以提供数据集并检索优化的解决方案。

先决条件

2.3.1. 使用 REST API 注册 Solver

在使用 solver 前,您必须使用 REST API 注册 solver 实例。

每个 solver 实例都可以一次优化一个规划问题。

流程

  1. 使用以下标头创建 HTTP 请求:

    authorization: admin:admin
    X-KIE-ContentType: xstream
    content-type: application/xml
    Copy to Clipboard
  2. 使用以下请求注册 Solver:

    PUT
    http://localhost:8080/kie-server/services/rest/server/containers/employeerostering_1.0.0-SNAPSHOT/solvers/EmployeeRosteringSolver
    请求正文
    <solver-instance>
      <solver-config-file>employeerostering/employeerostering/EmployeeRosteringSolverConfig.solver.xml</solver-config-file>
    </solver-instance>
    Copy to Clipboard

2.3.2. 使用 REST API 调用 Solver

注册 solver 实例后,您可以使用 REST API 向 resolver 提交数据集并检索优化的解决方案。

流程

  1. 使用以下标头创建 HTTP 请求:

    authorization: admin:admin
    X-KIE-ContentType: xstream
    content-type: application/xml
    Copy to Clipboard
  2. 使用数据集向 Solver 提交请求,如下例所示:

    POST
    http://localhost:8080/kie-server/services/rest/server/containers/employeerostering_1.0.0-SNAPSHOT/solvers/EmployeeRosteringSolver/state/solving
    请求正文
    <employeerostering.employeerostering.EmployeeRoster>
      <employeeList>
        <employeerostering.employeerostering.Employee>
          <name>John</name>
          <skills>
            <employeerostering.employeerostering.Skill>
              <name>reading</name>
            </employeerostering.employeerostering.Skill>
          </skills>
        </employeerostering.employeerostering.Employee>
        <employeerostering.employeerostering.Employee>
          <name>Mary</name>
          <skills>
            <employeerostering.employeerostering.Skill>
              <name>writing</name>
            </employeerostering.employeerostering.Skill>
          </skills>
        </employeerostering.employeerostering.Employee>
        <employeerostering.employeerostering.Employee>
          <name>Petr</name>
          <skills>
            <employeerostering.employeerostering.Skill>
              <name>speaking</name>
            </employeerostering.employeerostering.Skill>
          </skills>
        </employeerostering.employeerostering.Employee>
      </employeeList>
      <shiftList>
        <employeerostering.employeerostering.Shift>
          <timeslot>
            <startTime>2017-01-01T00:00:00</startTime>
            <endTime>2017-01-01T01:00:00</endTime>
          </timeslot>
          <requiredSkill reference="../../../employeeList/employeerostering.employeerostering.Employee/skills/employeerostering.employeerostering.Skill"/>
        </employeerostering.employeerostering.Shift>
        <employeerostering.employeerostering.Shift>
          <timeslot reference="../../employeerostering.employeerostering.Shift/timeslot"/>
          <requiredSkill reference="../../../employeeList/employeerostering.employeerostering.Employee[3]/skills/employeerostering.employeerostering.Skill"/>
        </employeerostering.employeerostering.Shift>
        <employeerostering.employeerostering.Shift>
          <timeslot reference="../../employeerostering.employeerostering.Shift/timeslot"/>
          <requiredSkill reference="../../../employeeList/employeerostering.employeerostering.Employee[2]/skills/employeerostering.employeerostering.Skill"/>
        </employeerostering.employeerostering.Shift>
      </shiftList>
      <skillList>
        <employeerostering.employeerostering.Skill reference="../../employeeList/employeerostering.employeerostering.Employee/skills/employeerostering.employeerostering.Skill"/>
        <employeerostering.employeerostering.Skill reference="../../employeeList/employeerostering.employeerostering.Employee[3]/skills/employeerostering.employeerostering.Skill"/>
        <employeerostering.employeerostering.Skill reference="../../employeeList/employeerostering.employeerostering.Employee[2]/skills/employeerostering.employeerostering.Skill"/>
      </skillList>
      <timeslotList>
        <employeerostering.employeerostering.Timeslot reference="../../shiftList/employeerostering.employeerostering.Shift/timeslot"/>
      </timeslotList>
      <dayOffRequestList/>
      <shiftAssignmentList>
        <employeerostering.employeerostering.ShiftAssignment>
          <shift reference="../../../shiftList/employeerostering.employeerostering.Shift"/>
        </employeerostering.employeerostering.ShiftAssignment>
        <employeerostering.employeerostering.ShiftAssignment>
          <shift reference="../../../shiftList/employeerostering.employeerostering.Shift[3]"/>
        </employeerostering.employeerostering.ShiftAssignment>
        <employeerostering.employeerostering.ShiftAssignment>
          <shift reference="../../../shiftList/employeerostering.employeerostering.Shift[2]"/>
        </employeerostering.employeerostering.ShiftAssignment>
      </shiftAssignmentList>
    </employeerostering.employeerostering.EmployeeRoster>
    Copy to Clipboard
  3. 请求规划问题的最佳解决方案:

    GET

    http://localhost:8080/kie-server/services/rest/server/containers/employeerostering_1.0.0-SNAPSHOT/solvers/EmployeeRosteringSolver/bestsolution

    响应示例

    <solver-instance>
      <container-id>employee-rostering</container-id>
      <solver-id>solver1</solver-id>
      <solver-config-file>employeerostering/employeerostering/EmployeeRosteringSolverConfig.solver.xml</solver-config-file>
      <status>NOT_SOLVING</status>
      <score scoreClass="org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore">0hard/0soft</score>
      <best-solution class="employeerostering.employeerostering.EmployeeRoster">
        <employeeList>
          <employeerostering.employeerostering.Employee>
            <name>John</name>
            <skills>
              <employeerostering.employeerostering.Skill>
                <name>reading</name>
              </employeerostering.employeerostering.Skill>
            </skills>
          </employeerostering.employeerostering.Employee>
          <employeerostering.employeerostering.Employee>
            <name>Mary</name>
            <skills>
              <employeerostering.employeerostering.Skill>
                <name>writing</name>
              </employeerostering.employeerostering.Skill>
            </skills>
          </employeerostering.employeerostering.Employee>
          <employeerostering.employeerostering.Employee>
            <name>Petr</name>
            <skills>
              <employeerostering.employeerostering.Skill>
                <name>speaking</name>
              </employeerostering.employeerostering.Skill>
            </skills>
          </employeerostering.employeerostering.Employee>
        </employeeList>
        <shiftList>
          <employeerostering.employeerostering.Shift>
            <timeslot>
              <startTime>2017-01-01T00:00:00</startTime>
              <endTime>2017-01-01T01:00:00</endTime>
            </timeslot>
            <requiredSkill reference="../../../employeeList/employeerostering.employeerostering.Employee/skills/employeerostering.employeerostering.Skill"/>
          </employeerostering.employeerostering.Shift>
          <employeerostering.employeerostering.Shift>
            <timeslot reference="../../employeerostering.employeerostering.Shift/timeslot"/>
            <requiredSkill reference="../../../employeeList/employeerostering.employeerostering.Employee[3]/skills/employeerostering.employeerostering.Skill"/>
          </employeerostering.employeerostering.Shift>
          <employeerostering.employeerostering.Shift>
            <timeslot reference="../../employeerostering.employeerostering.Shift/timeslot"/>
            <requiredSkill reference="../../../employeeList/employeerostering.employeerostering.Employee[2]/skills/employeerostering.employeerostering.Skill"/>
          </employeerostering.employeerostering.Shift>
        </shiftList>
        <skillList>
          <employeerostering.employeerostering.Skill reference="../../employeeList/employeerostering.employeerostering.Employee/skills/employeerostering.employeerostering.Skill"/>
          <employeerostering.employeerostering.Skill reference="../../employeeList/employeerostering.employeerostering.Employee[3]/skills/employeerostering.employeerostering.Skill"/>
          <employeerostering.employeerostering.Skill reference="../../employeeList/employeerostering.employeerostering.Employee[2]/skills/employeerostering.employeerostering.Skill"/>
        </skillList>
        <timeslotList>
          <employeerostering.employeerostering.Timeslot reference="../../shiftList/employeerostering.employeerostering.Shift/timeslot"/>
        </timeslotList>
        <dayOffRequestList/>
        <shiftAssignmentList/>
        <score>0hard/0soft</score>
      </best-solution>
    </solver-instance>
    Copy to Clipboard

第 3 章 Java solvers 入门:云供应商示例

示例演示了使用 Java 代码的基本红帽业务优化器的开发。

假设您的公司拥有多个云计算机,需要在这些计算机上运行多个进程。您必须将每个进程分配到计算机。

必须满足以下硬限制:

  • 每个计算机都必须能够处理进程总和的最低硬件要求:

    • CPU 容量 :计算机的 CPU 能力必须至少是分配给该计算机的进程所需的 CPU 电源总和。
    • 内存容量 :计算机的 RAM 内存必须至少是分配给该计算机的进程所需的 RAM 内存总和。
    • 网络容量 :计算机的网络带宽必须至少是分配给该计算机的进程所需的网络带宽总和。

应优化以下软限制:

  • 每个分配了一个或多个进程的计算机都会产生维护成本(每计算机可修复)。

    • 成本 :最小化维护成本。

此问题是 bin 打包 的形式。在以下简化的示例中,我们使用简单算法为两台限制(CPU 和 RAM)为两台计算机分配四个进程:

cloudBalanceUseCase

此处使用的简单算法是第一个 Fit Decreasing 算法,它会首先 分配较大的进程,并将较小的进程分配给剩余的空间。如看到的那样,这不是最佳选择,因为它没有足够的空间来分配黄色进程 D

商业优化器通过使用其他智能算法找到更最佳的解决方案。它还扩展:在数据(更多进程、更多计算机)和限制(更多硬件要求、其他限制)中。

以下概述适用于本例,以及 第 4.10 节 “机器重新分配(Google ROADEF 2012)” 中描述的更多限制的高级实现:

cloudOptimizationValueProposition
表 3.1. 云平衡问题大小
问题大小计算机Process搜索空间

2computers-6processes

2

6

64

3computers-9processes

3

9

10^4

4computers-012processes

4

12

10^7

100computers-300processes

100

300

10^600

200computers-600processes

200

600

10^1380

400computers-1200processes

400

1200

10^3122

800computers-2400processes

800

2400

10^6967

3.1. 域模型设计

使用 域模型 有助于确定哪些类正在规划实体及其属性计划变量。它还有助于简化约束、提高性能并提高未来需求的灵活性。

3.1.1. 设计域模型

要创建域模型,请定义代表问题的输入数据的所有对象。在本例中,对象是进程和计算机。

域模型中的单独的对象必须代表一组问题,其中包含输入数据和解决方案。在本例中,此对象包含计算机列表和进程列表。每个进程分配到一个计算机;计算机之间的进程分布是解决方案。

流程

  1. 绘制域模型的类图。
  2. 将其规范化以删除重复的数据。
  3. 为每个类编写 一些示例实例。示例实例是与规划目的相关的实体属性。

    • 计算机 :代表具有特定硬件和维护成本的计算机。

      在本例中,计算机 类的示例实例为 cpuPower内存networkBandwidth成本 为。

    • 进程 :代表具有需求的进程。需要由 Planner 分配给 计算机

      Process 实例示例 是必需的CpuPowerRequireMemoryrequiredNetworkBandwidth

    • CloudBalance :代表计算机之间进程分布。包含特定 数据集 的每个 计算机 和流程。

      对于代表完整数据集和解决方案的对象,必须存在包含 分数 的示例实例。企业优化器可以计算和比较不同解决方案的分数;解决方案与最高分数是最佳解决方案。因此,CloudBalance 的示例实例 分数 为。

  4. 在规划过程中确定哪些关系(或字段)变化:

    • 规划实体 :业务优化器在公司期间可能会改变的类(或类)。在本例中,它是类 进程,因为我们可以将进程移到不同的计算机。

      • 代表业务优化器无法更改的输入数据的类称为 问题事实
    • 规划变量 :计划实体类的属性(或属性),这些类在技术期间发生了变化。在本例中,这是类 进程 的属性 计算机
    • 规划解决方案 :代表问题解决方案的类。此类必须代表完整的数据集,并包含所有规划实体。在本例中,是类 CloudBalance

在以下 UML 类图中,vmim Optimizer 概念已被注解:

cloudBalanceClassDiagram

您可以在 examples/sources/src/main/java/org/optaplanner/examples/cloudbalancing/domain 目录中找到本例的类定义。

3.1.2. 计算机

Computer 类是一种 Java 对象,它存储数据,有时被称为 POJO (旧 Java 对象)。通常,您将拥有许多带有输入数据的类。

例 3.1. CloudComputer.java

public class CloudComputer ... {

    private int cpuPower;
    private int memory;
    private int networkBandwidth;
    private int cost;

    ... // getters
}
Copy to Clipboard

3.1.3. 进程

Process 类是参与期间修改的类。

我们需要告诉 Business Optimizer,它可以更改属性 计算机。为此,可使用 @PlanningEntity 注解类,并使用 @PlanningVariable 注解 getComputer () getter。

课程,属性 计算机还需要 设置者,因此业务优化器可以在技术期间更改它。

例 3.2. CloudProcess.java

@PlanningEntity(...)
public class CloudProcess ... {

    private int requiredCpuPower;
    private int requiredMemory;
    private int requiredNetworkBandwidth;

    private CloudComputer computer;

    ... // getters

    @PlanningVariable(valueRangeProviderRefs = {"computerRange"})
    public CloudComputer getComputer() {
        return computer;
    }

    public void setComputer(CloudComputer computer) {
        computer = computer;
    }

    // ************************************************************************
    // Complex methods
    // ************************************************************************

    ...

}
Copy to Clipboard

Business Optimizer 需要知道它可以选择将哪些值分配给属性 计算机。这些值从规划解决方案上的方法 CloudBalance.getComputerList () 检索,后者返回当前数据集中的所有计算机的列表。

CloudProcess.getComputer () 上的 @PlanningVariable 'svalueRangeProviderRefs 参数需要与 CloudBalance.getComputerList () 上的 @ValueRangeProvider 'sid 匹配。

注意

您还可以在字段而不是 getters 上使用注解。

3.1.4. CloudBalance

CloudBalance 类具有 @PlanningSolution 注释。

此类包含所有计算机和进程的列表。它代表了规划问题,以及(如果被初始化)规划解决方案。

CloudBalance 类有以下关键属性:

  • 它包含一组业务优化器可以更改的进程集合。我们使用 @PlanningEntityCollectionProperty 注解 getter getProcessList (),以便 Business Optimizer 能够检索它可以更改的进程。为保存解决方案,BUSINESS Optimizer 使用更改的进程列表初始化类的新实例。

    1. 它还有一个 @PlanningScore 注解的属性 分数,这是该解决方案处于当前状态的 分数。当为解决方案实例计算 Score 时,业务优化器会自动更新它,因此此属性需要一个 setter。
    2. 特别是使用 Drools 进行分数计算,属性 computerList 需要用 @ProblemFactCollectionProperty 注解,以便业务优化器可以检索计算机(虚拟化事实)列表,并使其可供决策引擎使用。

例 3.3. CloudBalance.java

@PlanningSolution
public class CloudBalance ... {

    private List<CloudComputer> computerList;

    private List<CloudProcess> processList;

    private HardSoftScore score;

    @ValueRangeProvider(id = "computerRange")
    @ProblemFactCollectionProperty
    public List<CloudComputer> getComputerList() {
        return computerList;
    }

    @PlanningEntityCollectionProperty
    public List<CloudProcess> getProcessList() {
        return processList;
    }

    @PlanningScore
    public HardSoftScore getScore() {
        return score;
    }

    public void setScore(HardSoftScore score) {
        this.score = score;
    }

    ...
}
Copy to Clipboard

3.2. 运行 Cloud Balancing Hello World

您可以运行示例"hello world"应用来演示解析器。

流程

  1. 下载并配置您首选的 IDE 中的示例。有关在 IDE 中下载和配置示例的步骤,请参考 第 4.1.3 节 “在 IDE 中运行 Red Hat Business Optimizer 示例(IntelliJ、Ecli 或 Netbeans)”
  2. 使用以下主类创建运行配置: org.optaplanner.examples.cloudbalancing.app.CloudBalancingHelloWorld

    默认情况下,Cloud Balancing Hello World 配置为运行 120 秒。

结果

应用程序执行以下代码:

例 3.4. CloudBalancingHelloWorld.java

public class CloudBalancingHelloWorld {

    public static void main(String[] args) {
        // Build the Solver
        SolverFactory<CloudBalance> solverFactory = SolverFactory.createFromXmlResource("org/optaplanner/examples/cloudbalancing/solver/cloudBalancingSolverConfig.xml");
        Solver<CloudBalance> solver = solverFactory.buildSolver();

        // Load a problem with 400 computers and 1200 processes
        CloudBalance unsolvedCloudBalance = new CloudBalancingGenerator().createCloudBalance(400, 1200);

        // Solve the problem
        CloudBalance solvedCloudBalance = solver.solve(unsolvedCloudBalance);

        // Display the result
        System.out.println("\nSolved cloudBalance with 400 computers and 1200 processes:\n" + toDisplayString(solvedCloudBalance));
    }

    ...
}
Copy to Clipboard

代码示例执行以下操作:

  1. 根据 解析器 配置构建 Solver (本例中为 XML 文件 cloudBalancingSolverConfig.xml )。

    构建 Solver 是此流程中最复杂的部分。如需了解更多详细信息,请参阅 第 3.3 节 “solver 配置”

            SolverFactory<CloudBalance> solverFactory = SolverFactory.createFromXmlResource(
                    "org/optaplanner/examples/cloudbalancing/solver/cloudBalancingSolverConfig.xml");
            Solver solver<CloudBalance> = solverFactory.buildSolver();
    Copy to Clipboard
  2. 加载问题。

    CloudBalancingGenerator 生成一个随机问题:您将替换为加载实际问题的类,例如从数据库中。

            CloudBalance unsolvedCloudBalance = new CloudBalancingGenerator().createCloudBalance(400, 1200);
    Copy to Clipboard
  3. 解决问题。

            CloudBalance solvedCloudBalance = solver.solve(unsolvedCloudBalance);
    Copy to Clipboard
  4. 显示结果。

            System.out.println("\nSolved cloudBalance with 400 computers and 1200 processes:\n"
                    + toDisplayString(solvedCloudBalance));
    Copy to Clipboard

3.3. solver 配置

solver 配置文件决定了参与过程的工作方式;它被视为代码的一部分。该文件命名为 example /sources/src/main/resources/org/optaplanner/examples/cloudbalancing/solver/cloudBalancingSolverConfig.xml

例 3.5. cloudBalancingSolverConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<solver>
  <!-- Domain model configuration -->
  <scanAnnotatedClasses/>

  <!-- Score configuration -->
  <scoreDirectorFactory>
    <easyScoreCalculatorClass>org.optaplanner.examples.cloudbalancing.optional.score.CloudBalancingEasyScoreCalculator</easyScoreCalculatorClass>
    <!--<scoreDrl>org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>-->
  </scoreDirectorFactory>

  <!-- Optimization algorithms configuration -->
  <termination>
    <secondsSpentLimit>30</secondsSpentLimit>
  </termination>
</solver>
Copy to Clipboard

这个 resolver 配置由三个部分组成:

  1. 域模型配置业务优化器变化是什么?

    我们需要使业务优化者了解我们的域类。在此配置中,它将自动扫描类路径中的所有类(对于 @PlanningEntity@PlanningSolution 注解):

      <scanAnnotatedClasses/>
    Copy to Clipboard
  2. 分数配置业务优化器应该如何优化规划变量?我们的目标是什么?

    由于我们存在硬和软限制,因此我们使用一个 HardSoftScore。但我们需要根据我们的业务需求告知业务优化器如何计算分数。此外,我们将查看两种替代方法来计算分数:使用基本的 Java 实施和使用 droolL。

      <scoreDirectorFactory>
        <easyScoreCalculatorClass>org.optaplanner.examples.cloudbalancing.optional.score.CloudBalancingEasyScoreCalculator</easyScoreCalculatorClass>
        <!--<scoreDrl>org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>-->
      </scoreDirectorFactory>
    Copy to Clipboard
  3. 优化算法配置业务优化器应如何优化它?在这种情况下,我们使用默认的优化算法(因为没有配置显式优化算法) 30 秒:

      <termination>
        <secondsSpentLimit>30</secondsSpentLimit>
      </termination>
    Copy to Clipboard

    在使用实时规划功能时,业务优化器应该以秒为单位得到良好结果(即使使用了实时规划功能),但其结果越好,其结果越好。高级用例可能会使用与硬时间限制不同的终止标准。

    默认算法将容易使用人工规划器和大多数内部实施。您可以使用高级基准测试程序功能来更好地获得更好的结果。

3.4. 分数配置

商业优化器将搜索具有最高 分数的解决方案这个示例使用 Hard SoftScore,这意味着 Business Optimizer 将查找没有硬约束(需要填充的硬件要求)且尽可能少的软约束(尽量降低维护成本)的解决方案。

scoreComparisonCloudBalancing

当然,业务优化器需要告知这些特定于域的分数限制。您可以使用 Java 或 dols 语言定义限制。

3.4.1. 使用 Java 配置分数计算

定义分数功能的一种方法是以普通 Java 实施接口 EasyScoreCalculator

流程

  1. 在 Cloud BalancingSolverConfig.xml 文件中,添加或取消注释设置:

      <scoreDirectorFactory>
        <easyScoreCalculatorClass>org.optaplanner.examples.cloudbalancing.optional.score.CloudBalancingEasyScoreCalculator</easyScoreCalculatorClass>
      </scoreDirectorFactory>
    Copy to Clipboard
  2. 实施 compute Score (Solution) 方法,以返回 Hard SoftScore 实例。

    例 3.6. CloudBalancingEasyScoreCalculator.java

    public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance> {
    
        /**
         * A very simple implementation. The double loop can easily be removed by using Maps as shown in
         * {@link CloudBalancingMapBasedEasyScoreCalculator#calculateScore(CloudBalance)}.
         */
        public HardSoftScore calculateScore(CloudBalance cloudBalance) {
            int hardScore = 0;
            int softScore = 0;
            for (CloudComputer computer : cloudBalance.getComputerList()) {
                int cpuPowerUsage = 0;
                int memoryUsage = 0;
                int networkBandwidthUsage = 0;
                boolean used = false;
    
                // Calculate usage
                for (CloudProcess process : cloudBalance.getProcessList()) {
                    if (computer.equals(process.getComputer())) {
                        cpuPowerUsage += process.getRequiredCpuPower();
                        memoryUsage += process.getRequiredMemory();
                        networkBandwidthUsage += process.getRequiredNetworkBandwidth();
                        used = true;
                    }
                }
    
                // Hard constraints
                int cpuPowerAvailable = computer.getCpuPower() - cpuPowerUsage;
                if (cpuPowerAvailable < 0) {
                    hardScore += cpuPowerAvailable;
                }
                int memoryAvailable = computer.getMemory() - memoryUsage;
                if (memoryAvailable < 0) {
                    hardScore += memoryAvailable;
                }
                int networkBandwidthAvailable = computer.getNetworkBandwidth() - networkBandwidthUsage;
                if (networkBandwidthAvailable < 0) {
                    hardScore += networkBandwidthAvailable;
                }
    
                // Soft constraints
                if (used) {
                    softScore -= computer.getCost();
                }
            }
            return HardSoftScore.valueOf(hardScore, softScore);
        }
    
    }
    Copy to Clipboard

即使我们优化了上述代码以使用 Maps 来迭代 processList 一次,它仍然会很慢,因为它不会进行增量分数计算。

要修复这个问题,可以使用增量 Java 分数计算或 drools 分数计算。本指南中不涵盖增量 Java 分数计算。

3.4.2. 使用 drools 配置分数计算

您可以使用 dols 规则语言(DRL)来定义限制。dols 分数计算使用增量计算,每个分数约束都会写成一个或多个分数规则。

通过使用决策引擎进行分数计算,您可以与其他 dols 技术集成,如分区表(基于 XLS 或 Web)、Business Central 和其他支持的功能。

流程

  1. 在 classpath 中添加 scoreDrl 资源,以使用决策引擎作为分数功能。在 Cloud BalancingSolverConfig.xml 文件中,添加或取消注释设置:

      <scoreDirectorFactory>
        <scoreDrl>org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>
      </scoreDirectorFactory>
    Copy to Clipboard
  2. 创建硬限制。这些限制可确保所有计算机有足够的 CPU、RAM 和网络带宽来支持其所有进程:

    例 3.7. cloudBalancingScoreRules.drl - Hard Constraints

    ...
    
    import org.optaplanner.examples.cloudbalancing.domain.CloudBalance;
    import org.optaplanner.examples.cloudbalancing.domain.CloudComputer;
    import org.optaplanner.examples.cloudbalancing.domain.CloudProcess;
    
    global HardSoftScoreHolder scoreHolder;
    
    // ############################################################################
    // Hard constraints
    // ############################################################################
    
    rule "requiredCpuPowerTotal"
        when
            $computer : CloudComputer($cpuPower : cpuPower)
            accumulate(
                CloudProcess(
                    computer == $computer,
                    $requiredCpuPower : requiredCpuPower);
                $requiredCpuPowerTotal : sum($requiredCpuPower);
                $requiredCpuPowerTotal > $cpuPower
            )
        then
            scoreHolder.addHardConstraintMatch(kcontext, $cpuPower - $requiredCpuPowerTotal);
    end
    
    rule "requiredMemoryTotal"
        ...
    end
    
    rule "requiredNetworkBandwidthTotal"
        ...
    end
    Copy to Clipboard
  3. 创建软约束。此约束可最小化维护成本。只有在满足硬限制时才会应用它:

    例 3.8. cloudBalancingScoreRules.drl - Soft Constraints

    // ############################################################################
    // Soft constraints
    // ############################################################################
    
    rule "computerCost"
        when
            $computer : CloudComputer($cost : cost)
            exists CloudProcess(computer == $computer)
        then
            scoreHolder.addSoftConstraintMatch(kcontext, - $cost);
    end
    Copy to Clipboard

3.5. 进一步开发问题

现在,本示例可以正常工作,您可以尝试进一步开发它。例如,您可以增强域模型并添加额外的限制,例如:

  • 每个进程都 属于一个 服务。计算机可能会崩溃,因此运行同一服务的进程应该(或必须)分配给不同的计算机。
  • 每个计算机 都位于一个构建 。构建可能会刻录,因此应(或必须)将同一服务的进程分配给不同构建中的计算机。

第 4 章 Red Hat Business Optimizer 提供的示例

Red Hat Process Automation Manager 提供了几个 Red Hat Business Optimizer 示例。您可以检查示例的代码,并根据需要对其进行修改以满足您的需要。

注意

红帽不支持 Red Hat Process Automation Manager 发行版本中所含的示例代码。

4.1. 下载并运行示例

您可以从 Red Hat Software Downloads 网站下载 Red Hat Business Optimizer 示例并运行它们。

4.1.1. 下载 Red Hat Business Optimizer 示例

您可以将示例作为 Red Hat Process Automation Manager 附加组件软件包的一部分下载。

流程

  1. Software Downloads 页面下载 rhpam-7.10.0-add-ons.zip 文件。
  2. 解压缩文件。
  3. 从解压缩的目录中解压缩 rhpam-7.10-planner-engine.zip 文件。

结果

在解压缩的 rhpam-7.10-planner-engine 目录中,您可以在以下子目录下找到示例源代码:VirtualMachine examples/sources/src/main/java/org/optaplanner/examples 047 examples/sources/src/main/resources/org/optaplanner/examples 047 webexamples/sources/src/main/java/org/optaplanner/examples 网页示例/sources/src/main/resources/org/optaplanner/examples

第 4.2 节 “Business Optimizer 示例表” 中的示例列表列出了用于单个示例的目录名称。

4.1.2. 运行 Business Optimizer 示例

Red Hat Business Optimizer 包括了多个示例来演示各种用例。

先决条件

流程

  1. rhpam-7.10.0-planner-engine 文件夹中,打开 examples 目录,并使用适当的脚本来运行示例:

    Linux 或 Mac:

    $ cd examples
    $ ./runExamples.sh
    Copy to Clipboard

    Windows:

    $ cd examples
    $ runExamples.bat
    Copy to Clipboard

从 GUI 应用程序窗口中选择并运行示例:

plannerExamplesAppScreenshot
注意

Red Hat Business Optimizer 本身没有 GUI 依赖项。它还在服务器或移动 JVM 上运行,就像在桌面上一样。

4.1.3. 在 IDE 中运行 Red Hat Business Optimizer 示例(IntelliJ、Ecli 或 Netbeans)

如果您使用集成开发环境(IDE),如 IntelliJ、Ecli 或 Netbeans,您可以在开发环境中运行您下载的红帽业务优化器示例。

先决条件

流程

  1. 以新项目的形式打开 Red Hat Business Optimizer 示例:

    1. 对于 IntelliJ 或 Netbeans,打开 examples/sources/pom.xml 作为新项目。Maven 集成指导您完成其余安装;跳过此过程中的其余步骤。
    2. 对于 Eclipse,为目录 example /sources 创建一个新项目。
  2. 将所有 JAR 添加到目录二进制文件的 classpath 和目录 examples/binaries,但 examples/binaries/optaplanner-examples114.jar 文件除外。
  3. 添加 Java 源目录 src/main/java 和 Java 资源目录 src/main/resources
  4. 创建运行配置:

    • 主类: org.optaplanner.examples.app.OptaPlannerExamplesApp
    • VM 参数(可选): -Xmx512M -server -Dorg.optaplanner.examples.dataDir=examples/sources/data
    • 工作目录: example/sources
  5. 运行运行配置。

4.1.4. 运行 Web 示例

除了 GUI 示例外,Red Hat Process Automation Manager 还包括一组用于 Red Hat Business Optimizer 的 Web 示例。Web 示例包括:

  • vehicle 路由:计算最短的路由,以使用 LeafletGoogle Maps 视觉化来获取多个不同的客户所需的所有项目。
  • Cloud balancing:分配具有不同规格和成本的计算机的进程。

先决条件

Web 示例需要几个 CRUD API 才能运行,如以下 API:

  • Servlet
  • JAX-RS
  • CDI

Business Optimizer 本身不需要这些 API。

流程

  1. 下载 IaaS 应用服务器,如 JBoss EAP 或 WildFly 并解压缩。
  2. 在解压缩的 rhpam-7.10.0-planner-engine 目录中,打开子目录 webexamples/binaries,并将 optaplanner-webexamples114.war 文件部署到 sVirt 应用程序服务器上。

    如果在独立模式中使用 JBoss EAP,可以通过将 optaplanner-webexamples114.war 文件添加到 JBOSS_home/standalone/deployments 文件夹来完成。

  3. 在网页浏览器中打开以下地址: http://localhost:8080/optaplanner-webexamples/

4.2. Business Optimizer 示例表

某些业务优化器示例解决了参与 contests 中出出的问题。以下表中的 Contest 列列出了 contests。它也识别一个示例为 realisticunrealistic 用于 contest 的目的。最后的 contest 是一个官方独立 contest

最后的 contest 是符合以下标准的官方独立 contest:

  • 明确定义的实际用例
  • 真实限制
  • 多个真实数据集
  • 在特定硬件的特定时间限制中可重复生成结果
  • 领导和/或企业级操作人员的严重参与。

协作 contests 为业务优化器和专家研究提供了目标比较。

表 4.1. 示例概述
示例Domain大小法国目录名称

N queens

1 个实体类

(1 个变量)

实体 IANA 256

值 IANA 256

搜索空间 10^616

Pointless (cheatable)

nqueens

Cloud balancing

1 个实体类

(1 个变量)

实体为 2400

值 IANA 800

搜索空间 10^6967

否(由我们定义)

cloudbalancing

trafficing Salesman

1 个实体类

(1 个链变量)

实体 IANA 980

980

搜索空间 10^2504

unrealistic TSP web

tsp

Dinnerparty

1 个实体类

(1 个变量)

实体 144

72

搜索空间 10^310

unrealistic

dinnerParty

Tennis club 调度

1 个实体类

(1 个变量)

实体 72

值 IANA 7

搜索空间 10^60

否(由我们定义)

tennis

会议调度

1 个实体类

(2 个变量)

实体关联 10

320 和 IANA 5

搜索空间 10^320

否(由我们定义)

会议计划

类时间设置

1 个实体类

(2 个变量)

实体 IANA 434

值 IANA 25 和 IANA 20

搜索空间 10^1171

ITC 2007 跟踪 3

curriculumCourse

机器重新分配

1 个实体类

(1 个变量)

实体为 50000

值 IANA 5000

搜索空间 10^184948

最近迁移的 ROADEF 2012

machineReassignment

vehicle 路由

1 个实体类

(1 个链变量)

1 个影子实体类

(1 自动影子变量)

实体 IANA 2740

值 IANA 2795

搜索空间 10^8380

非弹性 VRP Web

vehiclerouting

带有时间窗的 vehicle 路由

所有 Vehicle 路由

(1 shadow 变量)

实体 IANA 2740

值 IANA 2795

搜索空间 10^8380

非弹性 VRP Web

vehiclerouting

项目作业调度

1 个实体类

(2 个变量)

(1 shadow 变量)

实体为 640

值 IANA ? 和 IANA ?

搜索空格

近远的 MISTA 2013

projectjobscheduling

任务分配

1 个实体类

(1 个链变量)

(1 shadow 变量)

1 个影子实体类

(1 自动影子变量)

实体为 500

520

搜索空间 10^1168

没有定义

taskassigning

评估时间设置

2 个实体类(相同层次结构)

(2 个变量)

实体为 1096

值 IANA 80 和 IANA 49

搜索空间 10^3374

ITC 2007 跟踪 1

考试

Nurse rostering

1 个实体类

(1 个变量)

实体为 752

值 IANA 50

搜索空间 10^1277

2010 年 10 月 11 日

nurserostering

趋势

1 个实体类

(1 个变量)

实体 1560

78

搜索空间 10^2301

unrealistic TTP

trafficingtournament

更便宜的时间调度

1 个实体类

(2 个变量)

实体为 500

值 IANA 100 和 IANA 288

搜索空间 10^20078

近似的 ICONHQ

cheaptimescheduling

参与

1 个实体类

(1 个变量)

实体关联 11

value = 1000

搜索空间 10^4

没有定义

参与

指导调度

1 个实体类

(2 个变量)

实体 IANA 216

值 IANA 18 和 IANA 20

搜索空间 10^552

没有定义

指导调度

rock 导览

1 个实体类

(1 个链变量)

(4 影子变量)

1 个影子实体类

(1 自动影子变量)

实体依赖项 47

值 IANA 48

搜索空间 10^59

没有定义

rocktour

飞行人员的调度

1 个实体类

(1 个变量)

1 个影子实体类

(1 自动影子变量)

实体 4375

750

搜索空间 10^12578

没有定义

flightcrewscheduling

4.3. N queens

n queens 放在 n 大小的 chessboard 中,因此不会相互攻击两个 queens。最常见的 n queens puzzle 是 8 个 queens puzzle,带有 n = 8

nQueensScreenshot

约束:

  • 使用 n 列的数量和 n 行。
  • n queens 放在按板上。
  • 没有两个 queens 可以相互攻击。queen 可以对同一水平、垂直或 diagonal 行的任何其他 queen 攻击。

本文档主要使用 4 queens puzzle 作为主要示例。

建议的解决方案可以是:

图 4.1. Four queens puzzle 的一个错误的解决方案

partiallySolvedNQueens04Explained

以上解决方案是错误,因为 queens A1B0 可以相互攻击(因此可能会 queens B0D0)。删除 queen B0 会遵循 "no two queens 可相互攻击"约束,但会破坏 "place n queens" 约束。

以下是正确的解决方案:

图 4.2. Four queens puzzle 的正确解决方案

solvedNQueens04

所有约束都已满足,因此解决方案正确。

请注意,大多数 queens puzzles 具有多个正确的解决方案。我们将专注于查找给定 n 的正确解决方案,而不是查找给定 n 可能的正确解决方案数量。

问题大小

4queens   has   4 queens with a search space of    256.
8queens   has   8 queens with a search space of   10^7.
16queens  has  16 queens with a search space of  10^19.
32queens  has  32 queens with a search space of  10^48.
64queens  has  64 queens with a search space of 10^115.
256queens has 256 queens with a search space of 10^616.
Copy to Clipboard

n queens 示例的实现尚未优化,因为它作为 beginner 示例。然而,它可以轻松地处理 64 queens。通过一些更改,它已被显示,可以轻松地处理 5000 queens 等。

4.3.1. N queens 的域模型

本例使用域模型来解决四个 queens 问题。

  • 创建域模型

    良好的域模型将更方便地理解并解决您的规划问题。

    这是 n queens 示例的域模型:

    public class Column {
    
        private int index;
    
        // ... getters and setters
    }
    Copy to Clipboard
    public class Row {
    
        private int index;
    
        // ... getters and setters
    }
    Copy to Clipboard
    public class Queen {
    
        private Column column;
        private Row row;
    
        public int getAscendingDiagonalIndex() {...}
        public int getDescendingDiagonalIndex() {...}
    
        // ... getters and setters
    }
    Copy to Clipboard
  • 计算搜索空间.

    Queen 实例有一个 Column (例如: 0 是列 A, 1 is column B, …​) 和一个 Row (例如,0 为行 0,1 为行 1, …​)。

    根据列和行计算升序行和降序行。

    列和行索引从小时的左上角开始。

    public class NQueens {
    
        private int n;
        private List<Column> columnList;
        private List<Row> rowList;
    
        private List<Queen> queenList;
    
        private SimpleScore score;
    
        // ... getters and setters
    }
    Copy to Clipboard
    1. 查找解决方案

      单个 NQueens 实例包含所有 Queen 实例的列表。它是 解决方案 实现,它将由 Solver 提供、解决并从 Solver 检索。

请注意,在四个 queens 示例中,NQueens 的 getN () 方法始终返回四个。

图 4.3. Four Queens 的解决方案

partiallySolvedNQueens04Explained
表 4.2. 域模型中解决方案详情
 columnIndexrowIndexascendingDiagonalIndex (columnIndex + rowIndex)descendingDiagonalIndex (columnIndex - rowIndex)

A1

0

1

1 (**)

-1

B0

1

0 (*)

1 (**)

1

C2

2

2

4

0

D0

3

0 (*)

3

3

当两个 queens 共享相同的列时,行或 diagonal 行(如 ASP 和(DSL))可以相互攻击。

4.4. Cloud balancing

有关本例的详情请参考 第 3 章 Java solvers 入门:云供应商示例

4.5. Tending Salesman (TSP - 指导销售问题)

给定一个城市列表,找到一次访问每个城市的 Salesman 最旧的导览。

问题由 Wikipedia 定义。它是计算数学 中最严重的问题之一。然而,在现实环境中,它通常只是规划问题的一部分,以及其他限制,如员工的过渡限制。

问题大小

dj38     has  38 cities with a search space of   10^43.
europe40 has  40 cities with a search space of   10^46.
st70     has  70 cities with a search space of   10^98.
pcb442   has 442 cities with a search space of  10^976.
lu980    has 980 cities with a search space of 10^2504.
Copy to Clipboard

问题困难

尽管 TSP 的简单定义,但问题难以解决。因为这是一个 NP 硬问题(如大多数计划问题),因此特定问题数据集的最佳解决方案可能会在对问题数据集稍有变化时改变:

tspOptimalSolutionVolatility

4.6. Dinnerparty

miss Manners 将抛出另一个危险方。

  • 这一次,她邀请了 144 个客户机,并为每个机器准备 12 个轮循表。
  • 每个客户机都应该位于相反条目的人员(左和右)旁边。
  • 邻居应该至少有一个 hobby 与客户机通用。
  • 在每个表格中,应当有两个策略:两个 doctors、两个社交、两个商标、两个公司和两个公司。
  • 两个策略:两个 doctors、两个 coaches 和两个公司在表上不能相同。

dolss Manners 也是常规的 Miss Manners 示例(这很小),并采用一种更严格的措施来解决它。规划器的实施更加可扩展,因为它使用 heuristics 来查找最佳解决方案,以及 drools 计算每个解决方案的分数。

问题大小

wedding01 has 18 jobs, 144 guests, 288 hobby practicians, 12 tables and 144 seats with a search space of 10^310.
Copy to Clipboard

4.7. Tennis club 调度

每周 10nis club 都有四个团队相互活跃循环。为团队分配这四个点。

硬限制:

  • 冲突 :团队一次只能播放一次。
  • 不可用:有些团队在某些情况下不可用。

中等限制:

  • 公平分配:所有团队都应该扮演了相等的次数。

软限制:

  • 平均聚合:每个团队都应该在其他团队中达到相等次数。

问题大小

munich-7teams has 7 teams, 18 days, 12 unavailabilityPenalties and 72 teamAssignments with a search space of 10^60.
Copy to Clipboard

图 4.4. 域模型

tennisClassDiagram

4.8. 会议调度

为开始时间和房间分配每个会议。会议具有不同的持续时间。

硬限制:

  • 房间冲突:两个会议不得同时使用同一空间。
  • 需要的参与:人无法同时拥有两个需要满足的会议。
  • 需要的房间容量: 会议不能处于不满足所有会议的房间。
  • 在同一天开始和结束:该会议不应多次调度。

中等限制:

  • 首选参与:人不能同时拥有两种偏好会议,也不能同时具有首选和必需的会议。

软限制:

  • 更早的时间,而不是之后:尽快调度所有会议。
  • 会议间的中断:任何两个会议都应该至少有一个时间中断。
  • 重叠的会议:为了最大程度减少并行会议的数量,因此用户不必选择另一个会议。
  • 首先分配更大的空间:如果一个更大的空间可用,则应给这一房间分配任何会议,以便满足尽可能多的人,即使他们尚未注册该会议。
  • 房间稳定性:如果人连续满足两个或更短的时间中断,则他们最好处于同一间。

问题大小

50meetings-160timegrains-5rooms  has  50 meetings, 160 timeGrains and 5 rooms with a search space of 10^145.
100meetings-320timegrains-5rooms has 100 meetings, 320 timeGrains and 5 rooms with a search space of 10^320.
200meetings-640timegrains-5rooms has 200 meetings, 640 timeGrains and 5 rooms with a search space of 10^701.
400meetings-1280timegrains-5rooms has 400 meetings, 1280 timeGrains and 5 rooms with a search space of 10^1522.
800meetings-2560timegrains-5rooms has 800 meetings, 2560 timeGrains and 5 rooms with a search space of 10^3285.
Copy to Clipboard

4.9. 课程时间设置(ITC 2007 Track 3 - Curriculum 时间表)

将每位安排成一个 timeslot 并放入一个房间。

硬限制:

  • 竞争器冲突:通常不能在同一时间段内有两个竞争。
  • 领导冲突:通常不能在同一时间段内有两个竞争。
  • 空间 occupancy:两个公司不能在同一时间内位于同一空间中。
  • 不可用周期(为每个数据集指定):特定持久性不能分配给特定的周期。

软限制:

  • 房间容量: 房间的容量不应小于其领导活动数量。
  • 最小工作天数:同一课程的显示应被分成最少的天数。
  • 领导压缩性:属于同一技术的视图应相互相邻(在连续的时间段内)。
  • 房间稳定性:同一课程的了解应分配给同一房。

这个问题由 国际时间建立复合的 Competition 2007 跟踪 3 定义。

问题大小

comp01 has 24 teachers,  14 curricula,  30 courses, 160 lectures, 30 periods,  6 rooms and   53 unavailable period constraints with a search space of  10^360.
comp02 has 71 teachers,  70 curricula,  82 courses, 283 lectures, 25 periods, 16 rooms and  513 unavailable period constraints with a search space of  10^736.
comp03 has 61 teachers,  68 curricula,  72 courses, 251 lectures, 25 periods, 16 rooms and  382 unavailable period constraints with a search space of  10^653.
comp04 has 70 teachers,  57 curricula,  79 courses, 286 lectures, 25 periods, 18 rooms and  396 unavailable period constraints with a search space of  10^758.
comp05 has 47 teachers, 139 curricula,  54 courses, 152 lectures, 36 periods,  9 rooms and  771 unavailable period constraints with a search space of  10^381.
comp06 has 87 teachers,  70 curricula, 108 courses, 361 lectures, 25 periods, 18 rooms and  632 unavailable period constraints with a search space of  10^957.
comp07 has 99 teachers,  77 curricula, 131 courses, 434 lectures, 25 periods, 20 rooms and  667 unavailable period constraints with a search space of 10^1171.
comp08 has 76 teachers,  61 curricula,  86 courses, 324 lectures, 25 periods, 18 rooms and  478 unavailable period constraints with a search space of  10^859.
comp09 has 68 teachers,  75 curricula,  76 courses, 279 lectures, 25 periods, 18 rooms and  405 unavailable period constraints with a search space of  10^740.
comp10 has 88 teachers,  67 curricula, 115 courses, 370 lectures, 25 periods, 18 rooms and  694 unavailable period constraints with a search space of  10^981.
comp11 has 24 teachers,  13 curricula,  30 courses, 162 lectures, 45 periods,  5 rooms and   94 unavailable period constraints with a search space of  10^381.
comp12 has 74 teachers, 150 curricula,  88 courses, 218 lectures, 36 periods, 11 rooms and 1368 unavailable period constraints with a search space of  10^566.
comp13 has 77 teachers,  66 curricula,  82 courses, 308 lectures, 25 periods, 19 rooms and  468 unavailable period constraints with a search space of  10^824.
comp14 has 68 teachers,  60 curricula,  85 courses, 275 lectures, 25 periods, 17 rooms and  486 unavailable period constraints with a search space of  10^722.
Copy to Clipboard

图 4.5. 域模型

curriculumCourseClassDiagram

4.10. 机器重新分配(Google ROADEF 2012)

为机器分配每个进程。所有进程都已有原始(未优化)分配。每个进程都需要每个资源(如 CPU 或 RAM)的数量。这是 Cloud Balancing 示例的复杂版本。

硬限制:

  • 最大容量 :不得超过每台机器的每个资源的最大容量。
  • 冲突:同一服务的处理必须在不同的计算机上运行。
  • 分散:同一服务的处理必须在位置之间分散。
  • dependencies :根据另一个服务,服务的进程必须在其他服务进程的邻居运行。
  • 临时使用:有些资源是临时的,是原始机器作为新分配的机器的最大容量。

软限制:

  • load :不应超过每台机器的每个资源的安全容量。
  • Balance :通过平衡每台计算机上的可用资源来保留将来分配的空间。
  • 流程移动成本:流程有移动成本。
  • 服务移动成本:服务具有移动成本。
  • 机器移动成本:将进程从机器 A 移动到机器 B 具有另一个 A-B 的移动成本。

这个问题由 Google ROADEF/EURO Challenge 2012 定义。

cloudOptimizationIsLikeTetris

图 4.6. 价值

cloudOptimizationValueProposition

问题大小

model_a1_1 has  2 resources,  1 neighborhoods,   4 locations,    4 machines,    79 services,   100 processes and 1 balancePenalties with a search space of     10^60.
model_a1_2 has  4 resources,  2 neighborhoods,   4 locations,  100 machines,   980 services,  1000 processes and 0 balancePenalties with a search space of   10^2000.
model_a1_3 has  3 resources,  5 neighborhoods,  25 locations,  100 machines,   216 services,  1000 processes and 0 balancePenalties with a search space of   10^2000.
model_a1_4 has  3 resources, 50 neighborhoods,  50 locations,   50 machines,   142 services,  1000 processes and 1 balancePenalties with a search space of   10^1698.
model_a1_5 has  4 resources,  2 neighborhoods,   4 locations,   12 machines,   981 services,  1000 processes and 1 balancePenalties with a search space of   10^1079.
model_a2_1 has  3 resources,  1 neighborhoods,   1 locations,  100 machines,  1000 services,  1000 processes and 0 balancePenalties with a search space of   10^2000.
model_a2_2 has 12 resources,  5 neighborhoods,  25 locations,  100 machines,   170 services,  1000 processes and 0 balancePenalties with a search space of   10^2000.
model_a2_3 has 12 resources,  5 neighborhoods,  25 locations,  100 machines,   129 services,  1000 processes and 0 balancePenalties with a search space of   10^2000.
model_a2_4 has 12 resources,  5 neighborhoods,  25 locations,   50 machines,   180 services,  1000 processes and 1 balancePenalties with a search space of   10^1698.
model_a2_5 has 12 resources,  5 neighborhoods,  25 locations,   50 machines,   153 services,  1000 processes and 0 balancePenalties with a search space of   10^1698.
model_b_1  has 12 resources,  5 neighborhoods,  10 locations,  100 machines,  2512 services,  5000 processes and 0 balancePenalties with a search space of  10^10000.
model_b_2  has 12 resources,  5 neighborhoods,  10 locations,  100 machines,  2462 services,  5000 processes and 1 balancePenalties with a search space of  10^10000.
model_b_3  has  6 resources,  5 neighborhoods,  10 locations,  100 machines, 15025 services, 20000 processes and 0 balancePenalties with a search space of  10^40000.
model_b_4  has  6 resources,  5 neighborhoods,  50 locations,  500 machines,  1732 services, 20000 processes and 1 balancePenalties with a search space of  10^53979.
model_b_5  has  6 resources,  5 neighborhoods,  10 locations,  100 machines, 35082 services, 40000 processes and 0 balancePenalties with a search space of  10^80000.
model_b_6  has  6 resources,  5 neighborhoods,  50 locations,  200 machines, 14680 services, 40000 processes and 1 balancePenalties with a search space of  10^92041.
model_b_7  has  6 resources,  5 neighborhoods,  50 locations, 4000 machines, 15050 services, 40000 processes and 1 balancePenalties with a search space of 10^144082.
model_b_8  has  3 resources,  5 neighborhoods,  10 locations,  100 machines, 45030 services, 50000 processes and 0 balancePenalties with a search space of 10^100000.
model_b_9  has  3 resources,  5 neighborhoods, 100 locations, 1000 machines,  4609 services, 50000 processes and 1 balancePenalties with a search space of 10^150000.
model_b_10 has  3 resources,  5 neighborhoods, 100 locations, 5000 machines,  4896 services, 50000 processes and 1 balancePenalties with a search space of 10^184948.
Copy to Clipboard

图 4.7. 域模型

machineReassignmentClassDiagram

4.11. vehicle 路由

使用一组电话,获取每个客户的对象并将其带入耗尽。每个 vehicle 都可以为多个客户提供服务,但它有有限的容量。

vehicleRoutingUseCase

除了基本问题单(CVRP)外,还有一个带有时间窗(CVRPTW)的变体。

硬限制:

  • vehicle 容量: vehicle 无法执行更多项目,然后其容量。
  • 时间窗(只在 CVRPTW 中):

    • 轮转时间:从一个位置传输到另一个地方需要时间。
    • 客户服务持续时间:在服务持续时间内,载体必须保持客户。
    • 客户就绪时间: vehicle 可在客户就绪时间之前到达,但必须在服务前等待到就绪的时间。
    • 客户到期时间:在客户到期之前,一个电话必须及时到达。

软限制:

  • 总距离:最小化所有电池的总距离头(fuel 消耗)。

分配的载体路由问题(CVRP)及其时间窗口变体(CVRPTW)由 VRP web 定义。

图 4.8. 价值

vehicleRoutingValueProposition

问题大小

CVRP 实例(没有时间窗):

belgium-n50-k10             has  1 depots, 10 vehicles and   49 customers with a search space of   10^74.
belgium-n100-k10            has  1 depots, 10 vehicles and   99 customers with a search space of  10^170.
belgium-n500-k20            has  1 depots, 20 vehicles and  499 customers with a search space of 10^1168.
belgium-n1000-k20           has  1 depots, 20 vehicles and  999 customers with a search space of 10^2607.
belgium-n2750-k55           has  1 depots, 55 vehicles and 2749 customers with a search space of 10^8380.
belgium-road-km-n50-k10     has  1 depots, 10 vehicles and   49 customers with a search space of   10^74.
belgium-road-km-n100-k10    has  1 depots, 10 vehicles and   99 customers with a search space of  10^170.
belgium-road-km-n500-k20    has  1 depots, 20 vehicles and  499 customers with a search space of 10^1168.
belgium-road-km-n1000-k20   has  1 depots, 20 vehicles and  999 customers with a search space of 10^2607.
belgium-road-km-n2750-k55   has  1 depots, 55 vehicles and 2749 customers with a search space of 10^8380.
belgium-road-time-n50-k10   has  1 depots, 10 vehicles and   49 customers with a search space of   10^74.
belgium-road-time-n100-k10  has  1 depots, 10 vehicles and   99 customers with a search space of  10^170.
belgium-road-time-n500-k20  has  1 depots, 20 vehicles and  499 customers with a search space of 10^1168.
belgium-road-time-n1000-k20 has  1 depots, 20 vehicles and  999 customers with a search space of 10^2607.
belgium-road-time-n2750-k55 has  1 depots, 55 vehicles and 2749 customers with a search space of 10^8380.
belgium-d2-n50-k10          has  2 depots, 10 vehicles and   48 customers with a search space of   10^74.
belgium-d3-n100-k10         has  3 depots, 10 vehicles and   97 customers with a search space of  10^170.
belgium-d5-n500-k20         has  5 depots, 20 vehicles and  495 customers with a search space of 10^1168.
belgium-d8-n1000-k20        has  8 depots, 20 vehicles and  992 customers with a search space of 10^2607.
belgium-d10-n2750-k55       has 10 depots, 55 vehicles and 2740 customers with a search space of 10^8380.

A-n32-k5  has 1 depots,  5 vehicles and  31 customers with a search space of  10^40.
A-n33-k5  has 1 depots,  5 vehicles and  32 customers with a search space of  10^41.
A-n33-k6  has 1 depots,  6 vehicles and  32 customers with a search space of  10^42.
A-n34-k5  has 1 depots,  5 vehicles and  33 customers with a search space of  10^43.
A-n36-k5  has 1 depots,  5 vehicles and  35 customers with a search space of  10^46.
A-n37-k5  has 1 depots,  5 vehicles and  36 customers with a search space of  10^48.
A-n37-k6  has 1 depots,  6 vehicles and  36 customers with a search space of  10^49.
A-n38-k5  has 1 depots,  5 vehicles and  37 customers with a search space of  10^49.
A-n39-k5  has 1 depots,  5 vehicles and  38 customers with a search space of  10^51.
A-n39-k6  has 1 depots,  6 vehicles and  38 customers with a search space of  10^52.
A-n44-k7  has 1 depots,  7 vehicles and  43 customers with a search space of  10^61.
A-n45-k6  has 1 depots,  6 vehicles and  44 customers with a search space of  10^62.
A-n45-k7  has 1 depots,  7 vehicles and  44 customers with a search space of  10^63.
A-n46-k7  has 1 depots,  7 vehicles and  45 customers with a search space of  10^65.
A-n48-k7  has 1 depots,  7 vehicles and  47 customers with a search space of  10^68.
A-n53-k7  has 1 depots,  7 vehicles and  52 customers with a search space of  10^77.
A-n54-k7  has 1 depots,  7 vehicles and  53 customers with a search space of  10^79.
A-n55-k9  has 1 depots,  9 vehicles and  54 customers with a search space of  10^82.
A-n60-k9  has 1 depots,  9 vehicles and  59 customers with a search space of  10^91.
A-n61-k9  has 1 depots,  9 vehicles and  60 customers with a search space of  10^93.
A-n62-k8  has 1 depots,  8 vehicles and  61 customers with a search space of  10^94.
A-n63-k9  has 1 depots,  9 vehicles and  62 customers with a search space of  10^97.
A-n63-k10 has 1 depots, 10 vehicles and  62 customers with a search space of  10^98.
A-n64-k9  has 1 depots,  9 vehicles and  63 customers with a search space of  10^99.
A-n65-k9  has 1 depots,  9 vehicles and  64 customers with a search space of 10^101.
A-n69-k9  has 1 depots,  9 vehicles and  68 customers with a search space of 10^108.
A-n80-k10 has 1 depots, 10 vehicles and  79 customers with a search space of 10^130.
F-n45-k4  has 1 depots,  4 vehicles and  44 customers with a search space of  10^60.
F-n72-k4  has 1 depots,  4 vehicles and  71 customers with a search space of 10^108.
F-n135-k7 has 1 depots,  7 vehicles and 134 customers with a search space of 10^240.
Copy to Clipboard

CVRPTW 实例(使用时间窗):

belgium-tw-d2-n50-k10    has  2 depots, 10 vehicles and   48 customers with a search space of   10^74.
belgium-tw-d3-n100-k10   has  3 depots, 10 vehicles and   97 customers with a search space of  10^170.
belgium-tw-d5-n500-k20   has  5 depots, 20 vehicles and  495 customers with a search space of 10^1168.
belgium-tw-d8-n1000-k20  has  8 depots, 20 vehicles and  992 customers with a search space of 10^2607.
belgium-tw-d10-n2750-k55 has 10 depots, 55 vehicles and 2740 customers with a search space of 10^8380.
belgium-tw-n50-k10       has  1 depots, 10 vehicles and   49 customers with a search space of   10^74.
belgium-tw-n100-k10      has  1 depots, 10 vehicles and   99 customers with a search space of  10^170.
belgium-tw-n500-k20      has  1 depots, 20 vehicles and  499 customers with a search space of 10^1168.
belgium-tw-n1000-k20     has  1 depots, 20 vehicles and  999 customers with a search space of 10^2607.
belgium-tw-n2750-k55     has  1 depots, 55 vehicles and 2749 customers with a search space of 10^8380.

Solomon_025_C101       has 1 depots,  25 vehicles and   25 customers with a search space of   10^40.
Solomon_025_C201       has 1 depots,  25 vehicles and   25 customers with a search space of   10^40.
Solomon_025_R101       has 1 depots,  25 vehicles and   25 customers with a search space of   10^40.
Solomon_025_R201       has 1 depots,  25 vehicles and   25 customers with a search space of   10^40.
Solomon_025_RC101      has 1 depots,  25 vehicles and   25 customers with a search space of   10^40.
Solomon_025_RC201      has 1 depots,  25 vehicles and   25 customers with a search space of   10^40.
Solomon_100_C101       has 1 depots,  25 vehicles and  100 customers with a search space of  10^185.
Solomon_100_C201       has 1 depots,  25 vehicles and  100 customers with a search space of  10^185.
Solomon_100_R101       has 1 depots,  25 vehicles and  100 customers with a search space of  10^185.
Solomon_100_R201       has 1 depots,  25 vehicles and  100 customers with a search space of  10^185.
Solomon_100_RC101      has 1 depots,  25 vehicles and  100 customers with a search space of  10^185.
Solomon_100_RC201      has 1 depots,  25 vehicles and  100 customers with a search space of  10^185.
Homberger_0200_C1_2_1  has 1 depots,  50 vehicles and  200 customers with a search space of  10^429.
Homberger_0200_C2_2_1  has 1 depots,  50 vehicles and  200 customers with a search space of  10^429.
Homberger_0200_R1_2_1  has 1 depots,  50 vehicles and  200 customers with a search space of  10^429.
Homberger_0200_R2_2_1  has 1 depots,  50 vehicles and  200 customers with a search space of  10^429.
Homberger_0200_RC1_2_1 has 1 depots,  50 vehicles and  200 customers with a search space of  10^429.
Homberger_0200_RC2_2_1 has 1 depots,  50 vehicles and  200 customers with a search space of  10^429.
Homberger_0400_C1_4_1  has 1 depots, 100 vehicles and  400 customers with a search space of  10^978.
Homberger_0400_C2_4_1  has 1 depots, 100 vehicles and  400 customers with a search space of  10^978.
Homberger_0400_R1_4_1  has 1 depots, 100 vehicles and  400 customers with a search space of  10^978.
Homberger_0400_R2_4_1  has 1 depots, 100 vehicles and  400 customers with a search space of  10^978.
Homberger_0400_RC1_4_1 has 1 depots, 100 vehicles and  400 customers with a search space of  10^978.
Homberger_0400_RC2_4_1 has 1 depots, 100 vehicles and  400 customers with a search space of  10^978.
Homberger_0600_C1_6_1  has 1 depots, 150 vehicles and  600 customers with a search space of 10^1571.
Homberger_0600_C2_6_1  has 1 depots, 150 vehicles and  600 customers with a search space of 10^1571.
Homberger_0600_R1_6_1  has 1 depots, 150 vehicles and  600 customers with a search space of 10^1571.
Homberger_0600_R2_6_1  has 1 depots, 150 vehicles and  600 customers with a search space of 10^1571.
Homberger_0600_RC1_6_1 has 1 depots, 150 vehicles and  600 customers with a search space of 10^1571.
Homberger_0600_RC2_6_1 has 1 depots, 150 vehicles and  600 customers with a search space of 10^1571.
Homberger_0800_C1_8_1  has 1 depots, 200 vehicles and  800 customers with a search space of 10^2195.
Homberger_0800_C2_8_1  has 1 depots, 200 vehicles and  800 customers with a search space of 10^2195.
Homberger_0800_R1_8_1  has 1 depots, 200 vehicles and  800 customers with a search space of 10^2195.
Homberger_0800_R2_8_1  has 1 depots, 200 vehicles and  800 customers with a search space of 10^2195.
Homberger_0800_RC1_8_1 has 1 depots, 200 vehicles and  800 customers with a search space of 10^2195.
Homberger_0800_RC2_8_1 has 1 depots, 200 vehicles and  800 customers with a search space of 10^2195.
Homberger_1000_C110_1  has 1 depots, 250 vehicles and 1000 customers with a search space of 10^2840.
Homberger_1000_C210_1  has 1 depots, 250 vehicles and 1000 customers with a search space of 10^2840.
Homberger_1000_R110_1  has 1 depots, 250 vehicles and 1000 customers with a search space of 10^2840.
Homberger_1000_R210_1  has 1 depots, 250 vehicles and 1000 customers with a search space of 10^2840.
Homberger_1000_RC110_1 has 1 depots, 250 vehicles and 1000 customers with a search space of 10^2840.
Homberger_1000_RC210_1 has 1 depots, 250 vehicles and 1000 customers with a search space of 10^2840.
Copy to Clipboard

4.11.1. Vehicle 路由的域模型

vehicleRoutingClassDiagram

带有 timewindows 域模型的 vehicle 路由大量使用 shadow 变量功能。这允许它更自然地表达限制,因为 arrivalTimedepartureTime 等属性直接在域模型中可用。

临时区分无线差异

在真实世界中,vehicles 不能从位置到位置跟随行:它们必须使用 roads 和 highways。从一个角度来说,这很重要:

vehicleRoutingDistanceType

对于优化算法,只要可以查找两个点之间的距离(最好是预先计算)。恶意成本甚至不需要是一个距离,它也有可能是大量时间、成本或加权功能。一些技术可用于预先计算 road 成本,如 GraphHopper (embeddable, offline Java engine), Open MapQuest (web service)和 Google Maps Client API (web service)。

integrationWithRealMaps

另外,还有一些技术来呈现它,如 开发人员的 Leaflet 和 Google Maps:Opt aplan ner-webexamples047.war 有一个示例,它演示了这样的渲染:

vehicleRoutingLeafletAndGoogleMaps

甚至可以使用 GraphHopper 或 Google Map Directions 呈现实际 road 路由,但由于路由对高路重叠,看不到顺序:

vehicleRoutingGoogleMapsDirections

请特别注意两个点之间的 road 成本与 Planner 中使用的优化标准相同。例如,GraphHopper 等默认返回最快的路由,而不是最短的路由。不要使用更快的 GPS 路由的 km (或 miles)距离来优化 Planner 中最短的往返:这会导致子优化解决方案,如下所示:

roadDistanceTriangleInequality

与流行不同,大多数用户都不希望使用最短的路由:他们希望使用最快的路由。它们更喜欢通常高路。它们更喜欢在 dirt roads 上正常的 roads。在现实环境中,最快速且最短的路由很少相同。

4.12. 项目作业调度

以时间和执行模式调度所有作业,以最小化项目延迟。每个作业都是项目的一部分。作业可以以不同的方式执行:每种方法是执行模式,它意味着不同的持续时间,但也不同的资源使用量。这是灵活的 作业跃点调度的形式

projectJobSchedulingUseCase

硬限制:

  • 作业优先级:只有所有前者作业都完成时,才可以启动作业。
  • 资源容量:不使用超过可用资源的资源。

    • 资源是本地的(同一项目的作业之间共享)或全局(在所有作业之间共享)
    • 资源是可续订(每天可用的容量)或不可续订(可续订的容量)

中等限制:

  • 项目总延迟:最小化每个项目的持续时间(makespan)。

软限制:

  • Total makespan:最小化整个多项目调度的持续时间。

这个问题由 MISTA 2013 挑战 定义。

问题大小

Schedule A-1  has  2 projects,  24 jobs,   64 execution modes,  7 resources and  150 resource requirements.
Schedule A-2  has  2 projects,  44 jobs,  124 execution modes,  7 resources and  420 resource requirements.
Schedule A-3  has  2 projects,  64 jobs,  184 execution modes,  7 resources and  630 resource requirements.
Schedule A-4  has  5 projects,  60 jobs,  160 execution modes, 16 resources and  390 resource requirements.
Schedule A-5  has  5 projects, 110 jobs,  310 execution modes, 16 resources and  900 resource requirements.
Schedule A-6  has  5 projects, 160 jobs,  460 execution modes, 16 resources and 1440 resource requirements.
Schedule A-7  has 10 projects, 120 jobs,  320 execution modes, 22 resources and  900 resource requirements.
Schedule A-8  has 10 projects, 220 jobs,  620 execution modes, 22 resources and 1860 resource requirements.
Schedule A-9  has 10 projects, 320 jobs,  920 execution modes, 31 resources and 2880 resource requirements.
Schedule A-10 has 10 projects, 320 jobs,  920 execution modes, 31 resources and 2970 resource requirements.
Schedule B-1  has 10 projects, 120 jobs,  320 execution modes, 31 resources and  900 resource requirements.
Schedule B-2  has 10 projects, 220 jobs,  620 execution modes, 22 resources and 1740 resource requirements.
Schedule B-3  has 10 projects, 320 jobs,  920 execution modes, 31 resources and 3060 resource requirements.
Schedule B-4  has 15 projects, 180 jobs,  480 execution modes, 46 resources and 1530 resource requirements.
Schedule B-5  has 15 projects, 330 jobs,  930 execution modes, 46 resources and 2760 resource requirements.
Schedule B-6  has 15 projects, 480 jobs, 1380 execution modes, 46 resources and 4500 resource requirements.
Schedule B-7  has 20 projects, 240 jobs,  640 execution modes, 61 resources and 1710 resource requirements.
Schedule B-8  has 20 projects, 440 jobs, 1240 execution modes, 42 resources and 3180 resource requirements.
Schedule B-9  has 20 projects, 640 jobs, 1840 execution modes, 61 resources and 5940 resource requirements.
Schedule B-10 has 20 projects, 460 jobs, 1300 execution modes, 42 resources and 4260 resource requirements.
Copy to Clipboard

4.13. 任务分配

将每个任务分配给员工队列中的 spot。每个任务都有一个持续时间,该持续时间会受到员工对任务的关联性级别的影响。

硬限制:

  • 行业:每个任务都需要一个或多个学习。员工必须拥有所有这些知识。

软级别 0 限制:

  • 关键任务:首先完成关键任务,早于主要和次要任务。

软级别 1 限制:

  • 最小化 makespan:缩短时间完成所有任务。

    • 首先,从最多的工作员工开始,再开始第二个工作员工,以创建公平和负载平衡。

软级别 2 约束:

  • 主要任务:尽快完成主要任务,早于次要任务。

软级别 3 限制:

  • 次要任务:尽快完成次要任务。

图 4.9. 价值

taskAssigningValueProposition

问题大小

24tasks-8employees   has  24 tasks, 6 skills,  8 employees,   4 task types and  4 customers with a search space of   10^30.
50tasks-5employees   has  50 tasks, 5 skills,  5 employees,  10 task types and 10 customers with a search space of   10^69.
100tasks-5employees  has 100 tasks, 5 skills,  5 employees,  20 task types and 15 customers with a search space of  10^164.
500tasks-20employees has 500 tasks, 6 skills, 20 employees, 100 task types and 60 customers with a search space of 10^1168.
Copy to Clipboard

图 4.10. 域模型

taskAssigningClassDiagram

4.14. 评估时间设置(ITC 2007 跟踪 1 - 评估)

将每个课程计划到一个句点,并放入一个房间。多个公司可以同时共享同一房。

examinationTimetablingUseCase

硬限制:

  • 评估冲突:不能在同一时间段内同时发生共享参与的两个技术。
  • 房间容量 :房间的容量必须始终足够高。
  • 持续时间: 周期的持续时间必须足以满足其所有销售期。
  • 与周期相关的硬限制(按数据集指定):

    • coincidence:两个指定的参与必须使用相同的句点(但可能为其他房间)。
    • 排除:两个指定的参与不得同时使用同一周期。
    • 之后:在另一个指定测试期后,必须在一个时间段内进行指定的考试。
  • 与空间相关的硬限制(每个数据集指定):

    • exclusive:一个指定的基准测试不必与任何其他课程共享其房间。

软限制(其中每个都具有参数损失):

  • 同一站不应在一行中有两个。
  • 同一成员不应在同一天上有两个活动。
  • 周期分布:共享的参与应是多个句点。
  • 混合持续时间:共享一个房间不应具有不同的持续时间。
  • 前端负载:在计划早期应该调度大量时间。
  • 周期损失(指定每个数据集):一些周期在使用时都有损失。
  • 空间损失(指定每个数据集):一些空间在使用时有损失。

它使用大量实际生命常量集。

这个问题由 国际时间建立复杂时间定义,即 2007 跟踪 1。Geoffrey De Smet 完成 4th,与非常早的 Planner 版本合作。因此,进行很多改进。

问题大小

exam_comp_set1 has  7883 students,  607 exams, 54 periods,  7 rooms,  12 period constraints and  0 room constraints with a search space of 10^1564.
exam_comp_set2 has 12484 students,  870 exams, 40 periods, 49 rooms,  12 period constraints and  2 room constraints with a search space of 10^2864.
exam_comp_set3 has 16365 students,  934 exams, 36 periods, 48 rooms, 168 period constraints and 15 room constraints with a search space of 10^3023.
exam_comp_set4 has  4421 students,  273 exams, 21 periods,  1 rooms,  40 period constraints and  0 room constraints with a search space of  10^360.
exam_comp_set5 has  8719 students, 1018 exams, 42 periods,  3 rooms,  27 period constraints and  0 room constraints with a search space of 10^2138.
exam_comp_set6 has  7909 students,  242 exams, 16 periods,  8 rooms,  22 period constraints and  0 room constraints with a search space of  10^509.
exam_comp_set7 has 13795 students, 1096 exams, 80 periods, 15 rooms,  28 period constraints and  0 room constraints with a search space of 10^3374.
exam_comp_set8 has  7718 students,  598 exams, 80 periods,  8 rooms,  20 period constraints and  1 room constraints with a search space of 10^1678.
Copy to Clipboard

4.14.1. 用于检查时间设置的域模型

下图显示了主要的评估域类:

图 4.11. 评估域类图

examinationDomainDiagram

请注意,我们已将考试概念分成 考试 课程和主题课程。在解决时(这是计划实体类)的考试实例在它们的期间或房间属性发生变化时发生了变化。主题 PeriodRoom 实例在参与期间永远不会改变(这些是问题事实,就像某些其他类一样)。

4.15. Nurse rostering (INRC 2010)

对于每个转换,请分配一个操作方式进行转换。

employeeShiftRosteringUseCase

硬限制:

  • 没有未分配的 转换(内置):每个转换都需要分配给员工。
  • 移动冲突 :员工每天只能有一个过渡。

软限制:

  • 合同费用。业务经常违反了这些情况,因此他们决定将它们定义为软限制,而非硬限制。

    • 最小和最大分配 :每个员工需要超过 x 过渡,且少于 y 过渡(取决于其合同)。
    • 最小和最大连续工作天数 :每个员工都需要连续在 x 和 y 天之间工作(取决于其合同)。
    • 最小和最大连续的免费天数 :每个员工都需要在 x 到 y 天之间自由使用(取决于其合同)。
    • 最小和最大连续的工作日 :每个员工都需要按行在 x 和 y 周线(取决于其合同)之间工作。
    • 完成 每周:每个员工都需要每天在一周内或根本不工作。
    • 周例期间 的相同迁移类型:对于同一员工的同一周例,每个每周过渡都必须相同。
    • 不支持的模式 :一行中不需要的转换类型的组合。例如:之后移动后接一个早的移动,后接一个晚的移动。
  • 员工希望:

    • 请求的 一天:员工希望在特定日期上工作。
    • 第一天请求 :员工不希望在特定日期上工作。
    • 根据请求迁移 :员工希望分配给特定的移动。
    • 移动请求 :员工不想分配给特定的移动。
  • 备选技术 :分配给专家的员工应该在这一迁移所需的每个技术方面有障碍。

此问题由 国际 Nurse Rostering Competition 2010 定义。

图 4.12. 价值

employeeRosteringValueProposition

问题大小

有三个数据集类型:

  • 过程:必须以秒为单位解决。
  • Medium:必须以分钟为单位解决。
  • 长:必须以小时为单位解决。
toy1          has 1 skills, 3 shiftTypes, 2 patterns, 1 contracts,  6 employees,  7 shiftDates,  35 shiftAssignments and   0 requests with a search space of   10^27.
toy2          has 1 skills, 3 shiftTypes, 3 patterns, 2 contracts, 20 employees, 28 shiftDates, 180 shiftAssignments and 140 requests with a search space of  10^234.

sprint01      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint02      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint03      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint04      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint05      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint06      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint07      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint08      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint09      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint10      has 1 skills, 4 shiftTypes, 3 patterns, 4 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_hint01 has 1 skills, 4 shiftTypes, 8 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_hint02 has 1 skills, 4 shiftTypes, 0 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_hint03 has 1 skills, 4 shiftTypes, 8 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_late01 has 1 skills, 4 shiftTypes, 8 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_late02 has 1 skills, 3 shiftTypes, 4 patterns, 3 contracts, 10 employees, 28 shiftDates, 144 shiftAssignments and 139 requests with a search space of  10^144.
sprint_late03 has 1 skills, 4 shiftTypes, 8 patterns, 3 contracts, 10 employees, 28 shiftDates, 160 shiftAssignments and 150 requests with a search space of  10^160.
sprint_late04 has 1 skills, 4 shiftTypes, 8 patterns, 3 contracts, 10 employees, 28 shiftDates, 160 shiftAssignments and 150 requests with a search space of  10^160.
sprint_late05 has 1 skills, 4 shiftTypes, 8 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_late06 has 1 skills, 4 shiftTypes, 0 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_late07 has 1 skills, 4 shiftTypes, 0 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.
sprint_late08 has 1 skills, 4 shiftTypes, 0 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and   0 requests with a search space of  10^152.
sprint_late09 has 1 skills, 4 shiftTypes, 0 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and   0 requests with a search space of  10^152.
sprint_late10 has 1 skills, 4 shiftTypes, 0 patterns, 3 contracts, 10 employees, 28 shiftDates, 152 shiftAssignments and 150 requests with a search space of  10^152.

medium01      has 1 skills, 4 shiftTypes, 0 patterns, 4 contracts, 31 employees, 28 shiftDates, 608 shiftAssignments and 403 requests with a search space of  10^906.
medium02      has 1 skills, 4 shiftTypes, 0 patterns, 4 contracts, 31 employees, 28 shiftDates, 608 shiftAssignments and 403 requests with a search space of  10^906.
medium03      has 1 skills, 4 shiftTypes, 0 patterns, 4 contracts, 31 employees, 28 shiftDates, 608 shiftAssignments and 403 requests with a search space of  10^906.
medium04      has 1 skills, 4 shiftTypes, 0 patterns, 4 contracts, 31 employees, 28 shiftDates, 608 shiftAssignments and 403 requests with a search space of  10^906.
medium05      has 1 skills, 4 shiftTypes, 0 patterns, 4 contracts, 31 employees, 28 shiftDates, 608 shiftAssignments and 403 requests with a search space of  10^906.
medium_hint01 has 1 skills, 4 shiftTypes, 7 patterns, 4 contracts, 30 employees, 28 shiftDates, 428 shiftAssignments and 390 requests with a search space of  10^632.
medium_hint02 has 1 skills, 4 shiftTypes, 7 patterns, 3 contracts, 30 employees, 28 shiftDates, 428 shiftAssignments and 390 requests with a search space of  10^632.
medium_hint03 has 1 skills, 4 shiftTypes, 7 patterns, 4 contracts, 30 employees, 28 shiftDates, 428 shiftAssignments and 390 requests with a search space of  10^632.
medium_late01 has 1 skills, 4 shiftTypes, 7 patterns, 4 contracts, 30 employees, 28 shiftDates, 424 shiftAssignments and 390 requests with a search space of  10^626.
medium_late02 has 1 skills, 4 shiftTypes, 7 patterns, 3 contracts, 30 employees, 28 shiftDates, 428 shiftAssignments and 390 requests with a search space of  10^632.
medium_late03 has 1 skills, 4 shiftTypes, 0 patterns, 4 contracts, 30 employees, 28 shiftDates, 428 shiftAssignments and 390 requests with a search space of  10^632.
medium_late04 has 1 skills, 4 shiftTypes, 7 patterns, 3 contracts, 30 employees, 28 shiftDates, 416 shiftAssignments and 390 requests with a search space of  10^614.
medium_late05 has 2 skills, 5 shiftTypes, 7 patterns, 4 contracts, 30 employees, 28 shiftDates, 452 shiftAssignments and 390 requests with a search space of  10^667.

long01        has 2 skills, 5 shiftTypes, 3 patterns, 3 contracts, 49 employees, 28 shiftDates, 740 shiftAssignments and 735 requests with a search space of 10^1250.
long02        has 2 skills, 5 shiftTypes, 3 patterns, 3 contracts, 49 employees, 28 shiftDates, 740 shiftAssignments and 735 requests with a search space of 10^1250.
long03        has 2 skills, 5 shiftTypes, 3 patterns, 3 contracts, 49 employees, 28 shiftDates, 740 shiftAssignments and 735 requests with a search space of 10^1250.
long04        has 2 skills, 5 shiftTypes, 3 patterns, 3 contracts, 49 employees, 28 shiftDates, 740 shiftAssignments and 735 requests with a search space of 10^1250.
long05        has 2 skills, 5 shiftTypes, 3 patterns, 3 contracts, 49 employees, 28 shiftDates, 740 shiftAssignments and 735 requests with a search space of 10^1250.
long_hint01   has 2 skills, 5 shiftTypes, 9 patterns, 3 contracts, 50 employees, 28 shiftDates, 740 shiftAssignments and   0 requests with a search space of 10^1257.
long_hint02   has 2 skills, 5 shiftTypes, 7 patterns, 3 contracts, 50 employees, 28 shiftDates, 740 shiftAssignments and   0 requests with a search space of 10^1257.
long_hint03   has 2 skills, 5 shiftTypes, 7 patterns, 3 contracts, 50 employees, 28 shiftDates, 740 shiftAssignments and   0 requests with a search space of 10^1257.
long_late01   has 2 skills, 5 shiftTypes, 9 patterns, 3 contracts, 50 employees, 28 shiftDates, 752 shiftAssignments and   0 requests with a search space of 10^1277.
long_late02   has 2 skills, 5 shiftTypes, 9 patterns, 4 contracts, 50 employees, 28 shiftDates, 752 shiftAssignments and   0 requests with a search space of 10^1277.
long_late03   has 2 skills, 5 shiftTypes, 9 patterns, 3 contracts, 50 employees, 28 shiftDates, 752 shiftAssignments and   0 requests with a search space of 10^1277.
long_late04   has 2 skills, 5 shiftTypes, 9 patterns, 4 contracts, 50 employees, 28 shiftDates, 752 shiftAssignments and   0 requests with a search space of 10^1277.
long_late05   has 2 skills, 5 shiftTypes, 9 patterns, 3 contracts, 50 employees, 28 shiftDates, 740 shiftAssignments and   0 requests with a search space of 10^1257.
Copy to Clipboard

图 4.13. 域模型

nurseRosteringClassDiagram

4.16. 趋势问题(TTP)

计划与 n 个团队间的匹配。

travelingTournamentUseCase

硬限制:

  • 每个团队都针对其他团队做两次操作两次:当家和一次性。
  • 每个团队在每个 timeslot 上都有一个匹配项。
  • 团队不能有超过三个以上的家或连续三个匹配。
  • 无重复者:与团队相比,不能连续地匹配同一两个。

软限制:

  • 最小化所有团队相换的总距离。

此问题在 Dan Trick 的网站(也包含了全局记录) 上定义。

问题大小

1-nl04     has  6 days,  4 teams and   12 matches with a search space of    10^5.
1-nl06     has 10 days,  6 teams and   30 matches with a search space of   10^19.
1-nl08     has 14 days,  8 teams and   56 matches with a search space of   10^43.
1-nl10     has 18 days, 10 teams and   90 matches with a search space of   10^79.
1-nl12     has 22 days, 12 teams and  132 matches with a search space of  10^126.
1-nl14     has 26 days, 14 teams and  182 matches with a search space of  10^186.
1-nl16     has 30 days, 16 teams and  240 matches with a search space of  10^259.
2-bra24    has 46 days, 24 teams and  552 matches with a search space of  10^692.
3-nfl16    has 30 days, 16 teams and  240 matches with a search space of  10^259.
3-nfl18    has 34 days, 18 teams and  306 matches with a search space of  10^346.
3-nfl20    has 38 days, 20 teams and  380 matches with a search space of  10^447.
3-nfl22    has 42 days, 22 teams and  462 matches with a search space of  10^562.
3-nfl24    has 46 days, 24 teams and  552 matches with a search space of  10^692.
3-nfl26    has 50 days, 26 teams and  650 matches with a search space of  10^838.
3-nfl28    has 54 days, 28 teams and  756 matches with a search space of  10^999.
3-nfl30    has 58 days, 30 teams and  870 matches with a search space of 10^1175.
3-nfl32    has 62 days, 32 teams and  992 matches with a search space of 10^1367.
4-super04  has  6 days,  4 teams and   12 matches with a search space of    10^5.
4-super06  has 10 days,  6 teams and   30 matches with a search space of   10^19.
4-super08  has 14 days,  8 teams and   56 matches with a search space of   10^43.
4-super10  has 18 days, 10 teams and   90 matches with a search space of   10^79.
4-super12  has 22 days, 12 teams and  132 matches with a search space of  10^126.
4-super14  has 26 days, 14 teams and  182 matches with a search space of  10^186.
5-galaxy04 has  6 days,  4 teams and   12 matches with a search space of    10^5.
5-galaxy06 has 10 days,  6 teams and   30 matches with a search space of   10^19.
5-galaxy08 has 14 days,  8 teams and   56 matches with a search space of   10^43.
5-galaxy10 has 18 days, 10 teams and   90 matches with a search space of   10^79.
5-galaxy12 has 22 days, 12 teams and  132 matches with a search space of  10^126.
5-galaxy14 has 26 days, 14 teams and  182 matches with a search space of  10^186.
5-galaxy16 has 30 days, 16 teams and  240 matches with a search space of  10^259.
5-galaxy18 has 34 days, 18 teams and  306 matches with a search space of  10^346.
5-galaxy20 has 38 days, 20 teams and  380 matches with a search space of  10^447.
5-galaxy22 has 42 days, 22 teams and  462 matches with a search space of  10^562.
5-galaxy24 has 46 days, 24 teams and  552 matches with a search space of  10^692.
5-galaxy26 has 50 days, 26 teams and  650 matches with a search space of  10^838.
5-galaxy28 has 54 days, 28 teams and  756 matches with a search space of  10^999.
5-galaxy30 has 58 days, 30 teams and  870 matches with a search space of 10^1175.
5-galaxy32 has 62 days, 32 teams and  992 matches with a search space of 10^1367.
5-galaxy34 has 66 days, 34 teams and 1122 matches with a search space of 10^1576.
5-galaxy36 has 70 days, 36 teams and 1260 matches with a search space of 10^1801.
5-galaxy38 has 74 days, 38 teams and 1406 matches with a search space of 10^2042.
5-galaxy40 has 78 days, 40 teams and 1560 matches with a search space of 10^2301.
Copy to Clipboard

4.17. 更便宜的时间调度

以时间和机器上调度所有任务,以最大程度降低功耗。电源价格因时间而异。这是 作业跃点调度的形式

硬限制:

  • 开始时间限制:每个任务都必须在最早的开始和最新开始限制之间启动。
  • 最大容量 :不得超过每台机器的每个资源的最大容量。
  • 启动和关闭 :每台机器必须在分配了任务的期间处于活跃状态。在任务之间,允许闲置,以避免启动和关闭成本。

中等限制:

  • 功耗:最小化整个时间表的总功耗。

    • 机器功耗:每个活跃或空闲的机器都会消耗电源,这取决于功耗(取决于该期间的电源价格)。
    • 任务功耗:每个任务都消耗电源,这推断了功耗(取决于其期间的电源价格)。
    • 机器启动和关闭成本 :机器每次启动或关闭时,都会带来额外的成本。

软限制(在原始问题定义中添加):

  • Start early: Prefer 更早地启动一个任务,而不是之后启动。

问题由 ICON 质询 定义。

问题大小

sample01   has 3 resources,   2 machines, 288 periods and   25 tasks with a search space of    10^53.
sample02   has 3 resources,   2 machines, 288 periods and   50 tasks with a search space of   10^114.
sample03   has 3 resources,   2 machines, 288 periods and  100 tasks with a search space of   10^226.
sample04   has 3 resources,   5 machines, 288 periods and  100 tasks with a search space of   10^266.
sample05   has 3 resources,   2 machines, 288 periods and  250 tasks with a search space of   10^584.
sample06   has 3 resources,   5 machines, 288 periods and  250 tasks with a search space of   10^673.
sample07   has 3 resources,   2 machines, 288 periods and 1000 tasks with a search space of  10^2388.
sample08   has 3 resources,   5 machines, 288 periods and 1000 tasks with a search space of  10^2748.
sample09   has 4 resources,  20 machines, 288 periods and 2000 tasks with a search space of  10^6668.
instance00 has 1 resources,  10 machines, 288 periods and  200 tasks with a search space of   10^595.
instance01 has 1 resources,  10 machines, 288 periods and  200 tasks with a search space of   10^599.
instance02 has 1 resources,  10 machines, 288 periods and  200 tasks with a search space of   10^599.
instance03 has 1 resources,  10 machines, 288 periods and  200 tasks with a search space of   10^591.
instance04 has 1 resources,  10 machines, 288 periods and  200 tasks with a search space of   10^590.
instance05 has 2 resources,  25 machines, 288 periods and  200 tasks with a search space of   10^667.
instance06 has 2 resources,  25 machines, 288 periods and  200 tasks with a search space of   10^660.
instance07 has 2 resources,  25 machines, 288 periods and  200 tasks with a search space of   10^662.
instance08 has 2 resources,  25 machines, 288 periods and  200 tasks with a search space of   10^651.
instance09 has 2 resources,  25 machines, 288 periods and  200 tasks with a search space of   10^659.
instance10 has 2 resources,  20 machines, 288 periods and  500 tasks with a search space of  10^1657.
instance11 has 2 resources,  20 machines, 288 periods and  500 tasks with a search space of  10^1644.
instance12 has 2 resources,  20 machines, 288 periods and  500 tasks with a search space of  10^1637.
instance13 has 2 resources,  20 machines, 288 periods and  500 tasks with a search space of  10^1659.
instance14 has 2 resources,  20 machines, 288 periods and  500 tasks with a search space of  10^1643.
instance15 has 3 resources,  40 machines, 288 periods and  500 tasks with a search space of  10^1782.
instance16 has 3 resources,  40 machines, 288 periods and  500 tasks with a search space of  10^1778.
instance17 has 3 resources,  40 machines, 288 periods and  500 tasks with a search space of  10^1764.
instance18 has 3 resources,  40 machines, 288 periods and  500 tasks with a search space of  10^1769.
instance19 has 3 resources,  40 machines, 288 periods and  500 tasks with a search space of  10^1778.
instance20 has 3 resources,  50 machines, 288 periods and 1000 tasks with a search space of  10^3689.
instance21 has 3 resources,  50 machines, 288 periods and 1000 tasks with a search space of  10^3678.
instance22 has 3 resources,  50 machines, 288 periods and 1000 tasks with a search space of  10^3706.
instance23 has 3 resources,  50 machines, 288 periods and 1000 tasks with a search space of  10^3676.
instance24 has 3 resources,  50 machines, 288 periods and 1000 tasks with a search space of  10^3681.
instance25 has 3 resources,  60 machines, 288 periods and 1000 tasks with a search space of  10^3774.
instance26 has 3 resources,  60 machines, 288 periods and 1000 tasks with a search space of  10^3737.
instance27 has 3 resources,  60 machines, 288 periods and 1000 tasks with a search space of  10^3744.
instance28 has 3 resources,  60 machines, 288 periods and 1000 tasks with a search space of  10^3731.
instance29 has 3 resources,  60 machines, 288 periods and 1000 tasks with a search space of  10^3746.
instance30 has 4 resources,  70 machines, 288 periods and 2000 tasks with a search space of  10^7718.
instance31 has 4 resources,  70 machines, 288 periods and 2000 tasks with a search space of  10^7740.
instance32 has 4 resources,  70 machines, 288 periods and 2000 tasks with a search space of  10^7686.
instance33 has 4 resources,  70 machines, 288 periods and 2000 tasks with a search space of  10^7672.
instance34 has 4 resources,  70 machines, 288 periods and 2000 tasks with a search space of  10^7695.
instance35 has 4 resources,  80 machines, 288 periods and 2000 tasks with a search space of  10^7807.
instance36 has 4 resources,  80 machines, 288 periods and 2000 tasks with a search space of  10^7814.
instance37 has 4 resources,  80 machines, 288 periods and 2000 tasks with a search space of  10^7764.
instance38 has 4 resources,  80 machines, 288 periods and 2000 tasks with a search space of  10^7736.
instance39 has 4 resources,  80 machines, 288 periods and 2000 tasks with a search space of  10^7783.
instance40 has 4 resources,  90 machines, 288 periods and 4000 tasks with a search space of 10^15976.
instance41 has 4 resources,  90 machines, 288 periods and 4000 tasks with a search space of 10^15935.
instance42 has 4 resources,  90 machines, 288 periods and 4000 tasks with a search space of 10^15887.
instance43 has 4 resources,  90 machines, 288 periods and 4000 tasks with a search space of 10^15896.
instance44 has 4 resources,  90 machines, 288 periods and 4000 tasks with a search space of 10^15885.
instance45 has 4 resources, 100 machines, 288 periods and 5000 tasks with a search space of 10^20173.
instance46 has 4 resources, 100 machines, 288 periods and 5000 tasks with a search space of 10^20132.
instance47 has 4 resources, 100 machines, 288 periods and 5000 tasks with a search space of 10^20126.
instance48 has 4 resources, 100 machines, 288 periods and 5000 tasks with a search space of 10^20110.
instance49 has 4 resources, 100 machines, 288 periods and 5000 tasks with a search space of 10^20078.
Copy to Clipboard

4.18. 资产类分配(Portfolio Optimization)

决定每个资产类参与的相对数量。

硬限制:

  • 风险最大值:标准总差异不得高于标准影响最大值。

  • 地区最大值:每个区域具有最多数量。
  • 扇区最大值:每个扇区具有最多数量。

软限制:

  • 最大化预期返回。

问题大小

de_smet_1 has 1 regions, 3 sectors and 11 asset classes with a search space of 10^4.
irrinki_1 has 2 regions, 3 sectors and 6 asset classes with a search space of 10^3.
Copy to Clipboard

大型数据集尚未被创建或测试,但不会造成问题。良好的数据源是 此资产评估网站

4.19. 指导调度

为每个电信分配一个 timeslot 和一个房间。Timeslots 可以重叠。读/写到/写入,该文件也可以使用 LibreOffice 或 Excel 编辑该文件。

硬限制:

  • 对话类型 timeslot :对话的类型必须与 timeslot 的对话类型匹配。
  • 房间不可用时间:对话的空间必须在对话的 timeslot 期间可用。
  • 房间冲突:两个对话无法在重叠的 timeslot 期间使用相同的空间。
  • speaker 不可用时间:每个对话的 speaker 都必须在对话的 timeslot 期间可用。
  • speaker 冲突:两个对话无法在重叠的 timeslot 期间共享 speaker。
  • 通用目的 timeslot 和 room 标签

    • speaker 所需的 timeslot 标签:如果 speaker 具有所需的 timeslot 标签,则必须将所有自己/她对话到与该标签的 timeslot。
    • speaker 禁止 timeslot 标签:如果 speaker 具有禁止的 timeslot 标签,则所有其/她的对话都不能分配给与该标签的 timeslot。
    • 对话所需的 timeslot 标签:如果通信具有所需的 timeslot 标签,则必须将其分配给具有该标签的 timeslot。
    • 禁止的 timeslot 标签:如果对话有禁止的 timeslot 标签,则无法将其分配给具有该标签的 timeslot。
    • speaker 需要的 room 标签:如果 speaker 具有必需的 room 标签,则必须将所有其/她的对话分配给具有该标签的房间。
    • speaker forbidden room tag:如果 speaker 具有禁止的 room 标签,则所有其/她的对话都不能分配给具有该标签的房间。
    • 对话所需的 room 标签:如果对话具有所需的 room 标签,则必须将其分配给具有该标签的房间。
    • 对话空间标签 :如果对话具有禁止的 room 标签,则无法将其分配给具有该标签的房间。
  • 对话互斥的 timelousive-talks 标签:共享这样的标签不能调度到重叠的 timeslots 中。
  • 对话先决条件:在所有先决条件通信后,必须调度一个对话。

软限制:

  • 主题跟踪冲突:最小化在重叠 timeslots 期间共享相同的主题标签的对话数量。
  • 扇区冲突:最小化在重叠 timeslots 期间共享相同的扇区标签的通信数量。
  • 内容使用者级别流程违反:对于每个内容标签,请在高级通信前调度简介。
  • Audience 级别区分 :对于每个时间线,最大化与不同使用者级别的对话数量。
  • 语言离散性:对于每个 timeslot,最大程度提高与不同语言对话的数量。
  • 通用目的 timeslot 和 room 标签

    • speaker 首选 timeslot 标签:如果 speaker 具有首选的 timeslot 标签,则所有自己/她的对话都应分配给具有该标签的 timeslot。
    • speaker undesired timeslot tag:如果 speaker 有一个不需要的 timeslot 标签,则所有其/她都不应分配给具有该标签的 timeslot。
    • 与首选 timeslot 标签通信:如果对话有一个首选的 timeslot 标签,则应将其分配给具有该标签的 timeslot。
    • 对话不需要的 timeslot 标签:如果通信具有不需要的 timeslot 标签,则不应将其分配给具有该标签的 timeslot。
    • speaker 首选空间标签:如果 speaker 具有首选空间标签,则所有 he/her 对话都应分配给具有该标签的房间。
    • speaker undesired room tag:如果 speaker 有一个不需要的 room 标签,则所有自己/她的对话都不应分配给具有该标签的房间。
    • 通信首选空间标签:如果对话有一个首选的空间标签,则应将其分配给具有该标签的房间。
    • 对话不需要的房间标签:如果对话具有不需要的空间标签,则不应将其分配给具有该标签的房间。
  • 相同的日期:所有与共享相同主题标签或内容标签的对话都应在最少天数内调度(以同一天表示)。

图 4.14. 价值

conferenceSchedulingValueProposition

问题大小

18talks-6timeslots-5rooms    has  18 talks,  6 timeslots and  5 rooms with a search space of  10^26.
36talks-12timeslots-5rooms   has  36 talks, 12 timeslots and  5 rooms with a search space of  10^64.
72talks-12timeslots-10rooms  has  72 talks, 12 timeslots and 10 rooms with a search space of 10^149.
108talks-18timeslots-10rooms has 108 talks, 18 timeslots and 10 rooms with a search space of 10^243.
216talks-18timeslots-20rooms has 216 talks, 18 timeslots and 20 rooms with a search space of 10^552.
Copy to Clipboard

4.20. rock 导览

从显示驱动 rock 总线来显示,但调度仅显示可用天数。

硬限制:

  • 调度每个所需显示。
  • 调度尽可能显示。

中等限制:

  • 最大化专家机会。
  • 最小化推动时间。
  • 早于更新版本。

软限制:

  • 避免长时间花费时间。

问题大小

47shows has 47 shows with a search space of 10^59.
Copy to Clipboard

4.21. 飞行人员的调度

将 flights 分配给 pilots 和 flight 参与。

硬限制:

  • 所需技术:每个 flight 分配都有一个必需的技术。例如,flight AB0001 需要 2 个 pilots 和 3 个动态活动。
  • flight 冲突:每个员工可以同时参与一个 flight
  • 在两个 flights 之间传输:在两个 flights 之间,员工必须能够从 arrival airport 传输到 departure airport。例如,An 在 Brussels 到达 Brussels 于 10:00,在 Amsterdam 到达 15:00。
  • 员工不可用:员工必须在 flight 之日可用。例如,An 位于 1-Feb 上的 PTO 上。

软限制:

  • 首先从家分配
  • 最后分配位于家
  • 每个员工的负载均衡 flight 持续时间

问题大小

175flights-7days-Europe  has 2 skills, 50 airports, 150 employees, 175 flights and  875 flight assignments with a search space of  10^1904.
700flights-28days-Europe has 2 skills, 50 airports, 150 employees, 700 flights and 3500 flight assignments with a search space of  10^7616.
875flights-7days-Europe  has 2 skills, 50 airports, 750 employees, 875 flights and 4375 flight assignments with a search space of 10^12578.
175flights-7days-US      has 2 skills, 48 airports, 150 employees, 175 flights and  875 flight assignments with a search space of  10^1904.
Copy to Clipboard

部分 II. 为 Red Hat Business Optimizer 部署和使用 vehicle 路由规划启动程序应用程序

作为开发人员,您可以使用 OptaWeb Vehicle Routing starter 应用程序来优化您的电池团队。

先决条件

  • 已安装 OpenJDK (JDK) 8。Red Hat build of Open JDK 位于红帽客户门户网站中的 Software Downloads 页面中(需要登录)。
  • 已安装 Apache Maven 3.6 或更高版本。Maven 可从 Apache Maven 项目网站 获得。

第 5 章 什么是 OptaWeb Vehicle Routing?

许多行业的主要目的是传输各种类型的 cargo。这些企业的目标是将加载点从加载点发送到目的地,并以最有效的方式使用其电点。主要目标之一是最大程度降低以时间或距离来测量的批量成本。

这种类型的优化问题被称为 vehicle 路由问题(VRP),并且有很多变化。

Red Hat Business Optimizer 可以解决许多这些载体路由变体,并提供解决方案示例。红帽业务优化器使开发人员能够专注于对业务规则和要求建模,而不是学习 约束编程。optaweb Vehicle Routing 通过提供回答问题的参考实现来扩展 Red Hat Business Optimizer 的 vehicle 路由功能:

  • 我在哪里获取距离和旋转时间?
  • 如何在映射中视觉化解决方案?
  • 如何构建在云中运行的应用程序?

optaweb Vehicle Routing 使用 OpenStreetMap (OSM)数据文件。有关 OpenStreetMap 的详情,请查看 OpenStreetMap 网站。

在使用 OptaWeb Vehicle 路由时使用以下定义:

区域 :由 OSM 文件表示的 Earth 映射的任意区域。区域可以是国家、城市、连续或一组通常一起使用的国家/地区。例如,DACH 区域包括西班牙语(DE)、Austria (AT)和 Sphone (CH)。

国家/ 地区代码 :由 ISO-3166 标准分配给国家/地区的双字母代码。您可以使用国家代码来过滤 geosearch 结果。由于您可以处理跨越多个国家/地区(如 DACH 区域)的区域,OptaWeb Vehicle Routing 接受一个国家代码列表,以便 geosearch 过滤可与这些区域一起使用。有关国家代码列表,请参阅 ISO 3166 国家代码

Geosearch :一个查询类型,您可以提供一个地址或区域的位置名称作为 search 关键字,并接收多个 GPS 位置。返回的位置数量取决于 search 关键字的唯一位置数量。由于大多数位置名称不是唯一的,因此仅过滤出非相关的结果,方法是仅包含位于工作地区或国家/国家/地区。

第 6 章 下载并构建 OptaWeb Vehicle Routing 部署文件

您必须在构建和部署 OptaWeb Vehicle 路由前下载并准备部署文件。

流程

  1. 导航到红帽客户门户网站中的 Software Downloads 页面(需要登录),然后从下拉菜单中选择产品和版本:

    • 产品 :Red Hat Process Automation Manager
    • Version: 7.10
  2. 下载 Red Hat Process Automation Manager 7.10 参考 实现(rhpam-7.10.0-reference- Implementationation.zip)。
  3. 下载 Red Hat Process Automation Manager 7.10 Maven Repository (rhpam-7.10.0-maven-repository.zip)。
  4. 提取 rhpam-7.10.0-maven-repository.zip 文件。
  5. rhpam-7.10.0-maven-repository/maven-repository 子目录的内容复制到 ~/.m2/repository 目录中。
  6. 提取 rhpam-7.10.0-reference-ementation.zip 文件。此存档包含三个参考实现 ZIP 文件。
  7. 提取 rhpam-7.10.0-optaweb-vehicle-routing.zip 文件。
  8. 导航到 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources 目录。
  9. 输入以下命令来构建 OptaWeb Vehicle Routing:

    mvn clean package -DskipTests
    Copy to Clipboard

第 7 章 使用 runLocally.sh 脚本在本地运行 OptaWeb Vehicle Routing

Linux 用户可以使用 runLocally.sh Bash 脚本来运行 OptaWeb Vehicle Routing。

注意

runLocally.sh 脚本不会在 macOS 中运行。如果您无法使用 runLocally.sh 脚本,请参阅 第 8 章 手动配置和运行 OptaWeb Vehicle Routing

runLocally.sh 脚本自动执行以下设置步骤,否则必须手动执行:

  • 创建数据目录。
  • 从 Geofabrik 下载所选的 OpenStreetMap (OSM)文件。
  • 尝试自动将国家代码与每个下载的 OSM 文件关联。
  • 如果独立 JAR 文件不存在,则构建项目。
  • 通过使用一个 region 参数或以交互方式选择区域来启动 OptaWeb Vehicle 路由。

有关执行 local Locally.sh 脚本的说明,请参见以下小节:

7.1. 以快速启动模式运行 OptaWeb Vehicle Routing runLocally.sh 脚本

使用 OptaWeb Vehicle Routing 启动的最简单方法是在没有任何参数的情况下运行 runLocally.sh 脚本。

先决条件

流程

  1. optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources 目录中输入以下命令。

     ./runLocally.sh
    Copy to Clipboard
  2. 如果提示创建 .optaweb-vehicle-routing 目录,请输入 y。首次运行脚本时,系统会提示您创建该目录。
  3. 如果提示下载 OSM 文件,请输入 y。您第一次运行脚本时,OptaWeb Vehicle Routing 会下载 Belgium OSM 文件。

    应用程序在下载 OSM 文件后启动。

  4. 要打开 OptaWeb Vehicle Routing 用户界面,请在网页浏览器中输入以下 URL:

    http://localhost:8080
    Copy to Clipboard
注意

您第一次运行脚本时,需要几分钟才能启动,因为 OSM 文件必须由 GraphHopper 导入,并存储为 road 网络图。下一次运行 run ly.sh 脚本时,负载时间会非常快。

7.2. 以互动模式运行 OptaWeb Vehicle Routing runLocally.sh 脚本

使用交互模式查看下载的 OSM 文件和分配给每个区域的国家代码的列表。您可以使用交互模式从 Geofabrik 下载额外的 OSM 文件,而无需访问网站并选择下载目的地。

先决条件

流程

  1. 将目录更改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources
  2. 输入以下命令以互动模式运行脚本:

    ./runLocally.sh -i
    Copy to Clipboard
  3. 在您选择的提示符处,输入 d 以显示下载菜单。之前下载的区域列表会显示,后跟您可以下载的区域列表。
  4. 可选:从之前下载的区域列表中选择区域:

    1. 在下载的区域列表中,输入与区域关联的数字。
    2. 按 Enter 键。
  5. 可选:下载区域:

    1. 输入与您要下载的区域关联的数字。例如,若要选择 Europe 映射,请输入 5
    2. 要下载映射,请输入 d,然后按 Enter 键。
    3. 要在映射中下载特定区域,请输入 e,然后输入与您要下载的区域关联的数字,然后按 Enter 键。

      使用大型 OSM 文件

      为获得最佳用户体验,请使用较小的区域,如个人美国或美国状态。使用大于 1 GB 的 OSM 文件需要大量 RAM 大小,并且需要大量时间(最多几小时)进行初始处理。

      应用程序在下载 OSM 文件后启动。

  6. 要打开 OptaWeb Vehicle Routing 用户界面,请在网页浏览器中输入以下 URL:

    http://localhost:8080
    Copy to Clipboard

7.3. 在非互动模式下运行 OptaWeb Vehicle Routing runLocally.sh 脚本

在非互动模式中使用 OptaWeb Vehicle Routing 启动 OptaWeb Vehicle Routing,并带有之前下载的 OSM 文件的单一命令。当您想快速切换区域或进行演示时,这非常有用。

先决条件

流程

  1. 将目录更改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources
  2. 执行以下命令,其中 &lt ;OSM_FILE_NAME > 是之前下载的 OSM 文件:

    ./runLocally.sh <OSM_FILE_NAME>
    Copy to Clipboard

7.4. 以 air distance 模式运行 OptaWeb Vehicle Routing runLocally.sh 脚本

optaweb Vehicle Routing 可以在 air distance 模式下工作,该模式根据两个协调之间的距离计算往返时间。如果您需要尽快启动并运行 OptaWeb Vehicle Routing,且不想使用 OSM (OpenStreetMap)文件,则使用此模式。air distance 模式只有在您需要进行测试的 OptaWeb Vehicle 路由且不需要准确的传输时间时才有用。

先决条件

流程

  1. 将目录更改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources
  2. 使用 --air 参数运行 runLocally.sh 脚本来以 air distance 模式启动 OptaWeb Vehicle Routing:

    ./runLocally.sh --air
    Copy to Clipboard

7.5. 更新数据目录

如果要使用不同的数据目录,您可以更新 OptaWeb Vehicle Routing 使用的数据目录。默认数据目录为 $HOME/.optaweb-vehicle-routing

先决条件

流程

  • 要使用不同的数据目录,请在其绝对路径到当前数据目录中的 .DATA_DIR_LAST 文件的绝对路径。
  • 要更改与地区关联的国家代码,请在当前数据目录中编辑 national_codes 目录中的对应文件。

    例如,如果您为 Scotland 下载 OSM 文件,且脚本无法猜测国家代码,请将 national _codes/scotland-latest 的内容设置为 GB。

  • 要删除区域,请从 data 目录中的 openstreetmap 目录中删除对应的 OSM 文件,并删除 graphhopper 目录中的区域目录。

第 8 章 手动配置和运行 OptaWeb Vehicle Routing

运行 OptaWeb Vehicle Routing 的最简单方法是使用 runlocally.sh 脚本。但是,如果系统上没有 Bash,您可以手动完成 runlocally.sh 脚本执行的步骤。

先决条件

流程

  1. 下载路由数据。

    路由引擎需要地理数据来计算在位置间传输所需时间。在运行 OptaWeb Vehicle Routing 前,您必须将 OpenStreetMap (OSM)数据文件下载到本地文件系统中。

    注意

    OSM 数据文件通常介于 100 MB 到 1 GB 之间,需要时间来下载文件,以便在构建或启动 OptaWeb Vehicle Routing 应用程序前下载文件。

    1. 在网页浏览器中打开 http://download.geofabrik.de/
    2. 单击 Sub Region 列表中的区域,如 Europe。此时会打开 subregion 页面。
    3. Sub Regions 表中,下载国家的 OSM 文件(.osm.pbf),如 Belgium。
  2. 创建数据结构。

    optaweb Vehicle Routing 读取和写入文件系统中多种数据。它从 openstreetmap 目录中读取 OSM (OpenStreetMap)文件,将 road 网络图写入 图形 跃点目录,并在名为 db 的目录中保留用户数据。创建一个用于存储所有数据的新目录,以便更轻松地升级到 OptaWeb Vehicle Routing 的较新版本,并继续使用之前创建的数据。

    1. 创建 $HOME/{VRP-DATA-DIR} 目录。
    2. $HOME/{VRP-DATA-DIR} 目录中创建 openstreetmap 目录:

      $HOME/{VRP-DATA-DIR}
      └── openstreetmap
      Copy to Clipboard
    3. 将所有下载的 OSM 文件(扩展为 .osm.pbf的文件)移到 openstreetmap 目录中。

      目录结构的其余部分由 OptaWeb Vehicle Routing 应用程序首次运行时创建。之后,您的目录结构类似以下示例:

      $HOME/{VRP-DATA-DIR}
      
      ├── db
      │   └── vrp.mv.db
      ├── graphhopper
      │   └── belgium-latest
      └── openstreetmap
          └── belgium-latest.osm.pbf
      Copy to Clipboard
  3. 将目录更改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources/optaweb-vehicle-routing-standalone/target
  4. 要运行 OptaWeb Vehicle Routing,请输入以下命令:

    java -jar optaweb-vehicle-routing-standalone-7.48.0.Final-redhat-00004.jar \
    --app.persistence.h2-dir=$HOME/{VRP-DATA-DIR}/db \
    --app.routing.gh-dir=$HOME/{VRP-DATA-DIR}/graphhopper \
    --app.routing.osm-dir=$HOME/{VRP-DATA-DIR}/openstreetmap \
    --app.routing.osm-file=<OSM_FILE_NAME> \
    --app.region.country-codes=<COUNTRY_CODE_LIST> \
    Copy to Clipboard

    在这个命令中,替换以下变量:

    • <OSM_FILE_NAME > :您要使用的区域的 OSM 文件以及之前下载的区域
    • <COUNTRY_CODE_LIST > :用于过滤 geosearch 查询的国家代码的逗号分隔列表。有关国家代码列表,请参阅 ISO 3166 国家代码

      应用程序在下载 OSM 文件后启动。

      在以下示例中,OptaWeb Vehicle Routing 下载 Central 美国的 OSM 映射(central-america-latest.osm.pbf),并在国家 Belize (BZ)和 Guatemala (GT)中搜索。

      java -jar optaweb-vehicle-routing-standalone-7.48.0.Final-redhat-00004.jar \
      --app.persistence.h2-dir=/home/user/.optaweb-vehicle-routing/db \
      --app.routing.osm-dir=/home/user/.optaweb-vehicle-routing/openstreetmap \
      --app.routing.gh-dir=/home/user/.optaweb-vehicle-routing/graphhopper \
      --app.routing.osm-file=central-america-latest.osm.pbf \
      --app.region.country-codes=BZ,GT
      Copy to Clipboard
  5. 要打开 OptaWeb Vehicle Routing 用户界面,请在网页浏览器中输入以下 URL:

    http://localhost:8080
    Copy to Clipboard

第 9 章 在 Red Hat OpenShift Container Platform 上运行 OptaWeb Vehicle Routing

Linux 用户可以使用 runOnOpenShift.sh Bash 脚本在 Red Hat OpenShift Container Platform 上安装 OptaWeb Vehicle Routing。

注意

runOnOpenShift.sh 脚本不会在 macOS 上运行。

先决条件

流程

  1. 登录或启动 Red Hat OpenShift Container Platform 集群。
  1. 输入以下命令,其中 & lt;PROJECT_NAME > 是新项目的名称:

    oc new-project <PROJECT_NAME>
    Copy to Clipboard
  2. 如有必要,将目录改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources
  3. 输入以下命令来执行 runOnOpenShift.sh 脚本并下载 OpenStreetMap (OSM)文件:

    ./runOnOpenShift.sh <OSM_FILE_NAME> <COUNTRY_CODE_LIST> <OSM_FILE_DOWNLOAD_URL>
    Copy to Clipboard

    在这个命令中,替换以下变量:

    • <OSM_FILE_NAME > :从 < OSM_FILE_DOWNLOAD_URL> 下载的文件的名称
    • <COUNTRY_CODE_LIST > :用于过滤 geosearch 查询的国家代码的逗号分隔列表。有关国家代码列表,请参阅 ISO 3166 国家代码
    • <OSM_FILE_DOWNLOAD_ URL> :可从 OpenShift 访问的 PBF 格式的 OSM 数据文件的 URL。该文件将在后端启动过程中下载,并保存为 /deployments/local/<OSM_FILE_NAME>

      以下示例配置了 OptaWeb Vehicle Routing,将 geosearch 结果过滤到 Belgium,并从 Geofabrik 下载最新的 Belgium OSM 提取:

      在以下示例中,OptaWeb Vehicle Routing 下载 Central 美国的 OSM 映射(central-america-latest.osm.pbf),并在国家 Belize (BZ)和 Guatemala (GT)中搜索。

      ./runOnOpenShift.sh central-america-latest.osm.pbf BZ,GT http://download.geofabrik.de/europe/central-america-latest.osm.pbf
      Copy to Clipboard
注意

对于 runOnOpenShift.sh 脚本的帮助,请输入 ./runOnOpenShift.sh --help

9.1. 使用本地更改更新部署的 OptaWeb Vehicle Routing 应用程序

在 Red Hat OpenShift Container Platform 上部署 OptaWeb Vehicle Routing 应用程序后,您可以更新后端和前端。

先决条件

  • optaweb Vehicle Routing 已成功使用 Maven 构建并在 OpenShift 上部署。

流程

  • 要更新后端,请执行以下步骤:

    1. 更改源代码,并使用 Maven 构建后端模块。
    2. 将目录更改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources/optaweb-vehicle-routing-backend
    3. 输入以下命令启动 OpenShift 构建:

      oc start-build backend --from-dir=. --follow
      Copy to Clipboard
  • 要更新前端,请执行以下步骤:

    1. 更改源代码,并使用 npm 工具构建前端模块。
    2. 将目录更改为 sources/optaweb-vehicle-routing-frontend
    3. 输入以下命令启动 OpenShift 构建:

      oc start-build frontend --from-dir=docker --follow
      Copy to Clipboard

第 10 章 使用 OptaWeb Vehicle Routing

在 OptaWeb Vehicle Routing 应用程序中,您可以标记映射中的多个位置。假设第一个位置为 depot。vehicles 必须从这一投票到您标记的所有其他位置提供很好的选择。

您可以设置 vehicle 的数量,以及每个载体的获取容量。但是,路由无法保证使用所有 vehicles。该应用程序根据需要对最佳路由使用尽可能多的 vehicle。

当前版本有一些限制:

  • 每次发送到某个位置的工作都应该使用一个点载载容量。例如,一个容量为 10 的 vehicle 可以访问最多 10 个位置,然后再返回 depot。
  • 不支持设置 vehicles 和 location 的自定义名称。

10.1. 创建路由

要创建最佳路由,请使用 OptaWeb Vehicle Routing 用户界面的 Demo 选项卡。

先决条件

  • optaweb Vehicle Routing 正在运行,您可以访问用户界面。

流程

  1. 在 OptaWeb Vehicle Routing 中,单击 Demo 以打开 Demo 选项卡。
  2. 使用映射上方的蓝色减号和加号按钮来设置载号。每个 vehicle 都有默认的容量 10。
  3. 根据需要,使用映射上的加号按钮到缩放。

    注意

    不要双击 缩放。双击 也会创建一个位置。

  4. 点 depot 的位置。
  5. 点映射上的其他位置进行发送点。
  6. 如果要删除位置:

    1. 将鼠标光标悬停在位置上,以查看位置名称。
    2. 在屏幕左侧的列表中找到位置名称。
    3. 点名称旁边的 X 图标。

每次添加或删除位置或更改 vehicle 数量时,应用程序会创建并显示新的最佳路由。如果解决方案使用多个 vehicles,则应用程序以不同的颜色显示每个载体的路由。

10.2. 查看和设置其他详情

您可以使用 OptaWeb Vehicle Routing 用户界面中的其他标签页来查看和设置其他详情。

先决条件

  • optaweb Vehicle Routing 正在运行,您可以访问用户界面。

流程

  • Vehicles 选项卡查看、添加和删除 vehicles,以及设置每个 vehicle 的容量。
  • Visits 选项卡查看和删除位置。
  • Route 选项卡选择每个载体并查看所选载体的路由。

10.3. 使用 OptaWeb Vehicle 路由创建自定义数据集

有由几个大型 Belgian 城市组成的内置演示数据集。如果要在 Load demo 菜单中有更多演示,您可以准备自己的数据集。

流程

要做到这一点,请按照以下步骤执行:

  1. 在 OptaWeb Vehicle Routing 中,通过单击映射或使用 geosearch 添加 depot 和多个访问。
  2. Export,并将文件保存到 data set_directory 中。

    注意

    data set 目录是 app.demo.data-set-dir 属性中指定的目录。

    如果应用程序通过 runLocally.sh 脚本运行,数据集目录被设置为 $HOME/{VRP-DATA-DIR}/dataset

    否则,属性来自 application.properties,默认为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources/optaweb-vehicle-routing-standalone/target/local/dataset

    您可以编辑 app.demo.data-set-dir 属性来指定 diffent 数据目录。

  3. 编辑 YAML 文件并为数据集选择唯一名称。
  4. 重启后端。

重启后端后,数据集目录中的文件会出现在 Load demo 菜单中。

10.4. 对 OptaWeb Vehicle 路由进行故障排除

如果 OptaWeb Vehicle 路由行为意外,请按照以下步骤出现问题。

先决条件

  • optaweb Vehicle Routing 正在运行,并意外地执行。

流程

  1. 要识别问题,请查看后端终端输出日志。
  2. 要解决这个问题,删除后端数据库:

    1. 通过在后端终端窗口中按 kbd:[114+C] 来停止后端。
    2. 删除目录 optaweb-vehicle-routing/optaweb-vehicle-routing-backend/local/db
    3. 重启 OptaWeb Vehicle Routing。

第 11 章 optaweb Vehicle Routing 开发指南

本节论述了如何在开发模式中配置和运行后端模块。

11.1. optaweb Vehicle Routing 项目结构

OptaWeb Vehicle Routing 项目是一个多模块 Maven 项目。

图 11.1. 模块依赖关系树图

后端和前端模块位于模块树的底部。这些模块包含应用程序源代码。

standalone 模块是一种编译模块,用于将后端和前端合并到单个可执行 JAR 文件中。

distribution 模块代表最终装配步骤。它采用独立应用程序和文档,并将其嵌套在容易分发的存档中。

后端和前端是单独的项目,您可以单独构建和部署。实际上,它们以完全不同的语言编写,并使用不同的工具构建。这两个项目都可以提供现代开发人员体验,并在代码更改和正在运行的应用程序之间快速切换。

下一小节介绍了如何在开发模式下运行后端和前端项目。

11.2. OptaWeb Vehicle Routing 后端模块

后端模块包含一个服务器端应用程序,它使用红帽业务优化载体路由。优化是一个 CPU 密集型计算,必须避免任何 I/O 操作才能对其完整潜在的执行。由于其中一个目标是最大程度降低往返成本,无论是时间还是距离,OptaWeb Vehicle 路由会使传输成本信息保留在 RAM 内存中。虽然 Red Hat Business Optimizer 需要了解用户输入的各方位置之间的旋转成本。此信息存储在名为 距离列表的结构中

当您输入新位置时,OptaWeb Vehicle Routing 会计算新位置和目前输入的所有其他位置之间的旋转成本,并将传输成本存储在距离列表中。旋转成本计算由 GraphHopper 路由引擎执行。

后端模块实现以下额外的支持功能:

  • Persistence
  • 前端的 websocket 连接
  • 数据集加载、导出和导入

要了解更多有关后端代码架构的信息,请参阅 第 12 章 optaweb Vehicle Routing 后端架构

下一节介绍了如何在开发模式下配置和运行后端。

11.2.1. 使用 Spring Boot Maven 插件运行 OptaWeb Vehicle Routing 后端模块

您可以使用 Spring Boot 插件在开发模式下运行 OptaWeb Vehicle Routing 后端模块。

先决条件

流程

  1. 将目录更改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources/optaweb-vehicle-routing-backend
  2. 要在开发模式下运行后端,请输入以下命令:

    mvn spring-boot:run
    Copy to Clipboard

11.2.2. 从 IntelliJ IDEA 运行 OptaWeb Vehicle Routing 后端模块

您可以使用 IntelliJ IDEA 运行 OptaWeb Vehicle Routing 后端模块,以便更轻松地开发您的项目。

流程

  1. 在 IntelliJ IDEA 中,输入 org.optaweb.vehiclerouting.OptaWebVehicleRoutingApplication。这将创建一个您要在下一步中编辑的运行配置。

    1. Editor 窗口中打开 OptaWebVehicleRoutingApplication 类。
    2. 单击编辑器窗口 gutter 中的绿色勾号,然后选择 Run OptaWebVehicleRoutingApplication。运行会失败,因为工作目录被设置为预期后端模块目录的项目的根目录。

      注意

      请参阅 IntelliJ IDEA 网站上的 Run Applications 页面,以了解有关在 IntelliJ IDEA 中运行应用程序的更多信息。

  2. 选择 Run→Edit Configuration,然后选择 Spring Boot→OptaWebVehicleRoutingApplication
  3. Program 参数设置为 --spring.profiles.active=local 以激活名为 local 的 Spring 配置集。这会指示应用程序使用 application-local.properties 文件中的配置。
  4. Working 目录改为 后端模块(Optaweb-vehicle-routing-backend)。
  5. On Update action 设置为 Hot swap class,并在失败时更新触发器文件。这可让您使用 Update 操作来快速重启应用程序。

    如需更多信息,请参阅 IntelliJ IDEA 2018.1 中的 Spring 和 Spring Boot

11.2.3. Spring Boot 自动重启

Spring Boot DevTools 提供了自动重启。https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-devtools-restart当您使用 Spring Boot Maven 插件运行 OptaWeb Vehicle Routing 后端时,应用程序会在 classpath 发生变化时自动重启。自动重启在 classpath 上扫描文件,因此您只需要重新编译更改来触发应用程序重启。不需要 IDE 配置。

如果您的 IDE 具有编译时保存的功能(如 Eclipse 或 NetBeans),您只需要保存自上次编译后更改的文件。

IntelliJ IDEA 会自动保存更改,您需要选择 Build[Recompile],这会重新编译活跃选项卡中的文件,或 Build[Build Project] 来重新编译所有更改。如需更多信息,请参阅使用 IntelliJ IDEA 编译和构建应用程序

11.2.4. 设置 OptaWeb Vehicle Routing 后端模块配置属性

您可以通过几种方法设置 OptaWeb Vehicle Routing 后端模块配置属性。如果您在本地运行 OptaWeb Vehicle Routing 时,本节中的方法很有用。

先决条件

流程

  1. application.properties 文件中设置配置属性:
  2. 将目录更改为 rhpam-7.48.0.Final-redhat-00004-optaweb-vehicle-routing/sources/optaweb-vehicle-routing-backend/src/main/resources
  3. 在文本编辑器中打开 application.properties 文件。
  4. 编辑或添加属性,然后保存文件。

    • 在运行打包应用程序时,请使用命令行参数。在以下示例中,&lt ;PROPERTY& gt; 是属性的名称,& lt;VALUE > 是该属性值:

      java -jar optaweb-vehicle-routing-backend.jar --app.<PROPERTY>=<VALUE>
      Copy to Clipboard
    • 当使用 spring-boot:run 运行应用程序时使用环境变量:

      <PROPERTY>=<VALUE> ./mvnw spring-boot:run
      Copy to Clipboard
      注意

      此方法需要 放松的绑定,只有在属性使用 @ConfigurationProperties 定义时才有效。

在使用 Spring Boot Maven 插件运行应用程序时,无法设置属性(/ mvnw spring-boot:run -D <PROPERTY)。插件要设置的任何系统属性到运行应用程序的 fork Java 进程,必须使用 systemPropertiesVariables 属性在 pom.xml 文件中指定应用程序。有关此属性的详情,请参考在 Spring 网站上 使用系统属性

您可以在 Spring Boot Externalized Configuration 页面中了解更多有关配置 Spring Boot 应用程序的信息。

提示

使用 src/main/resources/application-local.properties 来存储个人配置,而不影响 Git 工作树。

有关 OptaWeb Vehicle Routing 配置属性的完整列表,请参阅 第 13 章 optaweb Vehicle Routing 后端配置属性

有关 Spring Boot 中提供的应用程序属性的完整列表,请参阅 Spring 网站上的通用应用程序属性 页面。

11.2.5. optaweb Vehicle Routing 后端日志记录

optaweb Vehicle Routing 使用 SLF4J API 和 Logback 作为日志记录框架。Spring 环境允许您配置大多数日志方面,包括级别、模式和日志文件,方式与其他配置属性相同。设置日志记录属性的最常见方法是编辑 application.properties 文件,或使用 < PROPERTY>=<VALUE> 等参数,其中 <PROPERTY > 是属性的名称,<VALUE > 是该属性值。如需更多信息,请参阅 Spring Boot Logging 文档。

以下示例是可用于控制应用程序某些部分的日志级别的属性:

  • logging.level.org.optaweb.vehiclerouting=debug :启用后端代码的 debug 级别
  • logging.level.org.optaplanner.core=warn: 红帽商业优化器日志记录
  • logging.level.org.springframework.web.socket=trace :在调查 WebSocket 连接时访问更多详情

11.3. 使用 OptaWeb Vehicle Routing 前端模块

前端项目使用 Create React App 启动。创建 React App 提供了很多脚本和依赖项,可帮助开发并为生产环境构建应用程序。

先决条件

流程

  1. 在 Fedora 中,输入以下命令设置开发环境:

    sudo dnf install npm
    Copy to Clipboard

    有关安装 npm 的更多信息,请参阅下载并安装 Node.js 和 npm

  2. 将目录更改为 optaweb-vehicle-routing-distribution-7.48.0.Final-redhat-00004/sources/optaweb-vehicle-routing-frontend
  3. 安装 npm 依赖项:

    npm install
    Copy to Clipboard

    与 Maven 不同,npm 软件包管理器会在项目目录下在 node_modules 中安装依赖项,且仅在执行 npm 安装 时才执行。每当 package.json 中列出的依赖项更改时,例如,当您拉取到 master 分支更改时,您必须在运行开发服务器前执行 npm 安装

  4. 输入以下命令来运行开发服务器:

    npm start
    Copy to Clipboard
  5. 如果没有自动打开,在 Web 浏览器中打开 http://localhost:3000/

    默认情况下,npm start 命令尝试在默认浏览器中打开此 URL。

    注意

    如果您不希望 npm start 命令在每次运行时打开新的浏览器标签页,请导出 BROWSER=none 环境变量。您可以使用 .env.local 文件使这个首选项永久化。要做到这一点,请输入以下命令:

    echo BROWSER=none >> .env.local
    Copy to Clipboard

    每当在前端源代码中更改时,浏览器都会刷新页面。在终端中运行的开发服务器进程也会选择更改,并将编译和 lint 错误输出到控制台。

  6. 输入以下命令来运行测试:

    npm test
    Copy to Clipboard
  7. 更改 REACT_APP_BACKEND_URL 环境变量的值,以指定在执行 npm start 或 npm run 构建时npm 使用的后端项目的位置,例如:

    REACT_APP_BACKEND_URL=http://10.0.0.123:8081
    Copy to Clipboard
    注意

    环境变量在 npm 构建过程中在 JavaScript 捆绑包中硬编码,因此您必须在构建和部署前端前指定后端位置。

    要了解更多有关 React 环境变量的信息,请参阅 添加自定义环境变量

  8. 要构建前端,请输入以下命令之一:

    ./mvnw install
    Copy to Clipboard
    mvn install
    Copy to Clipboard

第 12 章 optaweb Vehicle Routing 后端架构

域模型和用例对于应用程序至关重要。OptaWeb Vehicle Routing 域模型位于构架的中心,由嵌入用例的应用程序层组成。路由优化、距离计算、持久性和网络通信等功能被视为实施详细信息,并放置在架构的最顶层。

图 12.1. 应用程序层图

12.1. 代码机构

后端代码以三个层进行组织,如上图所示。

org.optaweb.vehiclerouting
├── domain
├── plugin          # Infrastructure layer
│   ├── persistence
│   ├── planner
│   ├── routing
│   └── websocket
└── service         # Application layer
    ├── demo
    ├── distance
    ├── location
    ├── region
    ├── reload
    ├── route
    └── vehicle
Copy to Clipboard

service 软件包包含实施用例的应用程序层。插件 软件包包含基础架构层。

每个层中的代码按照功能进一步组织。这意味着每个服务或插件都有自己的软件包。

12.2. 依赖项规则

编译时依赖项只允许从外部层指向中心。遵循此规则有助于使域模型独立于底层框架和其他实施详情,并更精确建模业务实体的行为。随着正在推送到外文的演示和持久性,测试业务实体和用例的行为更为容易。

域没有依赖项。

服务仅依赖于域。如果服务需要发送结果(例如到数据库或客户端),它会使用输出边界接口。其实现由 Inversion of Control (IoC)容器注入。

插件以两种方式依赖于服务:首先,它们根据用户输入或来自优化引擎的事件调用服务。服务注入到插件中,该插件会将构建和依赖项解析的负担移到 IoC 容器。其次,插件实施服务输出边界接口来处理用例结果,例如对数据库保留更改或向 Web UI 发送响应。

12.3. 域软件包

domain 软件包包含对此项目的域建模 的业务对象,如 LocationVehicleRoute。这些对象严格于面向业务的,不得受到任何工具和框架的影响,如对象关系映射工具和 Web 服务框架。

12.4. 服务软件包

service 软件包包含实施 用例 的类。使用案例描述了您要做的项,例如添加新位置、更改出口容量或查找地址协调。管理用例的新规则使用域对象表示。

服务通常需要与外部层中的插件交互,如持久性、Web 和优化。为了满足层之间的依赖项规则,服务和插件之间的交互以定义服务依赖项的接口表示。插件可以通过提供实现服务的边界接口的 bean 来满足服务的依赖项。Spring IoC 容器会创建一个插件 bean 实例,并在运行时将其注入该服务。这是控制原则的 inversion 示例。

12.5. 插件软件包

插件 软件包包含基础架构功能,如优化、持久性、路由和网络。

第 13 章 optaweb Vehicle Routing 后端配置属性

您可以设置下表中列出的 OptaWeb Vehicle Routing 应用程序属性。

属性类型示例描述

app.demo.data-set-dir

相对路径或绝对路径

/home/user/{VRP-DATA-DIR}/dataset

自定义数据集从此目录加载。默认为 local/dataset

app.persistence.h2-dir

相对路径或绝对路径

/home/user/{VRP-DATA-DIR}/db

H2 用来存储数据库文件的目录。默认为 local/db

app.region.country-codes

ISO 3166-1 alpha-2 国家代码列表

US,GB,IE,DE,AT,CH )可能为空

限制 geosearch 结果。

app.routing.engine

Enumeration

air,graphhopper

路由引擎实施。默认为 graphhopper

app.routing.gh-dir

相对路径或绝对路径

/home/user/{VRP-DATA-DIR}/graphhopper

GraphHopper 用来存储 road 网络图形的目录。默认为 local/graphhopper

app.routing.osm-dir

相对路径或绝对路径

/home/user/{VRP-DATA-DIR}/openstreetmap

包含 OSM 文件的目录。默认为 local/openstreetmap

app.routing.osm-file

文件名

belgium-latest.osm.pbf

GraphHopper 要载入的 OSM 文件的名称。该文件必须放在 app.routing.osm-dir 下。

optaplanner.solver.termination.spent-limit

java.time.Duration

  • 1m
  • 150s
  • P2dT21h (PnDTnHnMn.nS)

在位置更改后解析程序应运行的时间。

server.address

IP 地址或主机名

10.0.0.123, my-vrp.geo-1.openshiftapps.com

将服务器绑定到的网络地址。

server.port

端口号

4000, 8081

服务器 HTTP 端口。

部分 III. 使用 IDE 为红帽业务优化器运行和修改员工入门程序

作为自定义规则开发人员,您可以使用 IDE 来构建、运行和修改使用 Red Hat Business Optimizer 功能的 optaweb-employee startering 启动程序应用程序。

先决条件

  • 您可以使用集成开发环境,如 Red Hat CodeReady Studio 或 IntelliJ IDEA。
  • 您已了解 Java 语言。
  • 您已了解 React 和 TypeScript。这个要求需要开发 OptaWeb UI。

第 14 章 员工入门应用程序概述

员工入门程序应用为员工分配在机构的不同位置上移动的员工。例如,您可以使用应用程序在 nurses 之间分发转换,保护任务在多个位置间移动,或者在 worker 间移动行。

最佳员工必须考虑多个变量。例如,在不同位置上移动需要不同的知识。另外,一些员工可能不适用于一些时间插槽,或者可能首选特定的时间插槽。此外,员工可以有一个合同,限制员工可在单一时间段内工作的小时数。

该入门应用程序的 Red Hat Business Optimizer 规则使用硬和软限制。在优化过程中,规划引擎可能无法违反硬限制,例如,如果员工不可用(开箱即用),或者员工无法在单个迁移中工作两个点。规划引擎尝试遵循软限制,如员工的首选项无法进行特定的转换,但如果最佳解决方案需要,则可能会违反它们。

第 15 章 构建并运行员工入门程序应用程序

您可以从源代码构建员工漏洞启动程序应用,并将它作为 JAR 文件运行。

或者,您可以使用 IDE (如 Eclipse)(包括 Red Hat CodeReady Studio)来构建和运行应用程序。

15.1. 准备部署文件

您必须在构建和部署应用程序前下载并准备部署文件。

流程

  1. 从 Red Hat Process Automation Manager 7.10 的 Software Downloads 页面下载 rhpam-7.10.0-reference-ementation.zip 文件。
  2. 解压下载的存档。
  3. jboss-rhba-7.10.0.GA-maven-repository/maven-repository 子目录的内容复制到 ~/.m2/repository 目录中。
  4. 展开 rhpam-7.10.0-optaweb-employee-rostering.zip 文件,该文件是从参考实施存档中提取的。

    optaweb-employee-rostering-distribution-7.48.0.Final-redhat-00004 文件夹已创建。这个文件夹是本文档后续部分的基本文件夹。

    注意

    文件和文件夹名称可能比本文档中特别说明的版本号要高。

15.2. 运行 Employee Rostering starter 应用程序 JAR 文件

您可以从参考实施下载中包含的 JAR 文件运行 Employee Rostering starter 应用。

先决条件

  • 您已下载并提取了 rhpam-7.10.0-reference-ementation.zip 文件,如 第 15.1 节 “准备部署文件” 所述。
  • 安装了 Java Development Kit。
  • 已安装 Maven。
  • 主机可以访问互联网。构建过程使用互联网从外部存储库下载 Maven 软件包。

流程

  1. 在命令终端中,切换到 源目录
  2. 输入以下命令:

    mvn clean install -DskipTests
    Copy to Clipboard
  3. 等待构建过程完成。
  4. 导航到 optaweb-employee-rostering-distribution-7.48.0.Final-redhat-00004/sources/optaweb-employee-rostering-standalone/target 目录。
  5. 输入以下命令来运行 Employee Rostering JAR 文件:

    java -jar optaweb-employee-rostering-standalone-*-exec.jar
    Copy to Clipboard
    注意

    此命令使用非生产数据库启动员工的 rostering 应用程序。要使用生产数据库启动员工 rostering 应用程序,请在上一命令中添加 --spring.profiles.active=production 参数。

  6. 要访问应用程序,请在网页浏览器中输入 http://localhost:8080/

15.3. 使用 Maven 构建并运行 Employee Rostering starter 应用程序

您可以使用命令行来构建并运行员工漏洞入门程序应用程序。

如果您使用这个步骤,则数据存储在内存中,并在服务器停止时丢失。要使用数据库服务器构建并运行应用程序,请参阅 第 15.4 节 “使用命令行构建并运行带有持久数据存储的员工入门程序应用程序”

先决条件

  • 您已准备好部署文件,如 第 15.1 节 “准备部署文件” 所述。
  • 安装了 Java Development Kit。
  • 已安装 Maven。
  • 主机可以访问互联网。构建过程使用互联网从外部存储库下载 Maven 软件包。

流程

  1. 导航到 optaweb-employee-rostering-backend 目录。
  2. 使用以下命令:

    mvn spring-boot:run
    Copy to Clipboard
  3. 导航到 optaweb-employee-rostering-frontend 目录。
  4. 使用以下命令:

    npm start
    Copy to Clipboard
    注意

    如果您使用 npm 启动服务器,npm 会监控代码更改。

  5. 要访问应用程序,请在网页浏览器中输入 http://localhost:3000/

15.4. 使用命令行构建并运行带有持久数据存储的员工入门程序应用程序

如果您使用命令行来构建员工的启动程序应用并运行它,您可以为持久数据存储提供数据库服务器。

先决条件

  • 您已准备好部署文件,如 第 15.1 节 “准备部署文件” 所述。
  • 安装了 Java Development Kit。
  • 已安装 Maven。
  • 主机可以访问互联网。构建过程使用互联网从外部存储库下载 Maven 软件包。
  • 您已部署了 MySQL 或 PostrgeSQL 数据库服务器。

流程

  1. 在命令终端中,导航到 optaweb-employee-rostering-standalone/target 目录。
  2. 输入以下命令来运行 Employee Rostering JAR 文件:

    java -jar optaweb-employee-rostering-standalone-*-exec.jar --spring.profiles.active=production
    spring.datasource.url=<DATABASE_URL> --spring.datasource.username=<DATABASE_USER> --spring.datasource.password=<DATABASE_PASSWORD>
    Copy to Clipboard

    在本例中,替换以下占位符:

    • <DATABASE_URL > : 连接到数据库的 URL,如 jdbc:postgresql://postgresql:5432/MY_DATABASE
    • <DATABASE_USER > :要连接到数据库的用户
    • <DATABASE_PASSWORD& gt; :< DATABASE_USER>的密码

15.5. 使用 IntelliJ IDEA 构建和运行员工的入门程序应用程序

您可以使用 IntelliJ IDEA 构建和运行员工启动者应用程序。

先决条件

  • 您已从 Employee Rostering GitHub 页面下载了 Employee Rostering 源代码。
  • 已安装 IntelliJ IDEA、Maven 和 Node.js。
  • 主机可以访问互联网。构建过程使用互联网从外部存储库下载 Maven 软件包。

流程

  1. 启动 IntelliJ IDEA。
  2. 在 IntelliJ IDEA 主菜单中选择 FileOpen
  3. 选择应用程序源的根目录,再单击 OK
  4. 在主菜单中选择 RunEdit Configuration
  5. 在出现的窗口中,展开 Templates 并选择 Maven。此时会出现 Maven 边栏。
  6. 在 Maven 侧边栏中,从 Working Directory 菜单中选择 optaweb-employee-rostering-backend
  7. 在命令行中 输入 spring-boot:run
  8. 要启动后端,请单击 OK
  9. 在命令终端中,导航到 optaweb-employee-rostering-frontend 目录。
  10. 输入以下命令启动前端:

    npm start
    Copy to Clipboard
  11. 要访问应用程序,请在网页浏览器中输入 http://localhost:3000/

第 16 章 员工入门应用程序的源代码概述

员工的入门程序应用程序由以下主要组件组成:

  • 一个后端,它使用 Red Hat Business Optimizer 实现逻辑,并提供 REST API
  • 使用 React 实施用户界面并通过 REST API 与后端 模块交互的前端模块

您可以独立构建和使用这些组件。特别是,您可以实施不同的用户界面,并使用 REST API 调用服务器。

除了两个主要组件外,员工还包含随机源数据的生成器(用于演示和测试目的)和基准测试应用程序。

模块和密钥类

员工模板的 Java 源代码包含多个 Maven 模块。每个模块都包含单独的 Maven 项目文件(pom.xml),但它们则用于在通用项目中构建。

模块包含多个文件,包括 Java 类。本文档列出所有模块,以及包含员工计算关键信息的类和其他文件。

  • optaweb-employee-rostering-benchmark 模块:包含生成随机数据和基准测试解决方案的额外应用程序。
  • optaweb-employee-rostering-distribution 模块:包含 README 文件。
  • optaweb-employee-rostering-docs 模块:包含文档文件。
  • optaweb-employee-rostering-frontend 模块:将客户端应用程序与用户界面包含在 React 中。
  • optaweb-employee-rostering-backend 模块:包含使用红帽商业优化器执行计算的服务器应用程序。

    • src/main/java/org.optaweb.employeerostering.service.roster/rosterGenerator.java: 为演示和测试目的生成随机输入数据。如果您更改了所需的输入数据,请相应地更改生成器。
    • src/main/java/org.optaweb.employeerostering.domain.employee/EmployeeAvailability.java: 定义员工的可用性信息。对于每个插槽,员工都可以不可用、可用,也可以为员工指定首选的时区。
    • src/main/java/org.optaweb.employeerostering.domain.employee/Employee.java: 定义员工。员工具有名称、经验列表,并在合同下工作。知识由专家对象表示。
    • src/main/java/org.optaweb.employeerostering.domain.roster/Roster.java: 定义计算的信息。
    • src/main/java/org.optaweb.employeerostering.domain.shift/Shift.java: 定义可以为其分配员工的过渡。转换由一个时间插槽和点定义。例如,在 diner 中,在 2 月 20 8AM-4PM 时间插槽的 Kitchen spot 中可能会进行转换。可以为给定的 spot 和 time 插槽定义多个转换。在这种情况下,这个 spot 和 time 插槽需要多个员工。
    • src/main/java/org.optaweb.employeerostering.domain.skill/Skill.java: 定义员工可以拥有的承诺。
    • src/main/java/org.optaweb.employeerostering.domain.spot/Spot.java: 定义可以放置员工的 spot。例如,Kitchen 可以是 spot。
    • src/main/java/org.optaweb.employeerostering.domain.contract/Contract.java: 定义在不同时间段内为员工设置限制的合同。
    • src/main/java/org.optaweb.employeerostering.domain.tenant/Tenant.java: 定义租户。每个租户代表一组独立的数据。一个租户的数据更改不会影响任何其他租户。
    • bedoview.java :与域对象相关的类,用于定义从其他信息计算的值集;客户端应用可以通过 REST API 读取这些值,但不能写这些值。
    • evinceservice.java: 接口位于定义 REST API 的服务软件包中。服务器和客户端应用都单独定义这些接口的实施。

第 17 章 修改员工入门程序应用程序

要修改员工的入门程序应用程序以满足您的需要,您必须更改管理优化流程的规则。您还必须确保数据结构包含所需的数据,并为规则提供所需的计算。如果用户界面中没有所需的数据,还必须修改用户界面。

以下流程概述了修改员工漏洞入门应用程序的一般方法。

先决条件

  • 您有一个成功构建应用程序的构建环境。
  • 您可以读取和修改 Java 代码。

流程

  1. 规划所需的更改。回答以下问题:

    • 需要 避免的其他场景是什么?这些情况 比较困难
    • 优化器必须 尝试避免在可能的情况下避免 的其他场景?这些情况是 软限制
    • 在潜在解决方案中是否发生每个场景,是否需要计算数据是什么?
    • 哪些数据可以从用户在现有版本中输入的信息中派生?
    • 哪些数据可以被硬编码?
    • 用户必须输入哪些数据,且不会在当前版本中输入?
  2. 如果可以从当前数据计算任何所需数据或可以硬编码,请将计算或硬编码添加到现有视图或实用程序类中。如果必须在服务器端计算数据,请添加 REST API 端点来读取它。
  3. 如果用户必须输入任何所需数据,请将数据添加到代表数据实体(如 Employee 类)的类中,添加 REST API 端点来读取和写入数据,并修改用户界面以进入数据。
  4. 当所有数据都可用时,修改规则。对于大多数修改,您必须添加新规则。规则位于 optaweb-employee-rostering/service/solver/employeeRosteringScoreRules.drl 文件中的 src/main/resources/org / optaweb/employee-rostering-backend 模块。

    对规则使用 Drools 语言。有关 dros 规则语言的参考信息,请参阅使用 DRL 规则设计决策服务optaweb-employee-rostering-backend 模块中定义的类可供决策引擎使用。

  5. 修改应用程序后,构建并运行它。

部分 IV. 在 Red Hat OpenShift Container Platform 上为 Red Hat Business Optimizer 部署和使用员工入门程序

作为自定义规则开发人员,您可以通过快速部署 Red Hat Process Automation Manager 发行版本中包含的 optaweb-employee-rostering starter 项目来测试和与红帽业务优化器功能交互。

先决条件

  • 您可以访问已部署的 OpenShift 环境。详情请参阅您使用的 OpenShift 产品文档。

第 18 章 员工入门应用程序概述

员工入门程序应用为员工分配在机构的不同位置上移动的员工。例如,您可以使用应用程序在 nurses 之间分发转换,保护任务在多个位置间移动,或者在 worker 间移动行。

最佳员工必须考虑多个变量。例如,在不同位置上移动需要不同的知识。另外,一些员工可能不适用于一些时间插槽,或者可能首选特定的时间插槽。此外,员工可以有一个合同,限制员工可在单一时间段内工作的小时数。

该入门应用程序的 Red Hat Business Optimizer 规则使用硬和软限制。在优化过程中,规划引擎可能无法违反硬限制,例如,如果员工不可用(开箱即用),或者员工无法在单个迁移中工作两个点。规划引擎尝试遵循软限制,如员工的首选项无法进行特定的转换,但如果最佳解决方案需要,则可能会违反它们。

第 19 章 在 OpenShift 上安装并启动员工启动程序应用程序

您可以使用 OpenShift 模板或使用参考实施发行版中提供的 provision.sh shell 脚本,将 Employee Rostering 初学程序应用程序部署到 Red Hat OpenShift Container Platform 中。

runOnOpenShift.sh 脚本在本地构建并打包应用源代码,并将其上传到 OpenShift 环境以进行部署。此方法需要 Java Development Kit、Apache Maven 和 bash shell 命令行。

19.1. 使用提供的脚本部署应用程序

您可以使用提供的脚本将 Employee Rostering starter 应用程序部署到 Red Hat OpenShift Container Platform。该脚本在本地构建并打包应用源代码,并将其上传到 OpenShift 环境以进行部署。

先决条件

  • 您可以使用 oc 命令行工具登录到目标 OpenShift 环境。有关此工具的更多信息,请参阅 CLI 参考
  • Maven 和 Java Development Kit 安装在本地系统中。
  • 您的本地系统中提供了 bash shell 环境。

流程

  1. 从红帽客户门户的 软件下载 页面下载 rhpam-7.10.0-maven-repository.zip 文件。
  2. 展开下载的存档。
  3. jboss-rhba-7.10.0.GA-maven-repository/maven-repository 子目录的内容复制到 ~/.m2/repository 目录中。
  4. 从红帽客户门户的 软件下载页面下载 rhpam-7.10.0-reference-ement ation.zip 文件。
  5. 展开下载的存档。
  6. 解压从参考实施存档中提取的 rhpam-7.10.0-optaweb-employee-rostering.zip 文件。
  7. 使用命令行,切换到 optaweb-employee-rostering-distribution-7.48.0.Final-redhat-00004/sources 文件夹。
  8. 要构建 Employee Rostering 应用程序,请运行以下命令:

    mvn clean install -DskipTests -DskipITs
    Copy to Clipboard
  9. 登录到 OpenShift 帐户或 Red Hat Code Ready Container 实例。在以下示例中,< account-url& gt; 是 OpenShift 帐户或 Red Hat Code Ready Container 实例的 URL,&lt ;login-token > 是该帐户的登录令牌:

    oc login <account-url> --token <login-token>
    Copy to Clipboard
  10. 创建一个新项目来托管 Employee Rostering:

    oc new-project optaweb-employee-rostering
    Copy to Clipboard
  11. 运行置备脚本以构建和部署应用程序:

    ./provision.sh
    Copy to Clipboard

    编译和打包可能需要 10 分钟才能完成。这些进程持续显示命令行输出的进度。

    当操作完成后,会显示以下信息,其中 < URL& gt; 是部署的 URL:

    You can access the application at <URL> once the deployment is done.
    Copy to Clipboard
  12. 为 OpenShift 帐户或 Red Hat Code Ready Container 实例输入您之前在流程中使用的 URL,以访问部署的应用程序。第一个启动最多可能需要一分钟,因为 OpenShift 平台上完成额外的构建。

    注意

    如果应用程序在单击链接后没有打开一分钟,请执行浏览器页面的硬刷新。

第 20 章 使用员工入门程序应用程序

您可以使用 Web 界面使用 Employee Rostering starter 应用。接口在 ReactJS 中开发。您还可以根据需要访问 REST API 来创建自定义用户界面。

20.1. 草案和发布的周期

在任何特定时间,您可以使用应用程序在名为 草案 周期内创建 roster;默认情况下,草案期限的长度为三周。

当 roster 在草案的第一周内最终时,您可以 发布 roster。目前,当前草案前一周的 roster 将变为一个 公布的 周期。在发布的期间,roster 已被修复,您无法自动更改它(仍然有可能出现紧急的手动更改)。然后,可以将此类人员分发到员工,以便他们能够计划自己的时间。草案期将于一周。

例如,假定设置了 9 月 1 到 9 月 21 的草案。在此期间,您可以自动创建员工的 roster。然后,当您发布 roster 时,最多 9 月 7 期将发布。新的草案期为 9 月 8 日至 9 月 28 日。

有关发布 roster 的说明,请参考 第 20.12 节 “发布转换月”

20.2. 轮转模式

员工树形应用程序支持 轮转模式 来移动和员工。

轮转模式是从两天开始的任何时间的"model"周期。模式不与特定日期关联。

您可以为轮转的每天创建时区。每次存储桶设置转换的时间。(可选)模板可以包含转换的默认员工的名称。

当您发布 roster 时,应用程序会将新每周添加到草案周期。目前,如果适用,将默认员工名称从轮转模式复制到草案周期的新部分。

当达到轮转模式的末尾时,它会自动从开始重启。

如果您的机构中的每周转换模式与每周转换模式不同,请使用一周或整个周的轮转模式(如 14、21 或 28 天),默认长度为 28 天。然后,模式始终在同一星期天上重复,您可以为不同的 weekdays 设置转换。

有关编辑轮转模式的步骤,请参考 第 20.13 节 “查看和编辑轮转模式”

20.3. 员工随机租户

Employee Rostering 应用支持多个 租户。每个租户都是一组独立的数据,包括输入和输出输出。更改一个租户的数据不会影响其他租户。您可以在租户间切换以使用几个独立的数据集,例如,为不同的位置准备员工 rosters。

安装后会存在几个示例租户,代表几个典型的企业类型,如工厂或站。您可以选择这些租户,并对其进行修改以符合您的需要。您还可以创建新租户来从空白后输入数据。

20.3.1. 更改 Employee Rostering 租户

您可以更改当前的租户。选择其他租户后,所有显示的信息都引用此租户以及您只影响此租户的任何更改。

流程

  1. 在 Employee Rostering 应用 Web 界面中,在浏览器窗口的右上角点 Tenant 列表。
  2. 从列表中选择租户。

20.3.2. 创建租户

您可以创建新租户来从空白后后输入数据。在创建租户时,您可以设置几个参数,以确定应用程序如何为这个租户准备输出。

重要

您无法在创建租户后更改租户参数。

流程

  1. 要在 Employee Rostering 应用程序 Web 界面中创建新租户,请单击浏览器窗口右上角的设置(gear)图标,然后单击 Add
  2. 设置以下值:

    • 名称 :新租户的名称。此名称显示在租户列表中。
    • 计划开始日期 :初始草案的开始日期。发布 roster 后,此日期成为公布的周期的开始日期。此日期的星期日始终保持于周日,开始草案期、任何特定发布的周期以及轮转模式的第一个使用。因此,将开始日期设置为每周开始(Sunday 或 Monday)通常最方便。
    • 草案长度(天) :草案期限的长度。在租户生命周期内,草案期限保持相同的长度。
    • 发布 Notice (天) :发布通知期限的长度。我们计划提前为任何一天发布最后的攻击,因此员工有足够的通知来计划他们的个人生命周期。在当前版本中,不会以任何方式强制执行此设置。
    • 发布长度(天) :每次发布 roster 时发布(修复)的期限的长度。在当前版本中,此设置在 7 天解决。
    • 轮转长度(天) :轮转模式的长度。
    • Time Zone :应用 roster 的环境时区。此时区用于决定用户界面显示的"当前"日期。
  3. 点击 Save

租户使用空白数据创建。

20.4. 学习学习

您可以设置示例内任何位置上可以满足的所有知识。例如,除了一般人工资源和 restaurant 操作等知识外,24 小时划分程序还需要合作、服务、总线和托管知识。

流程

  1. 在 Employee Rostering application web 界面中,点 Skills 选项卡。

    您可以在浏览器窗口的右上角看到当前可见的也可以使用,例如 1-15 of 34。您可以使用 &lt ;& gt; 按钮来显示列表中的其他知识。

    您可以在搜索框中输入任何重要名称,以搜索学习。

  2. 完成以下步骤以添加新技术:

    1. 点击 Add
    2. Name 下的文本字段中输入新技术的名称。
    3. 点 Save 图标。
  3. 要编辑技术的名称,请单击技术旁边的 Edit Skill 图标(铅笔图标)。
  4. 要删除技术,请单击技术旁边的 Delete Skill 图标(trashcan compose)。
注意

在每个租户中,名称必须是唯一的。如果相关人员与员工或点相关联,则无法删除相关技术。

20.5. 输入 spots

您必须输入点 列表,它代表业务的不同位置。对于 diner,点包括栏、总线板、前端计数器、各种 kitchen 站、服务区域以及办公室。

对于每个 spot,您可以从 Skills 选项卡中输入的列表中选择一个或多个所需 知识。应用程序rosters 仅拥有该点中所有所需知识的员工。如果 spot 不需要参与,应用程序就可以将任何员工带入到 spot 中。

流程

  1. 要在 Employee Rostering application web 界面中输入或更改 spots,点 Spots 选项卡。您可以在搜索框中输入 spot 名称 的任何部分 以搜索 spots。
  2. 完成以下步骤以添加新 spot:

    1. Add Spot
    2. Name 下的文本字段中输入新 spot 的名称。
    3. 可选:从 Required technology set 下的下拉列表中选择一个或多个知识
    4. 点 Save 图标。
  3. 要编辑 spot 的名称和所需知识,请点击 spot 旁边的 Edit Spot 图标(铅笔图标)。
  4. 要删除点,请点击 spot 旁边的 Delete Spot 图标(栏)。
注意

在每个租户中,spot 名称必须是唯一的。当为其创建任何转换时,您无法删除 spot。

20.6. 输入合同列表

您必须输入业务用于员工的所有合同的列表。

合同决定了员工可在一周、日历月份、日历月份或日历年内工作的最长时间。

在创建合同时,您可以设置任何限制或根本不设置任何限制。例如,一个部分员工可能无法在一周内工作超过 20 小时,而全时间员工可能限制为 10 小时,年数为 1800 小时。另一个合同可能不包括工作小时的限制。

您必须以分钟为单位为合同输入所有工作时间限制。

流程

  1. 要在 Employee Rostering 应用程序 Web 界面中输入或更改合同列表,请点 Contracts 选项卡。

    您可以在浏览器窗口的右上角看到当前可见的合同数,例如 1-15 of 34。您可以使用 &lt ;& gt; 按钮来显示列表中的其他合同。

    您可以在搜索框中输入合同名称的任何部分 以搜索合同。

  2. 完成以下步骤以添加新合同:

    1. 点击 Add
    2. Name 下的文本字段中输入合同名称。
    3. Maximum minutes 下输入所需的时间限制:

      • 如果员工不能超过每天的集合时间,请在 Per Day 处启用复选框,然后在此复选框旁边的字段中输入分钟。
      • 如果员工不能超过每周的时间,请启用 Per Week 的复选框,并在此复选框旁边的字段中输入分钟数。
      • 如果员工不能超过每个日历月份的时间,请启用处于 Per Month 的复选框,然后在此复选框旁边的字段中输入分钟数。
      • 如果员工不得每年的日历时间超过一个时间,请在此复选框旁边的字段中输入分钟。
    4. 点 Save 图标。
  3. 要编辑合同的名称和时间限值,请点合同名称旁边的 Edit Contract 图标(铅笔图标)。
  4. 要删除合同,请单击合同名称旁边的 Delete Contract 图标(trashcan form)。
注意

在每个租户中,合同名称必须是唯一的。如果该合同分配给任何员工,则无法删除该合同。

20.7. 输入员工列表

您必须输入业务的所有员工、他们拥有的人员以及应用到他们的相关合同。应用程序会根据相关实践,并根据合同中的工作时间限制对员工进行关注。

流程

  1. 要在 Employee Rostering 应用程序 Web 界面中输入或更改员工列表,请点 Employees 选项卡。

    您可以在浏览器窗口的右上角看到当前可见的员工的数量,例如 1-15 of 34。您可以使用 &lt ;& gt; 按钮来显示列表中的其他员工。

    您可以在搜索框中输入员工名称的任何部分 以搜索员工。

  2. 完成以下步骤以添加新员工:

    1. 点击 Add
    2. Name 下的文本字段中输入员工的名称。
    3. 可选:从 Skill set 下的下拉列表中,选择一个或多个知识。
    4. Contract 下的下拉列表中选择一个合同。
    5. 点 Save 图标。
  3. 要编辑员工的名称和知识,请单击员工名称旁边的 Edit Employee 图标(铅笔图标)。
  4. 要删除员工,请单击员工名称旁边的 Delete Employee 图标(trashcan compose)。
注意

在每个租户中,员工名称必须是唯一的。如果员工被影响到任何转换,则无法删除员工。

20.8. 设置员工可用性

您可以为特定时间设置员工的可用性。

如果某个员工 在一定时间内不可用,则员工永远不会分配给此时间跨度(例如,如果员工在 sick 或为 vacation 中被调用)的任何变化。不必要、需要的是特定时间的员工首选项;应用程序尽可能容纳它们。

流程

  1. 要在 Employee Rostering 应用程序 Web 界面中查看和编辑员工可用性,请点 Availability Roster 选项卡。

    在窗口的左上方,您可以看到显示 roster 的日期。要查看其他周,您可以使用 Week of field 旁边的 & lt; 和 > 按钮。或者,您可以点击 date 字段并更改日期来查看包括此日期的星期。

  2. 要为员工创建一个可用性条目,请单击时间表的空空间,然后选择员工。最初,为整个日期创建一个 Unavailable 条目。
  3. 要更改可用性条目,请单击该条目。您可以更改以下设置:

    • fromTo date and time :可用性条目应用到的时间范围。
    • 状态:您可以从下拉列表中选择 UnavailableDesired、或 Undesired 状态。

      若要保存该条目,请单击 Apply

  4. 要删除可用性条目,请单击该条目,然后单击 Delete availability

    您还可以通过将鼠标指针移到条目上,然后点在条目中显示的图标之一来更改或删除可用性条目:

    • 点击 Unavailable 图标将条目的状态设置为 Unavailable
    • 点击 Undesired 图标将条目的状态设置为 Undesired
    • 点击 Desired 图标将条目的状态设置为 Desired
    • 点击 Delete 图标删除该条目。
重要

如果员工已经分配给转换,然后在这一转换过程中创建或更改可用性条目,则分配不会自动更改。您必须再次创建员工转换器,以应用新的或更改的可用条目。

20.9. 在转换的循环中查看和编辑转换

Shift Roster 是所有 spots 及所有可能的时间。

如果在时间跨度内必须有一个点中的员工,则必须存在此点的转换,此时会跨越时间。如果点同时需要多个员工,您可以为同一点和时间跨度创建多个转换。

每次转换都由点(箭头)和时间范围(column)的交集的 rectangle 表示。

当新时间添加到草案周期时,应用程序会将转换(如果存在)从轮转模式复制到草案周期的新部分。您还可以在草案期间手动添加并编辑转换。

流程

  1. 要在 Employee Rostering 应用程序 Web 界面中查看和编辑转换的 roster,点 Shift 选项卡。

    在窗口的左上方,您可以看到显示 roster 的日期。要查看其他周,您可以使用 Week of field 旁边的 & lt; 和 > 按钮。或者,您可以点击 date 字段并更改日期来查看包括此日期的星期。

  2. 要添加转换,请点击调度的开放区域。应用程序添加了一个转换,确定从点击位置自动决定插槽和时间跨度。
  3. 要编辑转换,请点击转换。您可以为转换设置以下值:

    • fromTo date and time :转换的确切时间和持续时间。
    • 员工 :分配给转换的员工。
    • 固定 :员工是否 固定到 转换中。如果员工被固定,则自动员工障碍无法更改员工的分配。固定员工不会自动复制到任何其他转换。

      若要保存更改,请单击 应用

  4. 要删除转换,请单击转换,然后单击 Delete shift

20.10. 创建并查看员工转换障碍

您可以使用应用程序为所有员工创建和查看最佳过渡。

流程

  1. 要在 Employee Rostering 应用程序 Web 界面中查看和编辑转换的 roster,点 Shift 选项卡。
  2. 要创建最佳转换月,请单击 Schedule。应用程序需要 30 秒才能找到最佳解决方案。

结果

操作完成后,Shift Roster 视图包含最佳转换器视图。在草案期内创建新的 roster;操作不会修改发布的周期。

在窗口的左上方,您可以看到显示 roster 的日期。要查看其他周,您可以使用 Week of field 旁边的 & lt; 和 > 按钮。或者,您可以点击 date 字段并更改日期来查看包括此日期的星期。

在草案周期中,代表转换的框的边框是点行。在发布的周期中,边框是 unbroken 行。

代表转换的框的颜色显示每次转换的约束状态:

  • 强绿色:软约束匹配;例如,迁移是员工的"必要" timeslot。
  • Pale green:没有约束无法正常工作。
  • grey: Soft constraint broken; 例如,转换人员位于员工的"未必要"的 timeslot 中。
  • 黄色:中等约束中断;例如,没有员工分配给迁移。
  • 红帽:硬约束中断;例如,员工同时发生了两个转换。

20.11. 查看员工转换

您可以在以员工为中心的表格中查看特定员工的分配转换。该信息与 Shift Roster 相同,但查看格式对于通知员工关于其分配的转换更加方便。

流程

要查看员工表并在 Employee Rostering 应用程序 Web 界面中移动,请点 Availability Roster 选项卡。

在窗口的左上方,您可以看到显示 roster 的日期。要查看其他周,您可以使用 Week of field 旁边的 & lt; 和 > 按钮。或者,您可以点击 date 字段并更改日期来查看包括此日期的星期。

您可以在浏览器窗口的右上角看到当前可见的员工的数量,例如 1-10 of 34。您可以使用数字旁边的 & lt; 和 > 按钮来显示列表中的其他员工。

在草案周期中,代表转换的框的边框是点行。在发布的周期中,边框是 unbroken 行。

20.12. 发布转换月

当您发布转换月时,草案的第一周将发布。虽然仍然有可能更改紧急手动更改,但自动员工不再更改发布的期间的任何转换分配。草案期将于一周后进行。有关草案和发布周期的详情,请参考 第 20.1 节 “草案和发布的周期”

流程

  1. 要在 Employee Rostering 应用程序 Web 界面中查看和编辑转换的 roster,点 Shift 选项卡。
  2. 查看草案第一周的转换月,以确保接受它。
  3. 单击 Publish

20.13. 查看和编辑轮转模式

轮转模式允许您添加、移动和删除转换,以便您可以有效地管理员工资源。它由时区和席位定义。

轮转
  • 时间存储桶描述了特定点或位置(例如,Anaesthetics)的时间段 (例如,9:00 a.m. 到 5:00 p.m)用于特定点或位置(例如,A naesthetics)的时间插槽,以及需要两天或更长的培训。
  • 席位 (B) 是特定日期在特定时间存储桶中的员工分配。
  • 员工存根是一个图标,它代表了可用于分配给时区的员工。员工存根列在 Employee Stub List 中。

有关轮转模式的详情,请参考 第 20.2 节 “轮转模式”

流程

  1. Rotation 选项卡查看和编辑轮转模式。
  2. Rotation 菜单中选择一个 spot。
  3. 单击 Add New Time Bucket。此时会显示 Creating Working Time Bucket 对话框。
  4. 指定开始和结束时间,选择任何其他必要的知识,选择此时间存储桶的天数,然后单击 Save。该时区的未分配的席位会出现在按时间范围组织的 Rotation 页面中。
  5. 要创建员工存根列表,以便您可以向轮转添加员工,请点 Edit Employee Stub List
  6. Edit Employee Stub List 对话框中,点 Add Employee,然后从列表中选择一个员工。
  7. 添加此 stub 列表所需的所有员工,然后单击保存。员工在 Rotation 页面上的时间 bucket 上面出现。
  8. 点员工图标,从员工存根列表中选择员工。
  9. 单击鼠标并将它拖到时区的席位上,以将选定的员工分配到那些席位。席位会填充员工图标。

    注意

    时间 bucket 每天只能为其分配一个员工。要将多个员工添加到同一时间存储桶,请复制时区并根据需要更改员工名称。

  10. 要置备计划,请点击 Scheduling,然后选择您为其创建轮转的 spot。
  11. Provision 并指定日期范围。
  12. 取消选择此计划中您不想包含的 spots。
  13. 点击所选 spot 旁边的箭头,并取消选择您不想在计划中使用的任何时间存储桶。
  14. Provision Shifts。日历填充自时区生成的转换。
  15. 要修改转换,请点击日历上生成的转换。

部分 V. 在 Spring Boot 中使用 Red Hat Business Optimizer

本指南指导您使用 Red Hat Business Optimizer 的约束创建 Spring Boot 应用程序的过程。您将构建 REST 应用程序,该应用程序针对领导和专业者进行了优化。

timeTableAppScreenshot

您的服务将通过 AI 遵循以下硬和软 调度限制,自动将附件实例分配给 TimeslotRoom 实例:

  • 空间最多可以同时有一个小时间。
  • 一个架构师可以同时参与一个小时间。
  • 每天最多可同时参与一个小时间。
  • 交互式人员更喜欢在单个房间参与。
  • 指导人员更喜欢参与较少的活动,并排解少量间的差距。

mathematly 认为是 NP 硬性问题。这意味着难以扩展。只需将所有可能的组合与括号一起进行迭代,在非平量数据集中,即使是超级计算器,则需要几十年的时间。AI 的约束程序(如 Red Hat Business Optimizer)具有高级算法,可在合理的时间内提供最接近的解决方案。认为是合理的时间,这取决于您的问题的目标。

先决条件

  • 已安装 OpenJDK 8 或更高版本。Red Hat build of Open JDK 位于红帽客户门户网站中的 Software Downloads 页面中(需要登录)。
  • 已安装 Apache Maven 3.2 或更高版本。Maven 可从 Apache Maven 项目网站 获得。
  • 提供了 IDE,如 IntelliJ IDEA、VSCode、Ecli 或 NetBeans。

第 21 章 下载并构建可写入时间参考实施

如果要看到带有 Spring Boot 产品的 Red Hat Business Optimizer timetable 项目的完整示例,请从红帽客户门户网站下载入门程序应用程序。

流程

  1. 导航到红帽客户门户网站中的 Software Downloads 页面(需要登录),然后从下拉菜单中选择产品和版本:

    • 产品 :Red Hat Process Automation Manager
    • Version: 7.10
  2. 下载 Red Hat Process Automation Manager 7.10 参考 实现(rhpam-7.10.0-reference- Implementationation.zip)。
  3. 下载 Red Hat Process Automation Manager 7.10 Maven Repository (rhpam-7.10.0-maven-repository.zip)。
  4. 提取 rhpam-7.10.0-maven-repository.zip 文件。
  5. rhpam-7.10.0-maven-repository/maven-repository 子目录的内容复制到 ~/.m2/repository 目录中。
  6. 提取 rhpam-7.10.0-reference-ementation.zip 文件。此存档包含参考 ZIP 文件。
  7. 解压 rhpam-7.10.0-reference-ementation/rhpam-7.10.0-optaplanner-spring-boot-rhcs-timetabling.zip 文件。
  8. 进入 optaplanner-spring-boot- thetabling-7.48.0.Final-redhat-00004 目录。
  9. 输入以下命令来构建 Spring Boot eXecut timetabling 项目:

    mvn clean install -DskipTests
    Copy to Clipboard
  10. 要构建 Spring Boot phone 时间建立项目,请输入以下命令:

    mvn spring-boot:run -DskipTests
    Copy to Clipboard
  11. 要查看项目,请在 Web 浏览器中输入以下 URL:

    http://localhost:8080/
    Copy to Clipboard

第 22 章 对域对象建模

红帽商业优化时间项目的目标是为每个更少的项目分配一个时间插槽和房间。要做到这一点,添加三个类: Timeslotinit on 和 Room,如下图所示:

timeTableClassDiagramPure

timeslot

Timeslot 类代表当减少活动为过期的时间间隔时,例如,Monday 10:30 - 11:30Tuesday 13:30 - 14:30。在这个示例中,所有时间段都有相同的持续时间,在 lunch 或其他中断过程中没有时间插槽。

一个时间插槽没有日期,因为每周计划只重复一次。不需要 持续规划Timeslot 被称为 问题事实,因为公司不会更改 Timeslot 实例。此类类不需要任何特定于 Red Hat Business Optimizer 的注解。

房间

Room 类代表更小活动的位置,例如 Room ARoom B。在本例中,所有房间都没有容量限制,它们可以容纳所有定义。

空间 实例在竞争过程中不会改变,因此 Room 也是 问题事实

lesson

在小时间中,由周一类代表,受一组参与者代表的规定,例如,A.Turing for 9th rating 或 Chemistry by M.Curie 代表第 10 等级如果一个主题是按同一站组相同的每周的多次,则有多个仅可通过 id 区分的实例。例如,第 9 等级每周有六个数学。

在电信期间,红帽业务优化器会更改周一类的 timeslotroom 字段,以将每个小时间分配给一个时间插槽和房间。因为 Red Hat Business Optimizer 更改了这些字段,因此 Apple on 是一个 规划实体

timeTableClassDiagramAnnotated

上图中的大部分字段都包含输入数据,但 orange 字段除外。在输入数据中取消分配较少的 timeslotroom 字段,并在输出数据中分配(而非 null)。红帽业务优化器在参与期间会改变这些字段。此类字段称为 规划变量。为了让红帽业务优化器识别它们,timeslotroom 字段都需要 @PlanningVariable 注释。它们包含类属性需要 @PlanningEntity 注释。

流程

  1. 创建 src/main/java/com/example/domain/Timeslot.java 类:

    package com.example.domain;
    
    import java.time.DayOfWeek;
    import java.time.LocalTime;
    
    public class Timeslot {
    
        private DayOfWeek dayOfWeek;
        private LocalTime startTime;
        private LocalTime endTime;
    
        private Timeslot() {
        }
    
        public Timeslot(DayOfWeek dayOfWeek, LocalTime startTime, LocalTime endTime) {
            this.dayOfWeek = dayOfWeek;
            this.startTime = startTime;
            this.endTime = endTime;
        }
    
        @Override
        public String toString() {
            return dayOfWeek + " " + startTime.toString();
        }
    
        // ********************************
        // Getters and setters
        // ********************************
    
        public DayOfWeek getDayOfWeek() {
            return dayOfWeek;
        }
    
        public LocalTime getStartTime() {
            return startTime;
        }
    
        public LocalTime getEndTime() {
            return endTime;
        }
    
    }
    Copy to Clipboard

    请注意,toString () 方法保留输出短,以便更轻松地阅读 Red Hat Business Optimizer 的 DEBUGTRACE 日志,如稍后所示。

  2. 创建 src/main/java/com/example/domain/Room.java 类:

    package com.example.domain;
    
    public class Room {
    
        private String name;
    
        private Room() {
        }
    
        public Room(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return name;
        }
    
        // ********************************
        // Getters and setters
        // ********************************
    
        public String getName() {
            return name;
        }
    
    }
    Copy to Clipboard
  3. 创建 src/main/java/com/example/domain/Lesson.java 类:

    package com.example.domain;
    
    import org.optaplanner.core.api.domain.entity.PlanningEntity;
    import org.optaplanner.core.api.domain.variable.PlanningVariable;
    
    @PlanningEntity
    public class Lesson {
    
        private Long id;
    
        private String subject;
        private String teacher;
        private String studentGroup;
    
        @PlanningVariable(valueRangeProviderRefs = "timeslotRange")
        private Timeslot timeslot;
    
        @PlanningVariable(valueRangeProviderRefs = "roomRange")
        private Room room;
    
        private Lesson() {
        }
    
        public Lesson(Long id, String subject, String teacher, String studentGroup) {
            this.id = id;
            this.subject = subject;
            this.teacher = teacher;
            this.studentGroup = studentGroup;
        }
    
        @Override
        public String toString() {
            return subject + "(" + id + ")";
        }
    
        // ********************************
        // Getters and setters
        // ********************************
    
        public Long getId() {
            return id;
        }
    
        public String getSubject() {
            return subject;
        }
    
        public String getTeacher() {
            return teacher;
        }
    
        public String getStudentGroup() {
            return studentGroup;
        }
    
        public Timeslot getTimeslot() {
            return timeslot;
        }
    
        public void setTimeslot(Timeslot timeslot) {
            this.timeslot = timeslot;
        }
    
        public Room getRoom() {
            return room;
        }
    
        public void setRoom(Room room) {
            this.room = room;
        }
    
    }
    Copy to Clipboard

    bring on 类有一个 @PlanningEntity 注释,因此 Red Hat Business Optimizer 知道这个类在周五期间发生了变化,因为它包含一个或多个规划变量。

    timeslot 字段有一个 @PlanningVariable 注释,因此 Red Hat Business Optimizer 知道它可以更改其值。为了查找分配给此字段的潜在 Timeslot 实例,Red Hat Business Optimizer 使用 valueRangeProviderRefs 属性连接到提供 List<Timeslot&gt; 的值范围供应商。有关值范围供应商的详情,请查看 第 24 章 在计划解决方案中收集域对象

    由于同样原因,room 字段也有一个 @PlanningVariable 注释。

第 23 章 定义约束并计算分数

当遇到问题时,分数 代表给定解决方案的质量。分数越大。红帽业务优化器正在寻找最佳解决方案,这是在可用时间提供的最高分数的解决方案。它可能 是最佳解决方案

因为 timetable 示例用例有硬和软限制,因此请使用 Hard SoftScore 类来代表分数:

  • 硬限制不能被破坏。例如: 一个房间可以同时有一个小时间。
  • 软限制不应中断。例如: 一个公司更喜欢在单个房间参与。

硬限制会与其他硬限制进行权重。软限制会与其他软限制加权。硬限制始终超过软限制,无论它们对应的权重是什么。

要计算分数,您可以实施 EasyScoreCalculator 类:

public class TimeTableEasyScoreCalculator implements EasyScoreCalculator<TimeTable> {

    @Override
    public HardSoftScore calculateScore(TimeTable timeTable) {
        List<Lesson> lessonList = timeTable.getLessonList();
        int hardScore = 0;
        for (Lesson a : lessonList) {
            for (Lesson b : lessonList) {
                if (a.getTimeslot() != null && a.getTimeslot().equals(b.getTimeslot())
                        && a.getId() < b.getId()) {
                    // A room can accommodate at most one lesson at the same time.
                    if (a.getRoom() != null && a.getRoom().equals(b.getRoom())) {
                        hardScore--;
                    }
                    // A teacher can teach at most one lesson at the same time.
                    if (a.getTeacher().equals(b.getTeacher())) {
                        hardScore--;
                    }
                    // A student can attend at most one lesson at the same time.
                    if (a.getStudentGroup().equals(b.getStudentGroup())) {
                        hardScore--;
                    }
                }
            }
        }
        int softScore = 0;
        // Soft constraints are only implemented in the "complete" implementation
        return HardSoftScore.of(hardScore, softScore);
    }

}
Copy to Clipboard

不幸的是,这个解决方案无法很好地扩展,因为它不可缩小:每次将小时间分配给不同的时区或空间时,所有定义都会被重新评估以计算新的分数。

更好的解决方案是创建一个 src/main/java/com/example/solver/TimeTableConstraintProvider.java 类来执行增量分数计算。此类使用红帽业务优化器的 ConstraintStream API,该 API 被 Java 8 Streams 和 SQL 提升。ConstraintProvider 扩展比 EasyScoreCalculator: O (n)而不是O(n)而不是 O(n)更好的 magnitude 顺序。

流程

创建以下 src/main/java/com/example/solver/TimeTableConstraintProvider.java 类:

package com.example.solver;

import com.example.domain.Lesson;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.optaplanner.core.api.score.stream.Constraint;
import org.optaplanner.core.api.score.stream.ConstraintFactory;
import org.optaplanner.core.api.score.stream.ConstraintProvider;
import org.optaplanner.core.api.score.stream.Joiners;

public class TimeTableConstraintProvider implements ConstraintProvider {

    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[] {
                // Hard constraints
                roomConflict(constraintFactory),
                teacherConflict(constraintFactory),
                studentGroupConflict(constraintFactory),
                // Soft constraints are only implemented in the "complete" implementation
        };
    }

    private Constraint roomConflict(ConstraintFactory constraintFactory) {
        // A room can accommodate at most one lesson at the same time.

        // Select a lesson ...
        return constraintFactory.from(Lesson.class)
                // ... and pair it with another lesson ...
                .join(Lesson.class,
                        // ... in the same timeslot ...
                        Joiners.equal(Lesson::getTimeslot),
                        // ... in the same room ...
                        Joiners.equal(Lesson::getRoom),
                        // ... and the pair is unique (different id, no reverse pairs)
                        Joiners.lessThan(Lesson::getId))
                // then penalize each pair with a hard weight.
                .penalize("Room conflict", HardSoftScore.ONE_HARD);
    }

    private Constraint teacherConflict(ConstraintFactory constraintFactory) {
        // A teacher can teach at most one lesson at the same time.
        return constraintFactory.from(Lesson.class)
                .join(Lesson.class,
                        Joiners.equal(Lesson::getTimeslot),
                        Joiners.equal(Lesson::getTeacher),
                        Joiners.lessThan(Lesson::getId))
                .penalize("Teacher conflict", HardSoftScore.ONE_HARD);
    }

    private Constraint studentGroupConflict(ConstraintFactory constraintFactory) {
        // A student can attend at most one lesson at the same time.
        return constraintFactory.from(Lesson.class)
                .join(Lesson.class,
                        Joiners.equal(Lesson::getTimeslot),
                        Joiners.equal(Lesson::getStudentGroup),
                        Joiners.lessThan(Lesson::getId))
                .penalize("Student group conflict", HardSoftScore.ONE_HARD);
    }

}
Copy to Clipboard

第 24 章 在计划解决方案中收集域对象

TimeTable 实例将单个数据集的所有 TimeslotRoom 和 Appleon 实例嵌套。另外,由于它包含所有 lessons,每个都具有特定的计划变量状态,所以它是一个 规划解决方案,它具有分数:

  • 如果仅未被分配,则它是一个 未初始化的 解决方案,例如,分数为 -4init/0hard/0soft 的解决方案。
  • 如果它破坏硬限制,则是一个不可行的解决方案,例如,分数为 -2hard/-3soft 的解决方案。
  • 如果它遵循所有硬限制,那么它是一种可行的解决方案,例如,分数为 0hard/-7soft 的解决方案。

TimeTable 类有一个 @PlanningSolution 注释,因此 Red Hat Business Optimizer 知道这个类包含所有输入和输出数据。

具体来说,这个类是问题的输入:

  • 带有所有时间插槽的 timeslotList 字段

    • 这是问题事实列表,因为它们在竞争过程中不会改变。
  • 包含所有空间的 roomList 字段

    • 这是问题事实列表,因为它们在竞争过程中不会改变。
  • 带有所有 lessons 的 lessonList 字段

    • 这是规划实体的列表,因为它们在竞争期间发生了变化。
    • 每个 周一

      • timeslotroom 字段的值通常仍然为空,因此未分配。它们正在规划变量。
      • 其他字段(如 subject、MrrslirpGroup )已填写。这些字段是问题属性。

但是,此类也是解决方案的输出:

  • 一个 lessonList 字段,其中每个 每天 实例在周五后都有非空 timeslotroom 字段
  • 代表输出解决方案的质量的 score 字段,例如 0hard/-5soft

流程

创建 src/main/java/com/example/domain/TimeTable.java 类:

package com.example.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.drools.ProblemFactCollectionProperty;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;

@PlanningSolution
public class TimeTable {

    @ValueRangeProvider(id = "timeslotRange")
    @ProblemFactCollectionProperty
    private List<Timeslot> timeslotList;

    @ValueRangeProvider(id = "roomRange")
    @ProblemFactCollectionProperty
    private List<Room> roomList;

    @PlanningEntityCollectionProperty
    private List<Lesson> lessonList;

    @PlanningScore
    private HardSoftScore score;

    private TimeTable() {
    }

    public TimeTable(List<Timeslot> timeslotList, List<Room> roomList,
            List<Lesson> lessonList) {
        this.timeslotList = timeslotList;
        this.roomList = roomList;
        this.lessonList = lessonList;
    }

    // ********************************
    // Getters and setters
    // ********************************

    public List<Timeslot> getTimeslotList() {
        return timeslotList;
    }

    public List<Room> getRoomList() {
        return roomList;
    }

    public List<Lesson> getLessonList() {
        return lessonList;
    }

    public HardSoftScore getScore() {
        return score;
    }

}
Copy to Clipboard

值范围供应商

timeslotList 字段是一个值范围供应商。它包括了 Red Hat Business Optimizer 可以从这个实例分配 to to the timeslot 字段的 Timeslot 实例。timeslotList 字段有一个 @ValueRangeProvider 注释来连接这两个注解,方法是将 id 与大括号中的 @PlanningVariablevalueRangeProviderRefs 匹配。

遵循同样的逻辑,roomList 字段也具有 @ValueRangeProvider 注释。

问题事实和规划实体属性

此外,Red Hat Business Optimizer 需要了解它可以更改哪些实例,以及如何检索用于 TimeTableConstraintProviderTimeslotRoom 实例。

timeslotListroomList 字段有一个 @ProblemFactCollectionProperty 注解,因此您的 TimeTableConstraintProvider 可以从这些实例中选择。

lessonList 有一个 @PlanningEntityCollectionProperty 注释,因此 Red Hat Business Optimizer 可在将来更改它们,而您的 TimeTableConstraintProvider 也可以从这些中选择。

第 25 章 创建 Timetable 服务

现在,您已准备好将所有内容放在一起,并创建一个 REST 服务。但是,在 REST 线程上计划问题会导致 HTTP 超时问题。因此,Spring Boot Start 注入 SolverManager,它会在一个单独的线程池中运行 solvers,并可并行解决多个数据集。

流程

创建 src/main/java/com/example/solver/TimeTableController.java 类:

package com.example.solver;

import java.util.UUID;
import java.util.concurrent.ExecutionException;

import com.example.domain.TimeTable;
import org.optaplanner.core.api.solver.SolverJob;
import org.optaplanner.core.api.solver.SolverManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/timeTable")
public class TimeTableController {

    @Autowired
    private SolverManager<TimeTable, UUID> solverManager;

    @PostMapping("/solve")
    public TimeTable solve(@RequestBody TimeTable problem) {
        UUID problemId = UUID.randomUUID();
        // Submit the problem to start solving
        SolverJob<TimeTable, UUID> solverJob = solverManager.solve(problemId, problem);
        TimeTable solution;
        try {
            // Wait until the solving ends
            solution = solverJob.getFinalBestSolution();
        } catch (InterruptedException | ExecutionException e) {
            throw new IllegalStateException("Solving failed.", e);
        }
        return solution;
    }

}
Copy to Clipboard

在本例中,初始实施会等待 solver 完成,这仍然可能导致 HTTP 超时。完整的 实现可避免 HTTP 超时更小。

第 26 章 设置解析器终止时间

如果您的计划应用程序没有终止设置或终止事件,则理论上会永久运行,并且实际上会导致 HTTP 超时错误。要防止发生这种情况,请使用 optaplanner.solver.termination.spent-limit 参数指定应用程序终止的时间长度。在大多数应用程序中,将时间设置为至少五分钟(5m)。但是,在 Timetable 示例中,将过期时间限制为 5 秒,这足够短,以避免 HTTP 超时。

流程

使用以下内容创建 src/main/resources/application.properties 文件:

optaplanner.solver.termination.spent-limit=5s
Copy to Clipboard

第 27 章 使应用程序可执行

完成 Red Hat Business Optimizer Spring Boot timetable 项目后,将所有内容打包成单一可执行 JAR 文件中,由标准 Java main () 方法驱动。

先决条件

  • 您已完成了 Red Hat Business Optimizer Spring Boot timetable 项目。

流程

  1. 使用以下内容创建 TimeTableSpringBootApp.java 类:

    package com.example;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class TimeTableSpringBootApp {
    
        public static void main(String[] args) {
            SpringApplication.run(TimeTableSpringBootApp.class, args);
        }
    
    }
    Copy to Clipboard
  2. 将由 Spring Initializr 创建的 src/main/java/com/example/DemoApplication.java 类替换为 TimeTableSpringBootApp.java 类。
  3. 运行 TimeTableSpringBootApp.java 类作为常规 Java 应用程序的主类。

27.1. 尝试 timetable 应用程序

启动 Red Hat Business Optimizer Spring Boot timetable 应用程序后,您可以使用您想要的任何 REST 客户端测试 REST 服务。这个示例使用 Linux curl 命令来发送 POST 请求。

先决条件

  • Red Hat Business Optimizer Spring Boot timetable 应用程序正在运行。

流程

使用以下命令:

$ curl -i -X POST http://localhost:8080/timeTable/solve -H "Content-Type:application/json" -d '{"timeslotList":[{"dayOfWeek":"MONDAY","startTime":"08:30:00","endTime":"09:30:00"},{"dayOfWeek":"MONDAY","startTime":"09:30:00","endTime":"10:30:00"}],"roomList":[{"name":"Room A"},{"name":"Room B"}],"lessonList":[{"id":1,"subject":"Math","teacher":"A. Turing","studentGroup":"9th grade"},{"id":2,"subject":"Chemistry","teacher":"M. Curie","studentGroup":"9th grade"},{"id":3,"subject":"French","teacher":"M. Curie","studentGroup":"10th grade"},{"id":4,"subject":"History","teacher":"I. Jones","studentGroup":"10th grade"}]}'
Copy to Clipboard

大约 5 秒后,终止花费 application.properties 中定义的时间,服务会返回类似以下示例的输出:

HTTP/1.1 200
Content-Type: application/json
...

{"timeslotList":...,"roomList":...,"lessonList":[{"id":1,"subject":"Math","teacher":"A. Turing","studentGroup":"9th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"08:30:00","endTime":"09:30:00"},"room":{"name":"Room A"}},{"id":2,"subject":"Chemistry","teacher":"M. Curie","studentGroup":"9th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"09:30:00","endTime":"10:30:00"},"room":{"name":"Room A"}},{"id":3,"subject":"French","teacher":"M. Curie","studentGroup":"10th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"08:30:00","endTime":"09:30:00"},"room":{"name":"Room B"}},{"id":4,"subject":"History","teacher":"I. Jones","studentGroup":"10th grade","timeslot":{"dayOfWeek":"MONDAY","startTime":"09:30:00","endTime":"10:30:00"},"room":{"name":"Room B"}}],"score":"0hard/0soft"}
Copy to Clipboard

请注意,应用程序将所有四个小项分配给两个时间插槽之一,以及两个空间之一。另请注意,它符合所有硬限制。例如,M. Curie 的两个定义位于不同的时间段内。

在服务器端,info 日志显示 Red Hat Business Optimizer 在 5 秒内的作用:

... Solving started: time spent (33), best score (-8init/0hard/0soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
... Construction Heuristic phase (0) ended: time spent (73), best score (0hard/0soft), score calculation speed (459/sec), step total (4).
... Local Search phase (1) ended: time spent (5000), best score (0hard/0soft), score calculation speed (28949/sec), step total (28398).
... Solving ended: time spent (5000), best score (0hard/0soft), score calculation speed (28524/sec), phase total (2), environment mode (REPRODUCIBLE).
Copy to Clipboard

27.2. 构建应用程序

良好的应用程序包括测试覆盖。这个示例测试了 Timetable Red Hat Business Optimizer Spring Boot 应用程序。它使用 JUnit 测试来生成测试数据集,并将其发送到 TimeTableController 来解决。

流程

使用以下内容创建 src/test/java/com/example/solver/TimeTableControllerTest.java 类:

package com.example.solver;

import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

import com.example.domain.Lesson;
import com.example.domain.Room;
import com.example.domain.TimeTable;
import com.example.domain.Timeslot;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@SpringBootTest(properties = {
        "optaplanner.solver.termination.spent-limit=1h", // Effectively disable this termination in favor of the best-score-limit
        "optaplanner.solver.termination.best-score-limit=0hard/*soft"})
public class TimeTableControllerTest {

    @Autowired
    private TimeTableController timeTableController;

    @Test
    @Timeout(600_000)
    public void solve() {
        TimeTable problem = generateProblem();
        TimeTable solution = timeTableController.solve(problem);
        assertFalse(solution.getLessonList().isEmpty());
        for (Lesson lesson : solution.getLessonList()) {
            assertNotNull(lesson.getTimeslot());
            assertNotNull(lesson.getRoom());
        }
        assertTrue(solution.getScore().isFeasible());
    }

    private TimeTable generateProblem() {
        List<Timeslot> timeslotList = new ArrayList<>();
        timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(8, 30), LocalTime.of(9, 30)));
        timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(9, 30), LocalTime.of(10, 30)));
        timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(10, 30), LocalTime.of(11, 30)));
        timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(13, 30), LocalTime.of(14, 30)));
        timeslotList.add(new Timeslot(DayOfWeek.MONDAY, LocalTime.of(14, 30), LocalTime.of(15, 30)));

        List<Room> roomList = new ArrayList<>();
        roomList.add(new Room("Room A"));
        roomList.add(new Room("Room B"));
        roomList.add(new Room("Room C"));

        List<Lesson> lessonList = new ArrayList<>();
        lessonList.add(new Lesson(101L, "Math", "B. May", "9th grade"));
        lessonList.add(new Lesson(102L, "Physics", "M. Curie", "9th grade"));
        lessonList.add(new Lesson(103L, "Geography", "M. Polo", "9th grade"));
        lessonList.add(new Lesson(104L, "English", "I. Jones", "9th grade"));
        lessonList.add(new Lesson(105L, "Spanish", "P. Cruz", "9th grade"));

        lessonList.add(new Lesson(201L, "Math", "B. May", "10th grade"));
        lessonList.add(new Lesson(202L, "Chemistry", "M. Curie", "10th grade"));
        lessonList.add(new Lesson(203L, "History", "I. Jones", "10th grade"));
        lessonList.add(new Lesson(204L, "English", "P. Cruz", "10th grade"));
        lessonList.add(new Lesson(205L, "French", "M. Curie", "10th grade"));
        return new TimeTable(timeslotList, roomList, lessonList);
    }

}
Copy to Clipboard

此测试会验证之后,所有较少记录都会被分配给一个时间插槽和房间。它还会验证它发现了一个可行的解决方案(没有硬约束中断)。

通常,解析器会在 200 毫秒内找到可行的解决方案。请注意,@SpringBootTest 注释 的属性 如何覆盖 solver 终止,以便在找到可行的解决方案(0hard soft)时立即终止。这可避免硬编码一个固定时间,因为单元测试可能会在任意硬件上运行。这种方法可确保测试运行足够长,以找到可行的解决方案,即使在较慢的机器上也是如此。但是,即使在快速机器上,它不会运行毫秒的时间超过它。

27.3. 日志记录

完成 Red Hat Business Optimizer Spring Boot timetable 应用程序后,您可以使用日志信息来帮助微调 ConstraintProvider 中的限制。查看 info 日志文件中的分数计算速度,以评估对您的限制的影响。以调试模式运行应用程序,以显示应用程序采取的每个步骤,或使用 trace 日志记录来记录每个步骤和每次移动。

流程

  1. 在固定时间内运行 timetable 应用程序,例如五分钟。
  2. 查看日志文件中的分数计算速度,如下例所示:

    ... Solving ended: ..., score calculation speed (29455/sec), ...
    Copy to Clipboard
  3. 更改约束,在相同时间内再次运行 planning 应用程序,并查看日志文件中记录的分数计算速度。
  4. 以 debug 模式运行应用程序以记录每个步骤:

    • 要从命令行运行调试模式,请使用 -D 系统属性。
    • 要更改 application.properties 文件中的日志记录,请在该文件中添加以下行:

      logging.level.org.optaplanner=debug
      Copy to Clipboard

      以下示例以 debug 模式显示 日志文件中 的输出:

      ... Solving started: time spent (67), best score (-20init/0hard/0soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
      ...     CH step (0), time spent (128), score (-18init/0hard/0soft), selected move count (15), picked move ([Math(101) {null -> Room A}, Math(101) {null -> MONDAY 08:30}]).
      ...     CH step (1), time spent (145), score (-16init/0hard/0soft), selected move count (15), picked move ([Physics(102) {null -> Room A}, Physics(102) {null -> MONDAY 09:30}]).
      ...
      Copy to Clipboard
  5. 使用 trace 日志记录来显示每个步骤,以及每个步骤的每次移动。

第 28 章 添加数据库和 UI 集成

使用 Spring Boot 创建 Red Hat Business Optimizer 应用程序示例后,添加数据库和 UI 集成。

前提条件

  • 您已创建了 Red Hat Business Optimizer Spring Boot timetable 示例。

流程

  1. TimeslotRoom 和 Pricingon 创建 Java Persistence API (DSL)存储库。有关创建 JPA 存储库的详情,请参考在 Spring 网站上 使用 JPA 访问数据。
  2. 通过 REST 公开 JPA 存储库。有关公开存储库的详情,请参考 Spring 网站 使用 REST 访问 JPA 数据
  3. 构建 TimeTableRepository facade,在单个事务中读取和写入 TimeTable
  4. 按照以下示例所示调整 TimeTableController

    package com.example.solver;
    
    import com.example.domain.TimeTable;
    import com.example.persistence.TimeTableRepository;
    import org.optaplanner.core.api.score.ScoreManager;
    import org.optaplanner.core.api.solver.SolverManager;
    import org.optaplanner.core.api.solver.SolverStatus;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/timeTable")
    public class TimeTableController {
    
        @Autowired
        private TimeTableRepository timeTableRepository;
        @Autowired
        private SolverManager<TimeTable, Long> solverManager;
        @Autowired
        private ScoreManager<TimeTable> scoreManager;
    
        // To try, GET http://localhost:8080/timeTable
        @GetMapping()
        public TimeTable getTimeTable() {
            // Get the solver status before loading the solution
            // to avoid the race condition that the solver terminates between them
            SolverStatus solverStatus = getSolverStatus();
            TimeTable solution = timeTableRepository.findById(TimeTableRepository.SINGLETON_TIME_TABLE_ID);
            scoreManager.updateScore(solution); // Sets the score
            solution.setSolverStatus(solverStatus);
            return solution;
        }
    
        @PostMapping("/solve")
        public void solve() {
            solverManager.solveAndListen(TimeTableRepository.SINGLETON_TIME_TABLE_ID,
                    timeTableRepository::findById,
                    timeTableRepository::save);
        }
    
        public SolverStatus getSolverStatus() {
            return solverManager.getSolverStatus(TimeTableRepository.SINGLETON_TIME_TABLE_ID);
        }
    
        @PostMapping("/stopSolving")
        public void stopSolving() {
            solverManager.terminateEarly(TimeTableRepository.SINGLETON_TIME_TABLE_ID);
        }
    
    }
    Copy to Clipboard

    为了简单起见,此代码仅处理一次 TimeTable 实例,但易于启用多租户并并行处理不同高站的多个时间表实例。

    getTimeTable () 方法返回数据库的最新时间表。它使用 ScoreManager (自动注入)计算该时间的分数,以便 UI 能够显示分数。

    resolve () 方法启动一个作业,以解决当前时间集中,并将时间插槽和房间分配存储在数据库中。它使用 SolverManager.solveAndListen () 方法侦听中间最佳解决方案并相应地更新数据库。这可让 UI 在后端仍在竞争时显示进度。

  5. 现在,solv () 方法会立即返回,调整 TimeTableControllerTest,如下例所示:

    package com.example.solver;
    
    import com.example.domain.Lesson;
    import com.example.domain.TimeTable;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.Timeout;
    import org.optaplanner.core.api.solver.SolverStatus;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import static org.junit.jupiter.api.Assertions.assertFalse;
    import static org.junit.jupiter.api.Assertions.assertNotNull;
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    @SpringBootTest(properties = {
            "optaplanner.solver.termination.spent-limit=1h", // Effectively disable this termination in favor of the best-score-limit
            "optaplanner.solver.termination.best-score-limit=0hard/*soft"})
    public class TimeTableControllerTest {
    
        @Autowired
        private TimeTableController timeTableController;
    
        @Test
        @Timeout(600_000)
        public void solveDemoDataUntilFeasible() throws InterruptedException {
            timeTableController.solve();
            TimeTable timeTable = timeTableController.getTimeTable();
            while (timeTable.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);
                timeTable = timeTableController.getTimeTable();
            }
            assertFalse(timeTable.getLessonList().isEmpty());
            for (Lesson lesson : timeTable.getLessonList()) {
                assertNotNull(lesson.getTimeslot());
                assertNotNull(lesson.getRoom());
            }
            assertTrue(timeTable.getScore().isFeasible());
        }
    
    }
    Copy to Clipboard
  6. 轮询最新的解决方案,直到解决方案完成。
  7. 要视觉化时间表,请在这些 REST 方法之上构建高级 Web UI。

附录 A. 版本信息

文档最后在 2022 年 3 月 8 日更新。

附录 B. 联系信息

Red Hat Process Automation Manager 文档团队: brms-docs@redhat.com

法律通告

Copyright © 2023 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat