白冥 发表于 2025-2-10 05:50:20

【Python】【原创】马尔可夫链与动态行为和长期行为分析

本帖最后由 白冥 于 2025-2-11 02:13 编辑

概述      

      在生活中,一个离散系统可能有三种可能的结局,一种是永远在不停地变化,没有止息;一种是逐渐稳定,最终定格在遥远的明天;还有一种摇摆不定,振荡不止,似曾相识的昨日
不期而至。马尔可夫链便是这样的存在。
      本贴重点讨论马尔可夫链状态的可达性、类划分、首达概率、常返与瞬过、周期性等问题,并讨论平稳分布的概念。
      本帖代码经过重构,因此类结构和方法全部列出。代码和板书均由本人写就。

技术系列贴      
      马尔可夫链(1):马尔可夫链与马尔可夫性质

主要功能      
      1)结构分解:使用互通性将转移图分解成多个互不干扰、彼此独立的环境进行局部性质的分析。
      2)动态行为分析:通过研究转移图的常返性和周期性间接测试系统的动态性质。
      3)长期稳态研究:通过局部规律模拟状态的长期分布。


类结构与方法      
      Markov_chain 类
            ├ __init__ 方法
            ├ _build_P 方法
            ├ _get_classes 方法
            ├ is_irreducible 方法
            ├ _is_recurring_class 方法
            ├ get_recurring_classes 方法
            ├ _mul 方法
            ├ _get_period 方法
            ├ get_all_period_of_classes 方法
            └ get_stationary_distribution 方法


源代码      
from math import gcd
from math import inf as INFTY
class Markov_chain:
    def __init__(self, status:List,cpd:Dict,float]):
      self._status=status
      self._P=self._build_P(status, cpd)
    def _build_P(self, cpd):
      n=len(status)
      P=[*n for _ in range(n)]
      for e,p in cpd.items():
            s_0,s_1=e
            P=p
      return P
    def _get_classes(self):
      n = len(self._P)
      reachable = [>0 for j in range(n)] for i in range(n)]
      for k in range(n):
            for i in range(n):
                for j in range(n):
                  reachable = reachable or (reachable and reachable)
      mutual = [ and reachable for j in range(n)] for i in range(n)]
      visited = *n
      classes = []
      for i in range(n):
            if visited: continue
            current_class=
            visited=True
            for j in range(n):
                if mutual:
                  visited=True
                  current_class.append(j)
            classes.append(current_class)
      return classes
    def is_irreducible(self):
      return len(self._get_classes())==1
    def _is_recurring_class(self, class_):
      return not any(any(self._P>0 for s_j in self._status if s_j not in class_)for s_i in class_)
    def get_recurring_classes(self):
      recurring_classes=[]
      irreccurring_status=[]
      for class_ in self._get_classes():
            if self._is_recurring_class(class_):
                recurring_classes.append(class_)
            else:
                for state in class_:
                  irreccurring_status.append(state)
      return recurring_classes, irrecurring_status
    def _mul(self, Q,P):
      n=len(self._P)
      return [*P for k in range(n))for j in range(n)] for i in range(n)]
    def _get_period(self, class_):
      s_0=class_
      n = len(self._P)
      m = len(class_)
      X=[]
      P=[for r in self._P]
      Q=[[(1 if i=j else 0) for j in range(n)]for i in range(n)]
      for k in range(1,m+1):
            Q=self._mul(Q,P)
            if Q>0:
                X.append(k)
      return gcd(*X)
    def get_all_period_of_classes(self):
      recurring, irrecurring = self.get_recurring_classes()
      period={}
      for class_ in recurring:
            period = self._get_period(class_)
      period = None
      return period
    def get_stationary_distribution(self,class_):
      C=[ for j in class_] for i in class_]
      n = len(C)
      b = *(n-1)+
      A=[]
      for i in range(n-1):
            A.append([-C if i != j else 1 - C for j in range(n)])
      A.append(*n)
      for i in range(n):
            max_row = max(range(i, n), key=lambda r: abs(A))
            A, A = A, A
            b, b = b, b
            pivot = A
            for j in range(i, n):
                A /= pivot
            b /= pivot
            for k in range(i+1, n):
                factor = A
                for j in range(i, n):
                  A -= factor * A
                b -= factor * b
      pi = * n
      for i in range(n-1, -1, -1):
            pi = b
            for j in range(i+1, n):
                pi -= A * pi
      return pi

主要方法      
1) _get_classes 方法
      功能:识别所有强连通类。
      步骤:这个方法的目标是将状态分成不同的强连通组件。首先,它初始化了一个reachable矩阵,记录每个状态i到j是否可达。然后通过三重循环进行传递闭包计算,这实际上是Floyd-Warshall算法的变种,用于检测可达性。之后,mutual矩阵用来记录i和j是否相互可达,从而确定强连通组件。然后通过遍历每个未被访问的节点,将同一类的节点收集起来。
      

2) _is_recurring_class方法
      功能:检查给定的类是否是常返的。
      步骤:这里判断的是类中的状态是否不会转移到类外的状态。具体来说,检查类中的任一状态s_i是否有任何转移到不在类中的s_j的概率大于0。如果有,则不是常返类。常返类意味着无法离开这个类。
      

3) _get_period 方法:
      功能:计算给定类的周期。
      步骤:这里选择类中的第一个状态s_0,然后计算从s_0出发返回s_0的所有可能步数的最大公约数。其中,只需要考虑最多m步(m是类的大小),因为超过m步的路径会有重复状态,从而可以分解成更小的环。
      

4) get_stationary_distribution 方法
      功能:用于计算平稳分布。
      步骤:首先将转移矩阵限制在类中的状态,然后构建增广矩阵A和b,用高斯消元法解平稳方程。
      


概念补充      
      

老六不六 发表于 2025-2-10 08:14:06

好专业的知识,看得我头都晕晕的{:6_168:}

娱乐法师火布偶 发表于 2025-2-10 08:59:37

第二种情况是收敛了,第一种是不收敛

归北溟 发表于 2025-2-10 09:06:08

给技术大佬跪下了,完全看不懂ORZ

傲瑞龍兽 发表于 2025-2-10 09:20:39

救命,我毕业了啊喂,在高色色时突然被死去的知识攻击,另外感觉还是需要一些数学基础,所以不如大家一起来学实变复变和泛函;P

RudeRide 发表于 2025-2-10 09:41:04

Markov Decision Process作为Reinforcement Learning的基础,现在真的就是必不可缺了,马氏链相关性质,尤其是最终平稳的性质在解动态规划相关问题有指导意义,而且随着多智能体的热点兴起,这一理论基石的地位又抬了起来。

PURO_ 发表于 2025-2-10 09:47:03

好硬核,泥潭成为学习网站的可能性微存

找乐子企鹅仔 发表于 2025-2-10 10:56:03

有一种上一秒还在道观,下一秒直接进了教室面对着老师的尴尬感

520mariah 发表于 2025-2-10 11:44:58

这素在???疑似飞升学术论坛。突然意识到我的python课程还没学完:)

空玄君 发表于 2025-2-10 12:11:54

嘶,哲学和理论的反复敲击,梦回大学时光,泥潭也是越来越好了!

gamemalen99 发表于 2025-2-10 12:25:53

玛雅泥潭还有教代码的好厉害

万俟 发表于 2025-2-10 12:33:15

这不是我线性代数课上的讲稿嘛?好酷啊

星回 发表于 2025-2-10 15:14:09

不是?泥潭现在发帖都需要这样了吗:funk:

huafa 发表于 2025-2-10 16:38:38

我的天完全看不懂只感觉看完头很晕:funk:

Yang羊 发表于 2025-2-10 16:40:34

芝士有一点像大学里面的高数课的样子,我都已经逃到泥潭还不放过我惹

kimidave 发表于 2025-2-10 16:59:56

看不懂,但是感觉很震撼的说

莲一 发表于 2025-2-10 17:26:35

发的东西太高级了,看不懂额{:4_92:}

l312687174 发表于 2025-2-10 18:56:58

学渣看不懂, 羡慕大佬的技术

themental 发表于 2025-2-10 19:37:39

数学苦手表示你们慢聊我先走了

tuxonstar 发表于 2025-2-11 11:53:34

非常硬核的科普,但是做得很漂亮呢
页: [1] 2
查看完整版本: 【Python】【原创】马尔可夫链与动态行为和长期行为分析