Petri网转换为马尔科夫链算法

本文介绍从Petri网模型转换为马尔科夫链的算法,详细阐述了Petri网与马尔科夫链的基本概念,以及转换算法的具体步骤。Petri网用于描述系统的控制流和信息流,而马尔科夫链是一种随机过程模型。通过算法,Petri网的状态和变迁可以转换为马尔科夫链的状态和转移概率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Petri网转换为马尔科夫链算法

简介

Petri网

Petri网的概念是德国的Carl Adam Petri早在1962年提出来的。他在他的论文里提出了一个新的信息流模型,这个模型基于系统各部分的异步并发的操作,并把各部分之间的关系用网状的图来描述。

Petri网用于描述和分析系统中的控制流和信息流,尤其是那些有异步和并发活动的系统。
圆圈表示位置( place ),圆圈中有标识( token )表示条件( condition )满足。线段( bar)表示变迁( transition )。

马尔科夫链

马尔科夫链(Markov Chain, MC)是具有马尔科夫性质且存在于离散的指数集和状态空间内的随机过程。

马尔科夫性质:下一状态的概率分布只由当前状态决定,在时间序列中当前状态前的事件均与之无关。

满足以下条件的马尔科夫链能收敛:

  1. 可能的状态数是有限的
  2. 状态间的转移概率固定不变
  3. 任意状态之间能互相转换
  4. 不能是简单的循环

细致平衡条件:给定一个马尔科夫链,分布π\piπ和概率矩阵PPP,若式 πiPij=πjPji\pi _iP_{ij}=\pi_jP_{ji}πiPij=πjPji,则马尔科夫链具有一个平稳分布,即 πP=π\pi P=\piπP=π

转换算法

算法描述

算法参考随机Petri网模型到马尔可夫链的转换算法的证明_何炎祥一文,具体过程如下:

入口:Petri网,初始状态M0
出口:邻接表表示的马尔科夫链
PetriNet2MarkovChain:
	将M0加入队列Q
	while Q不为空:
		队首M出队
		求Petri网在状态M下的可实施变迁
		对每个可实施的变迁 t:
			求出Petri网实施t后的状态M'
			判定M'是否为新状态 - 见下 judgeMisNew
			if M' 是新状态:
				将M'加入队列Q
			将M'和t的编号填入M的邻接表
			将M和t的编号填入M'的逆邻接表
			将(M,M')编号序偶填入t对应的单链表
	马尔科夫链 MC = 邻接表,逆邻接表,变迁序偶链表
	return  MC

入口:状态M'
出口:-1:状态M'为新状态
	 >=0:状态M对应的编号,即M不是新状态
judgeMisNew:
	对每个已产生的状态M1
		if M' 与 M1 相同:
			return M1编号
	return -1

代码

代码主要由数据结构部分以及上述两个算法,采用C++编写,未使用较为复杂的数据结构,很容易使用其它编程语言重写,本人曾采用JavaScript重写并生成了一个网页版的demo。

注意:代码仅供参考,提供思路,若有问题,还望指针。

/*
Petri网主要包括如下数据结构:place 库所, transition 变迁, token令牌
马尔科夫链 MC包括:status 状态, transition 变迁
*/
#include <iostream>
#include <queue>
#include <set>
#include <vector>

using namespace std;

typedef pair<int, int> PII;
typedef vector<pair<int, int>> VECPII;
typedef vector<int> VI;
typedef vector<double> VD;

// 变迁
struct Transition {
    int val;
    VI inPlacesId;
    VI outPlacesId;
    Transition(int v, VI &ipids, VI &opids) {
        val = v;
        for (int tmp : ipids)
            inPlacesId.push_back(tmp);
        for (int tmp : opids)
            outPlacesId.push_back(tmp);
    }
};

// 库所 并未使用
struct Place {
    Transition tran;
    int tokenNum;
};

// 马尔科夫链的状态
struct Status {
    VI tokenNumInPlaces;

    Status() {}
    Status(VI &t) {
        for (int tmp : t)
            tokenNumInPlaces.push_back(tmp);
    }
    // 判断两个状态是否相等
    bool equal(const Status &t) {
        int sz = t.tokenNumInPlaces.size();
        if (sz != (int)tokenNumInPlaces.size())
            return false;
        for (int i = 0; i < sz; i++)
            if (tokenNumInPlaces[i] != t.tokenNumInPlaces[i])
                return false;
        return true;
    }
};

// Petri网, 规定每个库所 Place 中的令牌 token 仅保留一个
struct PetriNet {
    // vector<Place> pnPlaces;
    int pnPlaceNum;
    VI valOfTran;
    vector<Transition> pnTransitions;
    // 求出状态 m 下所有可实施的变迁 id
    VI getAvaTranIdsInSta(Status &m) {
        VI resTranIds;
        for (int i = 0; i < (int)pnTransitions.size(); i++) {
            Transition tmpTrans = pnTransitions[i];
            bool tranAvailable = true;
            for (int j = 0; j < (int)tmpTrans.inPlacesId.size(); j++) {
                int tmpPlaceId = tmpTrans.inPlacesId[j];
                // 当前状态的输入库所 InputPlace 是否都包含令牌 token
                if (m.tokenNumInPlaces[tmpPlaceId] < 1) {
                    tranAvailable = false;
                    break;
                }
            }
            if (tranAvailable)
                resTranIds.push_back(i);
        }
        return resTranIds;
    }
    // 在状态 m0 下实施 id 为 transId 的变迁,返回变迁实施后的状态
    // !!! 待实施的变迁应当是可实施的 !!!
    Status fireTrans(int transId, Status &m0) {
        Transition tmpTran = pnTransitions[transId];
        Status resM(m0.tokenNumInPlaces);
        // 所有输入库所令牌 token 减一
        for (int i = 0; i < (int)tmpTran.inPlacesId.size(); i++) {
            int tmpPlaceId = tmpTran.inPlacesId[i];
            resM.tokenNumInPlaces[tmpPlaceId]--;
        }
        // 所有输出库所令牌 token 置 1 !加一!
        for (int i = 0; i < (int)tmpTran.outPlacesId.size(); i++) {
            int tmpPlaceId = tmpTran.outPlacesId[i];
            resM.tokenNumInPlaces[tmpPlaceId] = 1;
        }
        return resM;
    }
};

// 马尔科夫链
struct MarkovChain {
    vector<Status> statusVec;
    vector<VECPII> adjacListOfSta;
    vector<VECPII> revAdjacListOfSta;
    vector<VECPII> listOfTran;
    VI tranVals;

    MarkovChain(const VI &tval) {
        listOfTran.resize(tval.size());
        for (int v : tval)
            tranVals.push_back(v);
    }
    // 获取状态 m0 的所有前驱状态 id 以及 m0 自己
    VI getPreStaOfM(int m0) {
        VI resStaIds;

        queue<int> staIdQue;
        set<int> visStaIds;
        staIdQue.push(m0);
        // 通过逆邻接表寻找 m0 的所有前驱状态
        while (!staIdQue.empty()) {
            int m = staIdQue.front();
            staIdQue.pop();
            resStaIds.push_back(m);
            if ((int)revAdjacListOfSta.size() <= m)
                continue;
            // 遍历当前状态 m 的所有前驱状态
            for (int i = 0; i < (int)revAdjacListOfSta[m].size(); i++) {
                int tmpStaId = revAdjacListOfSta[m][i].first;
                if (visStaIds.find(tmpStaId) == visStaIds.end()) {
                    visStaIds.insert(tmpStaId);
                    staIdQue.push(tmpStaId);
                }
            }
        }
        return resStaIds;
    }

    // 生成状态转移矩阵
    vector<VI> geneMatrixQ() {
        int sz = statusVec.size();
        vector<VI> resMatrix(sz);
        for (int i = 0; i < sz; i++)
            for (int j = 0; j < sz; j++)
                resMatrix[i].push_back(0);
        for (int i = 0; i < sz; i++) {
            int tmpSum = 0;
            for (const PII tmpPair : adjacListOfSta[i]) {
                int tmpTranVal = tranVals[tmpPair.second];
                resMatrix[i][tmpPair.first] = tmpTranVal;
                tmpSum += tmpTranVal;
            }
            resMatrix[i][i] = -tmpSum;
        }
        return resMatrix;
    }
};

// 判断是否为新状态, 返回 状态id 或 新状态 -1
int judgeMarkIsNew(Status &m, int preMid, MarkovChain &mc) {
    for (int i = 0; i < (int)mc.statusVec.size(); i++) {
        if (m.equal(mc.statusVec[i]))
            return i;
    }
    return -1;
}

// 通过随机Petri网(SPN)同构得到马尔科夫链(MC)
// 入口: Petri网 初始状态
MarkovChain createMCFromSPN(PetriNet &pn, Status &m0) {
    MarkovChain resMC(pn.valOfTran);
    resMC.statusVec.push_back(m0);
    resMC.adjacListOfSta.push_back(VECPII());
    resMC.revAdjacListOfSta.push_back(VECPII());
    queue<int> idableStaIdQ;
    idableStaIdQ.push(0);

    while (!idableStaIdQ.empty()) {
        int mid = idableStaIdQ.front();
        Status m = resMC.statusVec[mid];
        idableStaIdQ.pop();
        VI avaTrans = pn.getAvaTranIdsInSta(m);
        for (int i = 0; i < (int)avaTrans.size(); i++) {
            int tmpTranId = avaTrans[i];
            Status firedM = pn.fireTrans(tmpTranId, m);
            int judgeRes = judgeMarkIsNew(firedM, mid, resMC);
            int firedMId = judgeRes;
            // 新状态,加入MC中
            if (judgeRes == -1) {
                firedMId = resMC.statusVec.size();
                resMC.statusVec.push_back(firedM);
                resMC.adjacListOfSta.push_back(VECPII());
                resMC.revAdjacListOfSta.push_back(VECPII());
                idableStaIdQ.push(firedMId);
            }
            resMC.adjacListOfSta[mid].push_back(PII(firedMId, tmpTranId));
            resMC.revAdjacListOfSta[firedMId].push_back(PII(mid, tmpTranId));
            resMC.listOfTran[tmpTranId].push_back(PII(mid, firedMId));
        }
    }
    return resMC;
}
### 将Petri模型转换马尔科夫链的方法 #### 转换的基本原理 为了将Petri(PN)转化为马尔科夫链(MC),需要定义系统的状态空间及其转移概率。Petri中的标记配置代表MC的一个状态,而变迁的发生则对应于从一个状态转移到另一个状态的过程[^1]。 #### 创建状态空间 在Petri中,每一个可能的地方(place)标记分布构成马尔科夫链的一个独立状态。这意味着对于给定的PN结构,所有地方的不同组合方式决定了最终形成的MC有多少个离散状态。考虑到这一点,在实际操作前应当先枚举出所有的合法标记配置作为潜在的状态集合[^3]。 #### 定义转移概率 一旦确定了完整的状态集之后,下一步就是设定各状态间相互转变的可能性大小——即转移矩阵P内的元素p_ij。具体来说,当且仅当存在一条或多条能够使当前系统由i态变为j态的有效路径(也就是触发某些变迁),此时才赋予非零值;反之则设为0。值得注意的是,由于这里讨论的是随机过程而非决定论下的行为模式,所以还需要引入额外参数来量化这些事件发生的频率或倾向程度,比如依据经验数据估计得到的概率密度函数等。 #### 实现示例代码 下面给出一段Python伪代码用于展示上述理论的实际应用: ```python import numpy as np def petrinet_to_markovchain(petrinet_structure, initial_marking): """ Convert Petri Net structure into Markov Chain :param petrinet_structure: A dictionary describing transitions and places connections. :param initial_marking: Initial marking of the net. :return: Transition matrix P representing MC derived from PN. """ states = enumerate_all_possible_states(initial_marking) num_of_states = len(states) # Initialize transition probability matrix with zeros p_matrix = np.zeros((num_of_states, num_of_states)) for i in range(num_of_states): current_state = states[i] enabled_transitions = find_enabled_transitions(current_state, petrinet_structure) total_firing_probabilities = sum([get_transition_probability(t) for t in enabled_transitions]) if not math.isclose(total_firing_probabilities, 0): for j in range(num_of_states): next_state = states[j] common_places = set.intersection(set(current_state.keys()), set(next_state.keys())) matching_place_values = all([ current_state[p] == next_state[p] - get_consumption_arc_weight(t, p) + get_production_arc_weight(t, p) for p in common_places ]) if matching_place_values: firing_probs_sum = sum( [get_transition_probability(t) * int(is_valid_next_state_after_fire(t)) for t in enabled_transitions]) p_matrix[i][j] = firing_probs_sum / total_firing_probabilities return normalize_rows(p_matrix) # Helper functions omitted for brevity... ``` 此段程序展示了如何遍历所有可达状态并计算它们之间的相对跃迁几率,从而建立起描述整个动态变化规律的数学框架。需要注意的是这只是一个简化版本的概念验证工具,并未完全覆盖现实中复杂情况所需处理的各种细节问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值