2.2 DP: Value Iteration & Gambler‘s Problem

本文介绍了动态规划中的价值迭代算法,并通过赌博者问题进行案例分析。在赌博者问题中,赌徒试图用有限的钱通过掷硬币赢得目标金额。通过价值迭代,我们找到了最优策略,即在每一步选择最大期望收益的投注。文章还提供了Python代码实现,展示价值函数和策略的可视化结果。

目录

Value Iteration

Background

Definition

Pesudo code 

Gambler's Problem

Case

Case analysis

Code

Result


Value Iteration

Background

Policy iteration's process is that after value function (policy evaluation) converges, the policy then improved. In fact, there is no need that value function converges because even no the last many sweeps of policy evaluation, the policy can converge to the same result. Therefore, actually we do not need to make policy evaluation converged. 

Definition

We can go on several sweeps of policy evaluation, then turn into policy improvement and turn back to the policy evaluation until the policy converges to the optimal policy.

In extreme situations, we can make policy improvement just after one update of one state. 

Pesudo code 

while judge == True:

        judge = False;

        for s\in S:

                v_{old}\ =\ v(s)

                v(s)\ =\ max_a \sum_{s^{'},r^{'}} \ p(s^{'},r^{'}|s,a)[r+\gamma v(s^{'})]

                if |\ v(s) - v_{old} \ | > \theta:

                        judge = True;

# optimal policy 

\pi(s)\ =\ argmax_a \ sum_{s^{'},a^{'}} \ p(s^{'},a^{'}|s,a)[r+\gamma v(s^{'})]

Gambler's Problem

Case

Case analysis

S: the money we have : 0-100, v(0)=0,v(100)=1 (constant)

A: the money we stake: 0-min( s,100-s ) 

R:  no imtermediate reward, expect v(100)=1

S^{'}:  S+A or S-A, which depends on the probability: p_h (win)

Code

### settings


import math
import numpy
import random

# visualization 
import matplotlib 
import matplotlib.pyplot as plt

# global settings

MAX_MONEY = 100 ;

MIN_MONEY = 0 ; 

P_H = 0.4 ; 

gamma = 1 ;  # episodic

# accuracy of value function
error = 0.001; 

### functions

# max value function
def max_v_a(v,s):
	MIN_ACTION = 0 ;
	MAX_ACTION = min( s, MAX_MONEY-s ) ;
	
	v_a = numpy.zeros(MAX_ACTION+1 - MIN_ACTION ,dtype = numpy.float);
	
	for a in range(MIN_ACTION, MAX_ACTION+1):
		v_a [a-MIN_ACTION] = ( P_H*( 0 + gamma*v[s+a] ) + \
		(1- P_H)*( 0 + gamma*v[s-a] ) );
	
	return max(v_a)

# max value function index
def argmax_a(v,s):
	MIN_ACTION = 0 ;
	MAX_ACTION = min( s, MAX_MONEY-s ) ;
	
	v_a = numpy.zeros(MAX_ACTION+1 - MIN_ACTION ,dtype = numpy.float);
	
	for a in range(MIN_ACTION, MAX_ACTION+1):
		v_a [a-MIN_ACTION] = ( P_H*( 0 + gamma*v[s+a] ) + \
		(1- P_H)*( 0 + gamma*v[s-a] ) );
	
	return ( numpy.argmax(v_a) )

# visualization 

def visualization(v_set,policy):
	
	fig,axes = plt.subplots(2,1)
	for i in range(0,len(v_set)):
		axes[0].plot(v_set[i],linewidth=3)
	#	plt.pause(0.5)
	axes[0].set_title('value function')
	
	
	axes[1].plot(range(1,len(policy)+1),policy)
	axes[1].set_title('policy')
	plt.show()

### main programming

# policy 
policy = numpy.zeros(MAX_MONEY-1);

# value function
v = numpy.zeros(MAX_MONEY+1,dtype = numpy.float);

#every_sweep_of value function
v_set = [] ;

# initialization
v[MAX_MONEY] = 1 ;
v[MIN_MONEY] = 0 ;

judge = True;


# value iteration

while(judge):
	judge = False
	for s in range(MIN_MONEY+1,MAX_MONEY):
		v_old = v[s];
		v[s] = max_v_a(v,s);
		if math.fabs( v[s] - v_old ) > error:
			judge = True;
	v_set.append(v.copy())
	
# optimal policy 

for s in range(MIN_MONEY+1,MAX_MONEY):
	policy[s-1] = argmax_a(v,s)


# visualization

visualization(v_set,policy)

Result

for p_h =0.4 

### std::thread 的具体用法及语法解析 #### 1. `std::thread` 的基本用法 `std::thread` 是 C++ 标准库中用于创建和管理线程的类。它通过构造函数启动一个新线程,执行用户定义的函数。以下是 `std::thread` 的常见用法[^1]: - 使用普通函数作为目标函数。 - 使用成员函数作为目标函数。 - 使用 lambda 表达式或函数对象。 #### 2. 代码解析:`cmd_thread_ = std::thread(&DevicesMgr::CmdJob, this);` 这行代码的核心是通过 `std::thread` 构造函数启动一个新线程,并将成员函数 `DevicesMgr::CmdJob` 作为目标函数绑定到当前对象实例 `this` 上。 ##### 2.1 成员函数作为目标函数 当使用成员函数作为目标函数时,需要提供两个参数: - 指向成员函数的指针。 - 指向调用该成员函数的对象实例。 在代码中: ```cpp cmd_thread_ = std::thread(&DevicesMgr::CmdJob, this); ``` - `&DevicesMgr::CmdJob` 是指向 `DevicesMgr` 类中成员函数 `CmdJob` 的指针。 - `this` 是当前对象的指针,表示 `CmdJob` 方法将在当前对象实例上被调用。 ##### 2.2 绑定机制 `std::thread` 的构造函数会将提供的参数绑定到目标函数上。对于成员函数,`std::thread` 内部会通过 `std::bind` 或类似机制将对象实例和成员函数绑定在一起[^1]。 #### 3. 参数传递 `std::thread` 支持多种参数传递方式,包括值传递、引用传递和指针传递。以下是一些示例: ##### 3.1 值传递 如果将参数按值传递给目标函数,则 `std::thread` 会在内部复制该参数。 ```cpp void printValue(int value) { std::cout << "Value: " << value << std::endl; } int main() { int x = 42; std::thread t(printValue, x); // 按值传递 x t.join(); return 0; } ``` ##### 3.2 引用传递 如果需要传递变量的引用,可以使用 `std::ref` 或 `std::cref`。 ```cpp void modifyValue(int& value) { value *= 2; } int main() { int x = 42; std::thread t(modifyValue, std::ref(x)); // 按引用传递 x t.join(); std::cout << "Modified value: " << x << std::endl; return 0; } ``` ##### 3.3 指针传递 直接传递指针也是常见的做法。 ```cpp void processPointer(int* ptr) { if (ptr) { *ptr += 10; } } int main() { int x = 42; std::thread t(processPointer, &x); // 按指针传递 x t.join(); std::cout << "Processed value: " << x << std::endl; return 0; } ``` #### 4. 示例代码:结合成员函数与多线程 以下是一个完整的示例,展示如何使用 `std::thread` 调用成员函数: ```cpp #include <iostream> #include <thread> class DevicesMgr { public: void CmdJob() { for (int i = 0; i < 5; ++i) { std::cout << "CmdJob running on thread: " << std::this_thread::get_id() << ", iteration: " << i << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } } }; int main() { DevicesMgr mgr; std::thread cmd_thread(&DevicesMgr::CmdJob, &mgr); if (cmd_thread.joinable()) { cmd_thread.join(); } return 0; } ``` #### 5. 注意事项 - **线程生命周期管理**:必须确保线程在程序结束前正确地调用 `join()` 或 `detach()`[^1]。 - **资源竞争**:多线程环境下,共享资源可能引发数据竞争,应使用互斥锁(如 `std::mutex`)保护共享数据[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值