深入建模艺术:MiniZinc工具的使用指南(续)——揭秘模型与数据分离的抽象化策略

优化建模之MiniZinc(二) 模型的抽象化 -- 模型与信息的隔离

在前一篇文章中,我们阐述了MiniZinc程序的核心构成要素。

为了回顾,让我们审视一个生产安排问题:

我们在边界与敌对势力对峙,由于禁止开火,我们需要制造一批冷兵器来装备军队,可供选择的兵器有长矛、剑和锤子;制造兵器需耗费一定资源和工匠的时间,各类兵器对应的资源消耗如下:

我们的资源是有限的:

每种兵器对应一定的战斗力:

我们期望充分利用有限资源以最大化军队战斗力,那么各类兵器需要生产多少件呢?

相应的模型如下:

经过求解,我们可以得到答案:

模型中涉及数组和内置函数的相关内容,可以查阅后续对MiniZinc语法的详细解释。

该模型看似无误,求解过程也顺利。然而,在众多情况下,我们在建模时往往会遇到一系列假设性问题:若资源有所增加,情形将如何?若增加更多兵器种类,又将如何?

我们必须不断调整上述具体模型,以应对不断变化的数据。

若我们不是在解决兵器生产问题,而是在制定期末复习计划呢?我们是否需要重新编写整个模型呢?

在软件工程领域,设计模式为我们提供了重要的启示,即将变化的部分与相对稳定的部分分离,对于模型而言,亦是如此。在相同类型的生产安排模型中,存在一些共性,我们可以提取这些共性,并将数据独立出来。

生产安排模型

在生产安排模型中,我们可以提炼出一些共性:

基于这些共性,我们可以构建一个抽象模型(2_2_AbstractProductionModel.mzn):

我们注意到,在抽象模型中并未包含任何数据。这样我们就实现了模型与信息的分离,对于同一个模型,我们可以用它来解决具有相似性质的不同数据集。

为了验证,我们可以将之前的兵器生产问题构建一个独立的数据集2_2_WeaponProduction.dzn如下:

在命令行中执行minizinc--solver CBC 2_2_AbstractProductionModel.mzn 2_2_WeaponProduction.dzn,指定数据集和求解器进行求解,得到结果:

可以看到,对于兵器生产问题,我们得到的结果与之前相同。

学习时间分配问题

抽象模型的优势在于可以用它来处理同一类问题。利用之前建立的生产安排模型,我们可以探讨以下一个时间分配问题:

我们面临三门课程的期末考试,分别是运筹学、离散数学和C语言,对于每门课程的复习,一个理想的方案是分别分配一定的上机复习、讨论和书本自学时间,各门课程理想复习方案的时间比例如下:

但由于机房、讨论室和自学室各自存在时间限制,我们在考试前能够预约的时间如下:

每花费一个小时在不同科目上,我们能够提升不同的平均GPA:

假设我们起点较低,这轮复习不会使任何科目的GPA达到满分,但我们希望尽可能提高GPA,那么应该如何分配剩余的复习时间呢?

我们发现这个问题实际上也是生产安排问题的一类,我们并不需要对模型进行任何修改,只需修改数据集即可。我们建立一个数据文件2_2_StudyTime.dzn,放入相应的课程、用时和收益:

在命令行执行minizinc--solver CBC 2_2_AbstractProductionModel.mzn 2_2_StudyTime.dzn进行求解:

得到结果:

因此,在建模过程中,通常建议对模型进行抽象化,将模型文件和数据文件分离。

在上面的程序中,我们使用了如下语句:

这条语句定义了一个二维数组consumption,其维度分别为WEAPONS和RESOURCES。

数组是一种常用的数据结构,我们将在后面介绍数组的相关知识:

数组可以是一维或多维的,在声明时使用如下格式:

array[index_set1, index_set2,...] of

数组下标的集合可以是枚举类型或者是某个集合表达式。

数组内的元素可以是除了数组以外的任何内置类型,也就是说MiniZinc不支持数组嵌套。

一维数组

对于一维数组,我们可以用列表的方式进行初始化,这与其他大多数语言类似,例如以下这些示例:

二维数组

MiniZinc中二维数组的初始化具有特定的语法:

一个示例就是我们上面定义的二维数组:

特别需要注意的是结尾,不要忘记|符号。

内置函数初始化任意维度数组

对于任何维度k不大于6的数组,我们都可以使用内置函数arraykd进行初始化,例如:

分别等价于我们上面的一维和二维数组初始化方式。

除了使用内置函数或列表形式进行初始化外,MiniZinc还提供了类似于Python的推导式方式对数组进行初始化。其语法为:

[|,,...]

在推导过程中,我们也可以进行一些检验:

[|,,..., where]

例如:

会生成以下两个数组

注意,由于我们事先不知道数组的长度,我们使用了array[int]来让求解器自行推导数组长度。

相应的,集合也可以使用推导式的方式生成,唯一的不同在于用{}替换[]。

由于在列表推导式的应用中,我们可能产生不知道列表下标范围的情况。此时,我们可以使用内置函数index_set来获取一维数组的下标范围。

例如:

这里,我们的k将得到范围1..12。

对于多维数组,我们需要指定数组的总维度k和想要获取的具体维度m的下标。

MiniZinc中内置了一系列函数index_set_of来帮助我们获取下标,其中k<=6。例如,我们想获取二维数组第二个维度的下标,我们就可以使用函数index_set_2of2。

MiniZinc内置了一系列函数 index_set_of来协助我们获取索引,其中 k≤6。例如,若要获取二维数组第二个维度的索引,我们可以使用函数 index_set_2of2。

MiniZinc支持的基本整数运算包括加减乘除等四则运算:+,-,, div。对于浮点数,除法以/表示。

请注意,这里的整数除法使用的是 div而非/,/在MiniZinc中专门指代浮点数的除法,处理整数时可能会出现意想不到的结果。

除此之外,还有我们常用的取余运算 mod,整数的取余运算 a mod b会得到与a同号的结果,也就是说,一定存在 a= b(a div b)+(a mod b)。

以下是一些在MiniZinc中常用的内置运算函数。

对于数字:

对于数组:

离线编程工业机器人有哪些注意事项

离线编程指的是在计算机上预先构建和优化工业机器人的程序,随后将这些程序导入机器人控制器中,以便机器人在实际生产中自动执行任务。在执行工业机器人的离线编程时,以下是一些需要注意的事项:

1.明确工作环境:在离线编程前,了解机器人将要工作的实际环境至关重要。考虑到机器人在作业中可能遇到的障碍、安全风险和工作空间限制,以便在编程过程中做出恰当的决策。

2.确定任务要求:明确机器人需要完成的任务,包括运动轨迹、工具路径和操作顺序等。确保在离线编程中将所有任务要求准确建模。

3.选择恰当的离线编程软件:选择适用于你机器人品牌和型号的离线编程软件。这些软件通常提供虚拟仿真环境,以便在计算机上模拟机器人的运动和任务。

4.建立恰当的模型:在离线编程软件中构建真实的机器人模型,包括其构型、工具和传感器。确保模型的准确性,以避免在实际应用中出现故障。

5.优化路径规划:利用离线编程软件中的路径规划工具,优化机器人的运动轨迹,以提高任务的效率和速度。

6.考虑碰撞检测:在进行离线编程时,确保机器人的运动路径不会导致与其他设备、工件或工作环境发生碰撞。使用碰撞检测功能帮助避免潜在的冲突。

7.安全考量:离线编程时务必牢记安全因素。确保机器人在执行任务时不会对操作员或其他设备造成伤害。使用虚拟环境进行安全分析是一个好方法。

8.实地验证:尽管离线编程可以显著减少机器人在实际生产中的停机时间,但在将程序导入机器人控制器之前,最好在实地进行验证。通过实地测试,确保机器人在实际生产环境中能够按预期执行任务。

9.持续优化:离线编程不是一次性任务,随着生产需求的变化和改进的机会,需要持续优化机器人的程序和任务。

总的来说,离线编程是一个关键的步骤,有助于提升机器人的生产效率和降低停机时间,但在进行离线编程时,需要仔细考虑任务需求、安全因素和实际生产环境,以确保机器人能够安全、高效地执行任务。

以上所转载内容均来自于网络,不为其真实性负责,只为传播网络信息为目的,非商业用途,如有异议请及时联系btr2020@163.com,本人将予以删除。
THE END
分享
二维码
< <上一篇
下一篇>>