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

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

简介

Petri网

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

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

马尔科夫链

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

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

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

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

细致平衡条件:给定一个马尔科夫链,分布 π \pi π和概率矩阵 P P P,若式 π i P i j = π j P j i \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;
}
  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值