【CVRP&VRPTW】Python+Gurobi求解运输问题建模实践二

采用Python+Gurobi实现车辆路径规划问题建模求解【CVRP&VRPTW】

今天以经典CVRP和VRPTW为例,讲解如何采用python+gurobi编程求解。个人认为采用求解器求解数学模型的关键在于拿到一个正确的数学模型!本人在求解CVRP时,通过文献库搜索了很多文章,限于个人能力,无法采用gurobi对其模型进行求解。最后借用了微信博文中提到的数学模型。(文末给出链接)

往期资料

1. CVRP

1.1 适用场景

  • 求解CVRP
  • python+gurobi

1.2 数学模型

后续代码所对应的数学模型源自以下文章:

https://mp.weixin.qq.com/s/DYh-5WkrYxk1gCKo8ZjvAw

1.3 数据结构

采用.xlsx文件储存数据文件,共包含两个sheet,命名为:node,link。
在 ‘node’ sheet中内容如下:
在这里插入图片描述

在 ‘link’ sheet中内容如下:
在这里插入图片描述

1.4 编程实现

(1)读取文件

def readXlsxFile(filename):
    df=pd.read_excel(filename,sheet_name=None)
    "读取节点信息"
    df_node=df['node']
    depot=df_node['id'][0]
    N = [depot]
    C = []
    Q = {}
    for i in range(df_node.shape[0]):
        id=df_node['id'][i]
        demand=df_node['demand'][i]
        N.append(id)
        C.append(id)
        Q[id]=int(demand)
    N = tuplelist(N)
    C = tuplelist(C)
    Q=tupledict(Q)

    "读取网络弧信息"
    Cost={}
    df_link=df['link']
    for i in range(df_link.shape[0]):
        from_node_id=df_link['from_node_id'][i]
        to_node_id=df_link['to_node_id'][i]
        cost=df_link['link_cost'][i]
        Cost[from_node_id,to_node_id]=cost
    Cost=tupledict(Cost)
    return depot,C,N,Q,Cost

(2)模型构建与求解

def solveCVRPModel(depot,C,N,Q,Cost,n_vehicles=20,CAP=100):
    """
    :param depot: 车场索引
    :param C: 需求点集合
    :param N: 所有点集合
    :param Q: 需求集合
    :param Cost: 弧运输成本集合
    :param n_vehicles: 最大车辆数量
    :param CAP: 车辆容量
    :return:
    """
    "构建车队"
    K=tuplelist([f'v'+str(k) for k in range(n_vehicles)])
    "实例化模型"
    model=Model('cvrp')
    "添加变量"
    X=model.addVars( N,N,K,vtype=GRB.BINARY,name='X[i,j,k]')
    Y=model.addVars( K,N,vtype=GRB.BINARY,name='Y[k,i]')
    U=model.addVars( K,N,vtype=GRB.CONTINUOUS,name='U[k,i]')
    "目标函数:最小化路径成本"
    z1=quicksum( Cost[i,j]*X[i,j,k] for i in N for j in N for k in K if i!=j)
    model.setObjective(z1,GRB.MINIMIZE)
    "约束:需求覆盖约束"
    model.addConstrs( quicksum( Y[k,i] for k in K ) ==1 for i in C )
    "约束:车辆数量约束"
    model.addConstr( quicksum( Y[k,depot] for k in K) == n_vehicles )
    "约束:流平衡"
    model.addConstrs( quicksum( X[i,j,k] for j in N ) == quicksum( X[j,i,k] for j in N ) for i in N for k in K )
    "约束:决策变量关联"
    model.addConstrs( quicksum( X[i,j,k] for j in N ) == Y[k,i] for i in N for k in K )
    "约束:容量限制"
    model.addConstrs( quicksum( Q[i]*Y[k,i] for i in C ) <= CAP for k in K )
    "约束:破除子环"
    model.addConstrs( U[k,i]-U[k,j]+CAP*X[i,j,k] <= CAP-Q[i] for i in C for j in C for k in K )
    model.addConstrs( Q[i] <= U[k,i] for k in K for i in C )
    model.addConstrs( U[k,i] <= CAP for k in K for i in C)
    "求解"
    model.Params.TimeLimit = 300 # 设置求解时间上限
    model.optimize()
    if model.status == GRB.Status.OPTIMAL or model.status == GRB.Status.TIME_LIMIT:
        for k in K:
            for i in N:
                for j in N:
                    if i!=j :
                        if X[i,j,k].x>0:
                            print("X[{},{},{}]=1".format(i,j,k))
        print("obj:{}".format(model.objVal))
    else:
        print("no solution")

2. VRPTW

2.1 适用场景

  • 求解VRPTW
  • python+gurobi

2.2 数学模型

后续代码所对应的数学模型源自以下文章:

https://mp.weixin.qq.com/s/tF-ayzjpZfuZvelvItuecw

2.3 数据结构

采用.csv文件格式储存数据文件,分别为:node.csv 和link.csv
在 ‘node.csv’ 中内容如下:
在这里插入图片描述
在 ‘link.csv’ 中内容如下:
在这里插入图片描述

2.4 编程实现

(1)读取文件

def readCsvFile(node_file,link_file):
    """
    :param node_file: 节点文件,
    :param link_file: 网络弧文件
    :return:
    """
    N=[] #所有节点
    Q={} #节点需求
    TT={} #节点旅行时间
    ET={} #节点最早开始服务时间
    LT={} #节点最晚结束服务时间
    ST={} #节点服务时间
    Cost={}
    with open(node_file,'r') as f:
        node_reader=csv.DictReader(f)
        for row in node_reader:
            node_id = row['id']
            demand = float(row['demand'])
            start_time = float(row['start_time'])
            end_time = float(row['end_time'])
            service_time = float(row['service_time'])
            N.append(node_id)
            Q[node_id] = demand
            ET[node_id] = start_time
            LT[node_id] = end_time
            ST[node_id] = service_time
    with open(link_file,'r') as f:
        link_reader = csv.DictReader(f)
        for row in link_reader:
            from_node_id = row['from_node_id']
            to_node_id = row['to_node_id']
            travel_time = float(row['travel_time'])
            travel_cost = float(row['link_cost'])
            TT[from_node_id,to_node_id] = travel_time
            Cost[from_node_id,to_node_id] = travel_cost
    return N,Q,TT,ET,LT,ST,Cost

(2)模型构建与求解

def solveVRPTWModel(N,Q,TT,ET,LT,ST,Cost,CAP,K):
    """
    :param N: 所有节点集合,其中N[0]为车场
    :param Q: 节点需求集合
    :param TT: 旅行时间
    :param ET: 节点最早开始服务时间
    :param LT:节点最晚结束服务时间
    :param ST: 节点服务时间
    :param CAP: 车辆容量
    :param Cost: 旅行费用
    :param K: 车队数量
    :return:
    """
    C=tuplelist(N[1:]) #需求节点
    N=tuplelist(N)
    Q=tupledict(Q)
    TT=tupledict(TT)
    E=tupledict(ET)
    L=tupledict(LT)
    S=tupledict(ST)
    K=tuplelist([f'v'+str(i) for i in range(K)])
    M=10**5
    depot = N[0]
    "创建模型"
    model=Model()
    "添加变量"
    X=model.addVars(N,N,K,vtype=GRB.BINARY,name='X(i,j,k)')
    T=model.addVars( N,K,vtype=GRB.CONTINUOUS,lb=0,name='T[i,k]')
    "设置目标函数"
    z1=quicksum( Cost[i,j]*X[i,j,k] for i in N for j in N for k in K if i!=j)
    model.setObjective(z1,GRB.MINIMIZE)
    "车辆起点约束"
    model.addConstrs(quicksum(X[depot, j, k] for j in N) == 1 for k in K)
    "车辆路径连续约束"
    model.addConstrs( quicksum(X[i,j,k] for j in N if j!=i)==quicksum(X[j,i,k] for j in N if j!=i) for i in C for k in K)
    "车辆终点约束"
    model.addConstrs(quicksum(X[j, depot, k] for j in N) == 1 for k in K)
    "需求服务约束"
    model.addConstrs( quicksum(X[i,j,k] for k in K for j in N if j!=i)==1 for i in C)
    "车辆容量约束"
    model.addConstrs( quicksum(Q[i]*X[i,j,k] for i in C for j in N if i!=j)<=CAP for k in K )
    "时间窗约束"
    model.addConstrs( T[i,k]+S[i]+TT[i,j]-(1-X[i,j,k])*M<=T[j,k] for i in C for j in C for k in K if i!=j )
    model.addConstrs( T[i,k] >= E[i] for i in N for k in K)
    model.addConstrs( T[i,k] <= L[i] for i in N for k in K)
    "设置模型参数"
    model.Params.TimeLimit = 300 # 规模较大时可设置求解时间限制
    # model.setParam('OutputFlag', 0) #是否输出求解日志
    "模型求解"
    model.optimize()
    "判断求解状态"
    if model.status == GRB.Status.OPTIMAL or model.status == GRB.Status.TIME_LIMIT:
        print('obj={}'.format(model.objVal))
        res=[]
        for k in K:
            for i in N:
                for j in N:
                    if i!=j:
                        if X[i,j,k].x>0:
                            print("X[{},{},{}]=1".format(i,j,k))
                            res.append([i,j,k,T[i,k].x,T[j,k].x])
        saveFile(res)
    else:
        print("no solution")

(3)保存结果

def saveFile(data):
    outfile = open('results.csv', 'w', newline='', errors='ignore')
    write = csv.writer(outfile)
    write.writerow(['from_node_id', 'to_node_id', 'vehicle','Ti','Tj'])
    for v in data:
        write.writerow(v)
    outfile.close()

3. 完整代码

如有错误,欢迎交流。
代码和数据文件可从github主页免费获取:

https://github.com/PariseC/modeling_examples_using_gurobi_in_python

可关注微信公众号,及时获取新内容(推送内容正在准备中):

Python助力交通

参考

  1. https://mp.weixin.qq.com/s/DYh-5WkrYxk1gCKo8ZjvAw
  2. https://mp.weixin.qq.com/s/tF-ayzjpZfuZvelvItuecw
  3. http://www.gurobi.cn/pic.asp?bigclassname=%D1%A7%CF%B0%D7%CA%C1%CF
### 回答1: 当MySQL 8.0宕机导致数据文件损坏时,可以通过以下步骤进行数据文件恢复: 1. 停止MySQL服务:首先,停止MySQL数据库服务,以确保在恢复过程中没有新的写入操作。 2. 备份数据文件:在通过文件恢复之前,应该先备份损坏的数据文件,以防止进一步的数据丢失。 3. 检查错误日志:查看MySQL错误日志,它会记录关于宕机和数据文件损坏的信息。根据错误日志中的提示,了解具体的数据文件损坏情况。 4. 使用数据文件恢复工具:MySQL提供了一些内置工具来恢复损坏的数据文件,如"mysqlcheck"和"myisamchk"。根据错误日志的提示,选择合适的工具对损坏文件进行修复。 5. 修复数据文件:根据提示使用相应的工具对损坏的数据文件进行修复。这些工具会尝试自动修复损坏的数据文件,并恢复它们的完整性。在修复之前,建议先进行数据文件备份。 6. 启动MySQL服务:完成数据文件修复后,重新启动MySQL数据库服务。 7. 数据一致性检查:在启动MySQL服务之后,建议对数据库中的数据进行一致性检查,确保数据的完整性和正确性。 8. 数据恢复验证:通过执行一些测试语句或查询来验证数据文件恢复的结果,确保数据库的功能正常并且数据已经正确恢复。 在进行MySQL 8.0宕机数据文件恢复时,要小心操作,确保对数据进行适当的备份,并参考MySQL官方文档和手册以获得更详细的指导和建议。同时,为了避免宕机和数据文件损坏的情况发生,建议定期备份数据库、使用可靠的硬件设备和监控系统性能。 ### 回答2: MySQL 8.0 宕机后,进行数据文件恢复的步骤如下: 首先,需要确定数据文件的完整性。可以使用MySQL内置的工具如MySQLcheck或者InnoDB crash recovery检查数据文件是否完整。如果数据文件有损坏,需要修复损坏的文件。 其次,为了减少数据丢失的可能性,在宕机恢复之前,需要进行数据备份。可以使用MySQL的备份工具如mysqldump或者MySQL Enterprise Backup。 接下来,根据宕机原因来决定具体的恢复方法。如果是由于崩溃引起的宕机,可以使用InnoDB crash recovery工具进行自动恢复。如果宕机是由于硬件故障或者其他原因引起的,则需要使用冷备份或者热备份进行恢复。 在进行恢复过程中,可以使用MySQL内置的日志文件来回滚未完成的事务,并恢复到宕机前的状态。如果没有进行事务日志的备份,可以参考binlog来进行数据恢复。 最后,当数据库恢复完成后,需要进行一些额外的步骤,如更新MySQL的配置文件,重启MySQL服务等。 总结起来,MySQL 8.0 宕机数据文件的恢复过程包括确定数据文件完整性、数据备份、根据宕机原因选择恢复方法、使用日志文件回滚事务、进行数据恢复、完成后的一些额外操作。有时候可能需要专业人士的帮助来处理复杂的情况。 ### 回答3: 当MySQL 8.0宕机时,进行数据文件恢复主要包括几个步骤。 首先,需要通过查看数据库的错误日志文件来确定宕机的原因。错误日志通常位于MySQL的数据目录下,其命名通常为hostname.err。通过查看错误日志可以了解到宕机原因,并进一步确定后续操作。 接下来,需要进行MySQL实例的恢复。可以通过运行MySQL提供的备份工具mysqldump进行备份数据,或者使用复制功能(如主从复制)来实现数据的冗余。恢复时,可以运行启动命令"mysqld --skip-slave-start"来跳过启动slave线程。 在MySQL宕机后,将其重启到恢复模式下(也称为恢复状态)。 1. 首先,运行启动命令"mysqld --skip-grant-tables",此时MySQL不会验证用户登录信息,可以直接以超级用户(root)身份登录。 2. 接着,登录到MySQL服务器,运行以下命令:ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';来修改root用户的密码。 3. 运行FLUSH PRIVILEGES;来刷新权限。 4. 最后,再次重新启动MySQL服务器。 接下来,可以通过使用mysqldump等工具将备份的数据重新导入到MySQL中,或者使用复制功能来重建冗余数据。当恢复完成后,可以正常启动MySQL服务器,用户可以继续使用数据库服务。 需要注意的是,在MySQL宕机后,及时与数据库管理员或专业人员联系,以便获得更准确和专业的恢复指导和支持。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Better.C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值