VRPSolverEasy:支持VRP问题快速建模的精确算法Python包

文章目录

  • 前言
  • 一步步安装免费版
  • 主要模块介绍
    • 1. depot point
    • 2. customer point
    • 3. links
    • 4. vehicle type
  • VRPTW 算例
    • 数据说明
    • 模型建立
    • 输出求解状态及结果


前言

VRPSolverEasy 是用于车辆路径问题(VRP)的最先进的分支切割和定价算法求解器1,它的一大特点是,即使没有运筹学背景的用户,也可以直观地通过Python接口定义出VRP问题,无需知道模型是如何建立为 MIP 问题以及底层进行的线性处理,只需要通过配置好的方法,向模型中添加高度抽象的VehicleTypePoint(衍生出depotcustomer)、links 即可。

VRPSolver将VRP问题进行了高度抽象,尽管较大程度方便使用,但代价是限制了VRPSolver只能建模常见的标准的VRP变体问题,例如:

  1. 车辆带容量限制;
  2. 客户点带时间窗;
  3. 车辆不同质;
  4. 多depot发车;
  5. 客户点指定车辆资质;
  6. 时间依赖…

VRPSolver的内核是分支切割定价算法,其高效性在于对可行解最优界(下界)的优化上,而在初始可行解的寻找方面效率较低,因此由外部启发式求解器获得非常好的初始解(上界)时,VRPSolver的求解性能可以得到改善。

目前的VRPSolver仍然是proof-of-concept的代码,容易出现问题,因此建议仅用于研究、教学、测试等非生产环境。

一步步安装免费版

VRPSolverEasy有两种安装模式,一种是免费版本,直接安装VRPSolverEasy库(内嵌了COIN-OR CLP线性规划求解器),以及下载Bapcod发行版即可。另一种是学术版本,该版本使用了商业CPLEX MIP求解器,由于CPLEX可以免费用于学术目的,因此这个版本下的VRPSolverEasy也被称为学术版,该版本提高了求解性能,并提供了内置的基于MIP的启发式算法,对寻找可行的初始解非常有用。

这里我们仅介绍安装免费版的 VRPSolverEasy,操作系统默认为Windows。(学术版的安装请参考 官方文档)

(1)确认python版本及更新pip

VRPSolverEasy库要求python版本不小于 3.6,因此在开始安装前,先确认好python的版本,并建议更新 pip 库:

python -m pip install --upgrade pip

(2)安装VRPSolverEasy库

VRPSolverEasy库的安装可以直接用pip安装:

python -m pip install VRPSolverEasy

(3)安装Bapcod依赖的环境

由于内嵌的 CLP 仅是线性规划求解器,要用 B&C&P 求解MIP问题,还需安装Bapcod,由于Bapcod的底层是C++,因此要用Python接口使用,就还需下载能对该库进行编译和管理的工具CMake,该工具的官网下载地址为:Download CMake,具体的安装细节可以参考:Windows 安装CMake。在cmd控制台输入 cmake --version 即可查看CMake的版本。

接着还需安装 Bapcod 依赖的python库:

  1. Boost库版本1.76 pip install boost
  2. LEMON 库版本 1.3.1 pip install lemon

(4)申请Bapcod并替换相应文件

尽管Bapcod是免费开源的库,但是需要学术机构的电子邮箱才能下载Bapcod的源码,在 BaPCod官方网站 填写相应信息并回车进行申请。系统会自动验证该邮箱,并向该邮箱发送下载链接。

解压下载的文件,例如为 bapcod-v0.82.5,找到该文件夹下的 VRPSolverEasy 文件夹,复制该文件夹下的 Windows 文件夹到 VRPSolverEasy 库下面的 lib 文件夹中替换 Windows 即可。

主要模块介绍

关于主要模块的介绍我们截取翻译自VRPSolverEasy的技术报告1

导入VRPSolverEasy库,并通过以下命令创建模型。

import VRPSolverEasy
model = VRPSolverEasy.Model()

VRPSolverEasy库模型由四组实体对象定义:depot pointscustomer pointslinksvehicle types

1. depot point

depot 可以通过如下命令添加

model.add_depot(id=<id>, name='', service_time=0.0, tw_begin=0.0, tw_end=0.0)

添加 depot 方法的参数说明如下:

Characterization of a depot point v

2. customer point

customer 可以通过如下命令添加:

model.add_customer(id=<id>, id_customer=<id>, name ='', demand=0, penalty=0.0, service_time=0.0, tw_begin=0.0, tw_end=0.0, incompatible_vehicles=[])

添加 customer 方法的参数说明如下:

Characterization of a customer point v
不论是 depot point 还是 customer point,都应该有一个唯一的点 id,且每个 customer 都与一个或多个点相关联,其中 idid_customer 可以不同。

对于一些特殊的问题,例如同一个客户点具有不同的时间窗,且每个时间窗所兼容的车辆可能不同,常见于时间依赖的VRPTW问题,这类问题中,客户点可能会被多辆车访问(同时或者有时间前后约束),这时候为了避免与子环路消除约束相冲突,往往会创建虚拟点,在这里,如果我们要创建 customer point 的额外点,可以通过以下命令添加:

model.add_point(id=<id>, id_customer=<id>, name ='', demand=0, penalty=0.0, service_time=0.0, tw_begin=0.0, tw_end=0.0, incompatible_vehicles=[])

3. links

link 可以通过如下命令添加:

model.add_link(start_point_id=<id>, end_point_id=<id>, name='', is_directed=False, distance=0.0, time=0.0, fixed_cost=0.0)

添加 link 方法的参数说明如下:

Characterization of a link l
每一条 link 代表有向图G当中的一条弧,如果 is_directed=True,则说明该弧具有方向,只能从 start_point_idend_point_id 方向;如果 is_directed=False,则说明该弧是双向的(若不设置该参数默认为双向的)。

4. vehicle type

vehicle type 可以通过如下命令添加:

model.add_vehicle_type(id=<id>, start_point_id=-1, end_point_id=-1, name='', capacity=0, fixed_cost=0.0, var_cost_dist=0.0, var_cost_time=0.0, max_number=1, tw_begin=0.0, tw_end=0.0) 

添加 vehicle type 方法的参数说明如下:

Characterization of a vehicle type k
当车辆的开始点和结束点都为 -1 时,说明该车辆可以在任意节点处出发,和返回任意节点处。

VRPTW 算例

数据说明

如下设置 7 个节点,以第 1 个节点 Wisconsin, USAdepot point,其余节点为 customer point,除了 depot 其余节点都有大于0需求量,车辆的时间窗为 [ 0 , 5000 ] [0, 5000] [0,5000],每辆车单位距离成本为 10,节点与节点之间的距离通过欧式距离公式计算 compute_euclidean_distance

import VRPSolverEasy as vrpse
import mathdef compute_euclidean_distance(x_i, x_j, y_i, y_j):"""compute the euclidean distance between 2 points from graph"""return round(math.sqrt((x_i - x_j)**2 + (y_i - y_j)**2), 3)# Data
cost_per_distance = 10
begin_time = 0
end_time = 5000
nb_point = 7# Map with names and coordinates
coordinates = {"Wisconsin, USA": (44.50, -89.50),  # depot"West Virginia, USA": (39.000000, -80.500000),"Vermont, USA": (44.000000, -72.699997),"Texas, the USA": (31.000000, -100.000000),"South Dakota, the US": (44.500000, -100.000000),"Rhode Island, the US": (41.742325, -71.742332),"Oregon, the US": (44.000000, -120.500000)}# Demands of points
demands = [0, 500, 300, 600, 658, 741, 436]

模型建立

依次建立求解车辆路径网络流问题的要素:车辆、节点、弧。要素的参数值可以自定义配置。

# Initialisation
model = vrpse.Model()# Add vehicle type
model.add_vehicle_type(id=1,start_point_id=0,end_point_id=0,name="VEH1",capacity=1100,max_number=6,var_cost_dist=cost_per_distance,tw_end=5000)# Add depot
model.add_depot(id=0, name="D1", tw_begin=0, tw_end=5000)coordinates_keys = list(coordinates.keys())
# Add customers
for i in range(1, nb_point):model.add_customer(id=i,name=coordinates_keys[i],demand=demands[i],tw_begin=begin_time,tw_end=end_time)# Add links
coordinates_values = list(coordinates.values())
for i in range(0, 7):for j in range(i + 1, 7):dist = compute_euclidean_distance(coordinates_values[i][0],coordinates_values[j][0],coordinates_values[i][1],coordinates_values[j][1])model.add_link(start_point_id=i,end_point_id=j,distance=dist,time=dist)

输出求解状态及结果

当建立模型后,通过以下命令即可实现求解,求解的结果都会保存在 model 的属性当中。

# solve model
model.solve()

打印模型信息可以通过以下命令,默认将模型信息保存在 instance.json 文件中。

model.export()

通过 model.status 可以返回模型的求解状态码:

状态码说明
0找到一个解并证明了最优性
1求解过程被时间限制打断,但找到了优于截断值的解
2求解器证明不存在由于截断值的解
3求解过程被时间限制打断,且没找到由于截断值的解

判断求解状态码是一种输出结果的前置判断,在该库中也可以用 model.solution.is_defined() 进行判断,后者表示找到了可行解,且解的信息会保存到模型的属性当中:

if model.solution.is_defined():# 打印解的目标值及方案的全部信息print(model.solution)# 仅打印路线方案print(model.solution.routes)# 仅打印目标值print(model.solution.value)    # 打印解的求解时间和上下界信息等print(model.statistics)

打印解的目标值及方案的全部信息如下:

Solution cost : 1479.6800000008684Route for vehicle 1:ID : 0 --> 2 --> 5 --> 0Name : D1 --> Vermont, USA --> Rhode Island, the US --> D1End time : 0.0 --> 16.807 --> 19.259 --> 37.230000000000004Load : 0.0 --> 300.0 --> 1041.0 --> 1041.0
Total cost : 372.29999999999995Route for vehicle 1:ID : 0 --> 1 --> 3 --> 0Name : D1 --> West Virginia, USA --> Texas, the USA --> D1End time : 0.0 --> 10.548 --> 31.625 --> 48.728Load : 0.0 --> 500.0 --> 1100.0 --> 1100.0
Total cost : 487.2800000000001Route for vehicle 1:ID : 0 --> 4 --> 6 --> 0Name : D1 --> South Dakota, the US --> Oregon, the US --> D1End time : 0.0 --> 10.5 --> 31.006 --> 62.010000000000005Load : 0.0 --> 658.0 --> 1094.0 --> 1094.0
Total cost : 620.1

  1. N. Errami, E. Queiroga, R. Sadykov, E. Uchoa. “VRPSolverEasy: a Python library for the exact solution of a rich vehicle routing problem”, Technical report HAL-04057985, 2023. ↩︎ ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/412045.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[二]rtmp服务器搭建

[二]rtmp服务器搭建 一.测试二.使用Nginx搭建自己的rtmp服务器1.nginx是什么&#xff1f;2.环境准备 三、搭建过程1.安装编译 nginx 所需要的库2.下载 nginx-1.21.6.tar.gz3.下载 nginx-rtmp-module 4.解压5.编译6.启动nginx&#xff0c;检测nginx是否能成功运行7.配置nginx使用…

易飞ERP抛转钉钉签核,并自动审核易飞单据

支持易飞ERP所有单据送签到钉钉 &#xff08;v: rainholy&#xff09; 1、钉钉界面 2、易飞ERP单据配置 3、钉钉审批完后&#xff0c;自动审核易飞ERP单据

66.Go从零搭建一个orm框架【简版】

文章目录 一&#xff1a;前置学习1、 为什么要用orm2、Golang里面是如何原生连接MySQL的3、ORM框架构想 二: 开始造1、连接Connect2、设置/读取表名Table/GetTable3、新增/替换Insert/Replace4、条件Where5、条件OrWhere6、删除Delete7、修改Update8、查询9、设置查询字段Field…

AVL树 -- C++实现

AVL树 – C实现 1. AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1…

模具制造企业ERP系统有哪些?企业怎么选型适配的软件

模具的生产管理过程比较繁琐&#xff0c;涵盖接单报价、车间排期、班组负荷评估、库存盘点、材料采购、供应商选择、工艺流转、品质检验等诸多环节。 有些采用传统管理手段的模具制造企业存在各业务数据传递不畅、信息滞后、不能及时掌握订单和车间生产情况&#xff0c;难以对…

压力测试+接口测试(工具jmeter)

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因 为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是…

Jenkins持续集成项目搭建与实践

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号&#xff1a;互联网杂货铺&#xff0c;回复1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 Jenkins简介 Jenkins是Java编写的非常流行的持续集成…

C++:类(Class)

内容整理自&#xff1a;The Cherno:C系列&#xff0c;2024年1月18日 --------------------------------------------------------------------------------------------------------------------------------- 简单地说&#xff0c; 类&#xff0c;只是 数据功能 的整合体。…

构建中国人自己的私人GPT—限时免费部署

在现实生活中&#xff0c;很多公司或个人的资料是不愿意公布在互联网上的&#xff0c;但是我们又要使用人工智能的能力帮我们处理文件、做决策、执行命令那怎么办呢&#xff1f;于是我们构建自己或公司的本地专属GPT变得非常重要。 先看效果&#xff1a; 解方程&#xff0c;24小…

Kotlin程序设计(二)面向对象

Kotlin程序设计中级篇 我们在前面已经学习了Kotlin程序设计的基础篇&#xff0c;本章我们将继续介绍更多Kotlin特性&#xff0c;以及面向对象编程。 函数 其实函数我们在一开始就在使用了&#xff1a; fun main() {println("Hello World") }我们程序的入口点就是…

HarmonyOS—构建第一个ArkTS应用(Stage模型)

创建ArkTS工程 构建第一个页面 若首次打开DevEco Studio&#xff0c;请点击Create Project创建工程。如果已经打开了一个工程&#xff0c;请在菜单栏选择File > New > Create Project来创建一个新工程。选择Application应用开发&#xff0c;选择模板“Empty Ability”&am…

python PyQt5的学习

一、安装与配置 1、环境&#xff1a; python3.7 2、相关模块 pip install pyqt5 pyqt5-tools pyqt5designer 可以加个镜像 -i https://pypi.tuna.tsinghua.edu.cn/simple3、配置设计器 python的pyqt5提供了一个设计器&#xff0c;便于ui的设计 界面是这样的&#xff1a…