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

2024-01-18 03:28

本文主要是介绍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. ↩︎ ↩︎

这篇关于VRPSolverEasy:支持VRP问题快速建模的精确算法Python包的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/617974

相关文章

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Python中图片与PDF识别文本(OCR)的全面指南

《Python中图片与PDF识别文本(OCR)的全面指南》在数据爆炸时代,80%的企业数据以非结构化形式存在,其中PDF和图像是最主要的载体,本文将深入探索Python中OCR技术如何将这些数字纸张转... 目录一、OCR技术核心原理二、python图像识别四大工具库1. Pytesseract - 经典O

基于Linux的ffmpeg python的关键帧抽取

《基于Linux的ffmpegpython的关键帧抽取》本文主要介绍了基于Linux的ffmpegpython的关键帧抽取,实现以按帧或时间间隔抽取关键帧,文中通过示例代码介绍的非常详细,对大家的学... 目录1.FFmpeg的环境配置1) 创建一个虚拟环境envjavascript2) ffmpeg-py

python使用库爬取m3u8文件的示例

《python使用库爬取m3u8文件的示例》本文主要介绍了python使用库爬取m3u8文件的示例,可以使用requests、m3u8、ffmpeg等库,实现获取、解析、下载视频片段并合并等步骤,具有... 目录一、准备工作二、获取m3u8文件内容三、解析m3u8文件四、下载视频片段五、合并视频片段六、错误

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热