动态规划法在汽车租赁问题中的实战(使用策略迭代法得到最优策略和最优价值 python实现 附源码)

简介: 动态规划法在汽车租赁问题中的实战(使用策略迭代法得到最优策略和最优价值 python实现 附源码)

需要源码请点赞关注收藏评论区留言或私信博主~~~

策略迭代的关键部分是策略评估,首先评估状态的价值,然后根据状态的动作值进行相应的策略改进,并进行下一轮评估和改进。直到策略稳定,策略改进可以通过求解静态最优化问题来实现,通过状态动作值来选择动作,通常比策略评估容易。

基于状态值的策略迭代算法包括以下三个阶段

1:初始化策略函数和状态值函数

2:策略评估:在当前策略下 使用贝尔曼方程更新状态值函数 直到收敛

3:策略改进:基于贪心策略得到更优策略,直到策略收敛不再变化

 

算法步骤如下

汽车租赁问题描述:杰克经营两家异地的汽车租赁场,每天都有客户来租车,如果每个租赁场有可供外租的汽车,每租出一辆汽车,杰克获得10美元,为了保证每个租赁场有足够的汽车可租,每天晚上杰克会在两个租赁场之间移动车辆,每辆车的移车费用为2美元,假设每个租赁场的租车和还车的数量是一个泊松随机量。给定三个假设

1:任何一个租赁场车辆总数不超过20辆

2:当天还回的车辆第二天才能出租

3:两个租车场之间每天最多可移车数量为5辆

下面利用策略迭代方法 计算两个租赁场点之间的最优移车策略

经过五轮的策略评估和改进后 得到最优策略和最优价值

 

最优策略如下

最优价值如下

部分代码如下

# 代10-例4.6-汽车租赁问题
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from scipy.stats import poisson
# %matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
plt.rcParams['axes.unicode_minus']=False
matplotlib.use('TkAgg')
# 每个租赁场的最大车辆数
MAX_CARS = 20
# 每晚挪车的最大数
MAX_MOVE_OF_CARS = 5
#第一个租赁场租车的𝜆值
RENTAL_REQUEST_FIRST_LOC = 4
#第而个租赁场租车的𝜆值
RENTAL_REQUEST_SECOND_LOC = 3
#第一个租赁场还车的𝜆值
RETURNS_FIRST_LOC = 2
#第而个租赁场还车的𝜆值
RETURNS_SECOND_LOC = 3
DISCOUNT = 0.9
# 租出一辆车奖励值
RENTAL_CREDIT = 10
# 挪车费用
MOVE_CAR_COST = 2
# 所有可能的动作
actions = np.arange(-MAX_MOVE_OF_CARS, MAX_MOVE_OF_CARS + 1)
# An up bound for poisson distribution
# If n is greater than this value, then the probability of getting n is truncated to 0
POISSON_UPPER_BOUND = 11
# Probability for poisson distribution
# @lam: lambda should be less than 10 for this function
poisson_cache = dict()
def poisson_probability(n, lam):
    global poisson_cache
    key = n * 10 + lam
    if key not in poisson_cache:
        poisson_cache[key] = poisson.pmf(n, lam)
    return poisson_cache[key]
def expected_return(state, action, state_value, constant_returned_cars):
    """
    @state: [# of cars in first location, # of cars in second location]
    @action: positive if moving cars from first location to second location,
            negative if moving cars from second location to first location
    @stateValue: state value matrix
    @constant_returned_cars:  if set True, model is simplified such that
    the # of cars returned in daytime becomes constant
    rather than a random value from poisson distribution, which will reduce calculation time
    and leave the optimal policy/value state matrix almost the same
    """
    # initailize total return
    returns = 0.0
    # cost for moving cars
    returns -= MOVE_CAR_COST * abs(action)
    # moving cars
    NUM_OF_CARS_FIRST_LOC = min(state[0] - action, MAX_CARS)
    NUM_OF_CARS_SECOND_LOC = min(state[1] + action, MAX_CARS)
    # go through all possible rental requests
    for rental_request_first_loc in range(POISSON_UPPER_BOUND):
        for rental_request_second_loc in range(POISSON_UPPER_BOUND):
            # probability for current combination of rental requests
            prob = poisson_probability(rental_request_first_loc, RENTAL_REQUEST_FIRST_LOC) * \
                poisson_probability(rental_request_second_loc, RENTAL_REQUEST_SECOND_LOC)
            num_of_cars_first_loc = NUM_OF_CARS_FIRST_LOC
            num_of_cars_second_loc = NUM_OF_CARS_SECOND_LOC
            # valid rental requests should be less than actual # of cars
            valid_rental_first_loc = min(num_of_cars_first_loc, rental_request_first_loc)
            valid_rental_second_loc = min(num_of_cars_second_loc, rental_request_second_loc)
            # get credits for renting
            reward = (valid_rental_first_loc + valid_rental_second_loc) * RENTAL_CREDIT
            num_of_cars_first_loc -= valid_rental_first_loc
            num_of_cars_second_loc -= valid_rental_second_loc
            if constant_returned_cars:
                # get returned cars, those cars can be used for renting tomorrow
                returned_cars_first_loc = RETURNS_FIRST_LOC
                returned_cars_second_loc = RETURNS_SECOND_LOC
                num_of_cars_first_loc = min(num_of_cars_first_loc + returned_cars_first_loc, MAX_CARS)
                num_of_cars_second_loc = min(num_of_cars_second_loc + returned_cars_second_loc, MAX_CARS)
                returns += prob * (reward + DISCOUNT * state_value[num_of_cars_first_loc, num_of_cars_second_loc])
            else:
                for returned_cars_first_loc in range(POISSON_UPPER_BOUND):
                    for returned_cars_second_loc in range(POISSON_UPPER_BOUND):
                        prob_return = poisson_probability(
                            returned_cars_first_loc, RETURNS_FIRST_LOC) * poisson_probability(returned_cars_second_loc, RETURNS_SECOND_LOC)
                        num_of_cars_first_loc_ = min(num_of_cars_first_loc + returned_cars_first_loc, MAX_CARS)
                        num_of_cars_second_loc_ = min(num_of_cars_second_loc + returned_cars_second_loc, MAX_CARS)
                        prob_ = prob_return * prob
                        returns += prob_ * (reward + DISCOUNT *
                                            state_value[num_of_cars_first_loc_, num_of_cars_second_loc_])
    return returns
def figure_4_2(constant_returned_cars=True):
    value = np.zeros((MAX_CARS + 1, MAX_CARS + 1))
    policy = np.zeros(value.shape, dtype=np.int)
    iterations = 0
    _, axes = plt.subplots(2, 3, figsize=(40, 20))
    plt.subplots_adjust(wspace=0.1, hspace=0.2)
    axes = axes.flatten()
    while True:
        fig = sns.heatmap(np.flipud(policy), cmap="YlGnBu", vmax=5, vmin=-5,ax=axes[iterations],center=0)
        fig.set_ylabel('# B ',fontsize=30)
        fig.set_yticks(list(reversed(range(MAX_CARS + 1))))
        fig.set_xlabel('# A', fontsize=30)
        fig.set_title('policy {}'.format(iterations), fontsize=30)
        # policy evaluation (in-place)
        while True:
            old_value = value.copy()
    or (-j <= action <= 0):
                    # if(-i <= action <= 0) or (0 <= action <= j):
                        action_returns.append(expected_return([i, j], action, value, constant_returned_cars))
                    else:
                        action_returns.append(-np.inf)
                new_action = actions[np.argmax(action_returns)]
                policy[i, j] = new_action
                if policy_stable and old_action != new_action:
                    policy_stable = False
        print('policy stable {}'.format(policy_stable))
        if policy_stable:
            fig = sns.heatmap(np.flipud(value), cmap="YlGnBu", ax=axes[-1])
            fig.set_ylabel('# 第一地点的车辆数', fontsize=30)
            fig.set_yticks(list(reversed(range(MAX_CARS + 1))))
            fig.set_xlabel('# 第二地点的车辆数', fontsize=30)
            fig.set_title('optimal value', fontsize=30)
            break
        iterations += 1
    #保存路径
    #plt.savefig('images/figure_4_2.png')
    plt.show()
    #plt.close()
if __name__ == '__main__':
    figure_4_2()
相关文章
|
1月前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。
|
1月前
|
小程序 开发者 Python
探索Python编程:从基础到实战
本文将引导你走进Python编程的世界,从基础语法开始,逐步深入到实战项目。我们将一起探讨如何在编程中发挥创意,解决问题,并分享一些实用的技巧和心得。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供有价值的参考。让我们一起开启Python编程的探索之旅吧!
51 10
|
2月前
|
JSON 开发工具 git
基于Python和pygame的植物大战僵尸游戏设计源码
本项目是基于Python和pygame开发的植物大战僵尸游戏,包含125个文件,如PNG图像、Python源码等,提供丰富的游戏开发学习素材。游戏设计源码可从提供的链接下载。关键词:Python游戏开发、pygame、植物大战僵尸、源码分享。
|
2月前
|
算法 Unix 数据库
Python编程入门:从基础到实战
本篇文章将带你进入Python编程的奇妙世界。我们将从最基础的概念开始,逐步深入,最后通过一个实际的项目案例,让你真正体验到Python编程的乐趣和实用性。无论你是编程新手,还是有一定基础的开发者,这篇文章都将为你提供有价值的信息和知识。让我们一起探索Python的世界吧!
|
2月前
|
数据处理 Python
探索Python中的异步编程:从基础到实战
在Python的世界中,“速度”不仅是赛车手的追求。本文将带你领略Python异步编程的魅力,从原理到实践,我们不单单是看代码,更通过实例感受它的威力。你将学会如何用更少的服务器资源做更多的事,就像是在厨房里同时烹饪多道菜而不让任何一道烧焦。准备好了吗?让我们开始这场技术烹饪之旅。
|
算法 Python 设计模式
python设计模式(二十二):策略模式
策略模式,让一个类的行为或其算法可以在运行时更改,策略是让实例化对象动态的更改自身的某些方法使用的是types.MethodType绑定。 说起策略的动态更改方法,就不得不对比一下元类的动态增加方法,元类是类的抽象,它负责一个抽象类创建、实例化,是通过type函数来绑定方法。
1384 0
|
1月前
|
人工智能 数据可视化 数据挖掘
探索Python编程:从基础到高级
在这篇文章中,我们将一起深入探索Python编程的世界。无论你是初学者还是有经验的程序员,都可以从中获得新的知识和技能。我们将从Python的基础语法开始,然后逐步过渡到更复杂的主题,如面向对象编程、异常处理和模块使用。最后,我们将通过一些实际的代码示例,来展示如何应用这些知识解决实际问题。让我们一起开启Python编程的旅程吧!
|
26天前
|
Unix Linux 程序员
[oeasy]python053_学编程为什么从hello_world_开始
视频介绍了“Hello World”程序的由来及其在编程中的重要性。从贝尔实验室诞生的Unix系统和C语言说起,讲述了“Hello World”作为经典示例的起源和流传过程。文章还探讨了C语言对其他编程语言的影响,以及它在系统编程中的地位。最后总结了“Hello World”、print、小括号和双引号等编程概念的来源。
107 80
|
2月前
|
存储 索引 Python
Python编程数据结构的深入理解
深入理解 Python 中的数据结构是提高编程能力的重要途径。通过合理选择和使用数据结构,可以提高程序的效率和质量
158 59
|
15天前
|
Python
[oeasy]python055_python编程_容易出现的问题_函数名的重新赋值_print_int
本文介绍了Python编程中容易出现的问题,特别是函数名、类名和模块名的重新赋值。通过具体示例展示了将内建函数(如`print`、`int`、`max`)或模块名(如`os`)重新赋值为其他类型后,会导致原有功能失效。例如,将`print`赋值为整数后,无法再用其输出内容;将`int`赋值为整数后,无法再进行类型转换。重新赋值后,这些名称失去了原有的功能,可能导致程序错误。总结指出,已有的函数名、类名和模块名不适合覆盖赋新值,否则会失去原有功能。如果需要使用类似的变量名,建议采用其他命名方式以避免冲突。
34 14