[信息论]信道容量迭代算法程序设计(基于C++&Matlab实现)

算法分析

迭代法计算信道容量 C C C 的步骤如下:

首先,记 p ( y j ∣ x i ) = p i j p(y_j|x_i) = p_{ij} p(yjxi)=pij , p ( x i ) = p i p(x_i)=p_i p(xi)=pi , p ( x i ∣ y j ) = ϕ j i p(x_i|y_j)=\phi _{ji} p(xiyj)=ϕji ,其中 i = 1 , 2 , ⋯   , n ; j = 1 , 2 , ⋯   , m i=1,2,\cdots,n;j=1,2,\cdots,m i=1,2,,n;j=1,2,,m.算法中信息量的单位是奈特。

1.初始化参数

初始条件已知信源分布 p ( 0 ) { p 1 p 2 ⋯ p n } \pmb{{p^{(0)}}}\left\{ \begin{matrix} p_1\\p_2\\ \cdots \\p_n \end{matrix} \right\} p(0)p(0) p1p2pn (初始化为均匀分布),信道转移概率矩阵 P = { p 11 p 12 ⋯ p 1 m p 21 p 22 ⋯ p 2 m ⋮ ⋮ ⋱ ⋮ p n 1 p n 2 ⋯ p n m } \pmb{P}= \left\{ \begin{matrix} p_{11} & p_{12} & \cdots & p_{1m}\\ p_{21} & p_{22} & \cdots & p_{2m} \\ \vdots & \vdots & \ddots & \vdots \\ p_{n1} & p_{n2} & \cdots & p_{nm} \end{matrix} \right\} PP= p11p21pn1p12p22pn2p1mp2mpnm ,信道容量初值 C ( 0 ) = − ∞ \pmb{C^{(0)}}=-\infty C(0)C(0)=,信道容量相对误差门限 δ > 0 \delta>0 δ>0, 状态参数 k k k ,初值为 0 0 0.

2.迭代后验概率矩阵

ϕ j i ( k ) = p i j p i ( k ) ∑ i p i j p i ( k ) \phi_{ji}^{(k)}=\frac{p_{ij}p_i^{(k)}}{\sum_i p_{ij}p_i^{(k)}} ϕji(k)=ipijpi(k)pijpi(k)

3.迭代信源分布

由于算法中采用奈特作为信息量单位,同时已知下式
a b = e b l n a a^b=e^{blna} ab=eblna
因此迭代信源分布状态转移方程可以化简为:
p i ( k + 1 ) = e ∑ j p i j l n ϕ j i ( k ) ∑ i e ∑ j p i j l n ϕ j i ( k ) = ∏ j ( ϕ j i ( k ) ) p i j ∑ i ∏ j ( ϕ j i ( k ) ) p i j , i = 1 , ⋯   , r p_i^{(k+1)}=\frac{e^{\sum_j p_{ij}ln \phi_{ji}^{(k)}}}{\sum_i{e^{\sum_j p_{ij}ln \phi_{ji}^{(k)}}}}=\frac{\prod_j{{(\phi_{ji}^{(k)})}^{p_{ij}}}}{\sum_i \prod_j{{(\phi_{ji}^{(k)})}^{p_{ij}}}},i=1,\cdots,r pi(k+1)=iejpijlnϕji(k)ejpijlnϕji(k)=ij(ϕji(k))pijj(ϕji(k))pij,i=1,,r
这样进行处理的好处是,后向概率中有些元素的值为 0 0 0 ,对于大部分编程语言来说, l n 0 ln0 ln0 的运算一般是输出 n a n nan nan 运算符,无法得到正确计算结果。

4. 迭代信道容量

( 3 ) (3) (3) 中的分析可知,信道容量迭代方程可以化简为
C ( k + 1 ) = l n ( ∑ i e ∑ j p i j l n ϕ j i ( k ) ) = l n ( ∑ i ∏ j ( ϕ j i ( k ) ) p i j ) C^{(k+1)}=ln(\sum_i{e^{\sum_j p_{ij}ln \phi_{ji}^{(k)}}})=ln(\sum_i \prod_j{{(\phi_{ji}^{(k)})}^{p_{ij}}}) C(k+1)=ln(iejpijlnϕji(k))=ln(ij(ϕji(k))pij)

5.判定信道容量是否达到 δ \delta δ 精度范围要求

∣ C ( k + 1 ) − C ( k ) ∣ C ( k + 1 ) ⩽ δ \frac{|C^{(k+1)}-C^{(k)}|}{C^{(k+1)}} \leqslant \delta C(k+1)C(k+1)C(k)δ ,则停止迭代输出结果,否则继续迭代。

C++ Codes

/**
  ******************************************************************************
  * @file    Project/Template/main.cpp
  * @author  水声工程学院 LZH 2019051312
  * @version V1.0.0
  * @date    21-March-2022
  * @brief   Main program body
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include<iostream>
#include<iomanip>
#include<cmath>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ll long long
#define ld long double
#define pb push_back
#define eps 1e-8  //Change this value to upgrade precision
using namespace std;
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ld P_ij[105][105]={0};  //Transition probability matrix
ld Phi_ij[105][105]={0}; //Posterior probability matrix
ld p[105]; //Prior probability matrix
ld C0=-114514,C1=0; //C0:C(k) C1:C(k+1)
int n,m; //n rows and m columns
/* Private function prototypes -----------------------------------------------*/
ld C_update(int n,int m,ld (&phi_ij)[105][105],ld (&p_ij)[105][105]);
void p_update(int n,int m,ld (&phi_ij)[105][105],ld (&p_ij)[105][105]);
void Phi_update(int n,int m,ld (&phi_ij)[105][105],ld (&p_ij)[105][105]);
bool check(ld a,ld b);
/* Private functions -----------------------------------------------*/
/**
  * @brief  Get abs value of the input parameter.
  * @param  A long double format parameter.
  * @retval The abs value of the input parameter.
  */
ld abss(ld a){
   if (a<0)
	  return -a;
   return a;
}
/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(){
	ios::sync_with_stdio(0); //accelerate cin and cout.
	int step=0; //Steps of current iteration.
	/*Get all parameters*/
	cin>>n>>m;
	for (int i=1; i<=n; i++){
		p[i]=1.0/(ld)n; //Initialized array p into evenly distributed state.
		for (int j=1; j<=m; j++)
			cin>>P_ij[i][j];
	}

	/*Iteration procedure*/
	while (!check(C1,C0) || !step){
		C0=C1;
		Phi_update(n,m,Phi_ij,P_ij); //Update phi_{k} first.
		p_update(n,m,Phi_ij,P_ij); //Update p_{k+1}
		C1=C_update(n,m,Phi_ij,P_ij);//Update C_{k+1}
		step++; //Transfer to next state
	}
	
	/*Print out all answers*/
	cout.setf(ios::fixed); 
	for (int i=1; i<=n; i++) //Output Prior probability matrix
		cout<<setprecision(15)<<p[i]<<' ';
	cout<<'\n';
	cout<<C1<<endl; //Output C(k+1)
	return 0;
}


/**
  * @brief  Iterate the value of C(k+1)
  * @param  n: total number of rows. Passed by value.
  * @param  m: total number of columns. Passed by value.
  * @param  phi_ij: The Posterior probability matrix. Passed by reference.
  * @param  p_ij: The Prior probability matrix. Passed by reference.
  * @retval C(k+1)
  */
ld C_update(int n,int m,ld (&phi_ij)[105][105],ld (&p_ij)[105][105]){ 
    ld sum=0,sum_tmp=0,ans;
	for (int i=1; i<=n; i++){
		sum_tmp=1;
		for (int j=1; j<=m; j++)
			sum_tmp*=pow(phi_ij[i][j],p_ij[i][j]);
		sum+=sum_tmp;
	}
	ans=log(sum);
	return ans;
}

/**
  * @brief  Iterate the sequence of p.
  * @param  n: total number of rows. Passed by value.
  * @param  m: total number of columns. Passed by value.
  * @param  phi_ij: The Posterior probability matrix. Passed by reference.
  * @param  p_ij: The Prior probability matrix. Passed by reference.
  * @retval None.
  */
void p_update(int n,int m,ld (&phi_ij)[105][105],ld (&p_ij)[105][105]){ 
	ld sum=0,sum_tmp=0;
	for (int i=1; i<=n; i++){
		sum_tmp=1;
		for (int j=1; j<=m; j++)
			sum_tmp*=pow(phi_ij[i][j],p_ij[i][j]);
		sum+=sum_tmp;
	}
	
	for (int i=1; i<=n; i++){
		sum_tmp=1;
		for (int j=1; j<=m; j++)
			sum_tmp*=pow(phi_ij[i][j],p_ij[i][j]);
		p[i]=sum_tmp/sum;
	}
	return;
}

/**
  * @brief  Iterate the Posterior probability matrix.
  * @param  n: total number of rows. Passed by value.
  * @param  m: total number of columns. Passed by value.
  * @param  phi_ij: The Posterior probability matrix. Passed by reference.
  * @param  p_ij: The Prior probability matrix. Passed by reference.
  * @retval None.
  */
void Phi_update(int n,int m,ld (&phi_ij)[105][105],ld (&p_ij)[105][105]){ 
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++){
			ld sum=0;
			for (int k=1; k<=n; k++)
				sum+=p_ij[k][j]*p[k];
			phi_ij[i][j]=p_ij[i][j]*p[i]/sum;
		}
	return;
}

/**
  * @brief  Check whether or not C(k+1) satisfies eps range.
  * @param  a: C(k+1). Passed by value.
  * @param  b: C(k). Passed by value.
  * @retval True or False.
  */
bool check(ld a,ld b){
	ld tot;
	tot=abss(a-b)/a;
	if (tot<=eps)
		return true;
	return false;
}
/**
  * @}
  */

/************************END OF FILE*******************************/

Matlab Codes

eps=1e-8;
owari=0;
C0=-114514;
C1=0;
n=input('Input row num=');
m=input('Input column num=');
Phi_ij=zeros(n,m);
for ii=1:n
    p(ii)=1/n;
    for jj=1:m
        P_ij(ii,jj)=input(''); %Input the Prior probability matrix
    end
end

while (~owari)
       C0=C1;
       %Iterate Matrix Phi
       for ii=1:n
           for jj=1:m
               sum=0;
               for kk=1:n
                   sum=sum+P_ij(kk,jj)*p(kk);
               end
               Phi_ij(ii,jj)=P_ij(ii,jj)*p(ii)/sum;
           end
       end
       %Iterate the sequence of p
       sum=0; sum_tmp=0;
       for ii=1:n
           sum_tmp=1;
           for jj=1:m
               sum_tmp=sum_tmp*(Phi_ij(ii,jj)^P_ij(ii,jj));
           end
           sum=sum+sum_tmp;
       end
       
       for ii=1:n
           sum_tmp=1;
           for jj=1:m
               sum_tmp=sum_tmp*(Phi_ij(ii,jj)^P_ij(ii,jj));
           end
           p(ii)=sum_tmp/sum;
       end
       %Iterate the value of C(k+1)
       sum=0; sum_tmp=0;
       for ii=1:n
           sum_tmp=1;
           for jj=1:m
               sum_tmp=sum_tmp*(Phi_ij(ii,jj)^P_ij(ii,jj));
           end
           sum=sum+sum_tmp;
       end
       C1=log(sum);
       %check whether or not C(k+1) satisfies eps range.
       tot=abs(C1-C0)/C1;
       if (tot<=eps)
           owari=1;
       end
end

%Output the results
fprintf('p(k+1)=[');
for ii=1:n
    fprintf('%20.15f ',p(ii));
end
str=[']'];
disp(str);
fprintf('C(k+1)=%20.15f\n',C1);

测试数据与结果展示

测试数据

测试数据使用教材 P 61  例 4.7 P61\ 例4.7 P61 4.7 测试数据。

输入数据

P = { 1 0 1 0 0.5 0.5 0 1 0 1 } \pmb{P}= \left\{ \begin{matrix} 1& 0\\1 & 0\\ 0.5 & 0.5\\0 & 1\\ 0& 1 \end{matrix} \right\} PP= 110.500000.511 , e p s = 1 0 − 8 eps=10^{-8} eps=108, p ( 0 ) = ( 0.2 , 0.2 , 0.2 , 0.2 , 0.2 ) \pmb{p^{(0)}}=(0.2,0.2,0.2,0.2,0.2) p(0)p(0)=(0.2,0.2,0.2,0.2,0.2), C ( 0 ) = − ∞ \pmb{C^{(0)}}=-\infty C(0)C(0)=

输出数据

p ( k + 1 ) = ( 0.25 , 0.25 , 0 , 0.25 , 0.25 ) \pmb{p^{(k+1)}}=(0.25,0.25,0,0.25,0.25) p(k+1)p(k+1)=(0.25,0.25,0,0.25,0.25), C ( k + 1 ) = 1 b i t = 0.6931471806 n a t \pmb{C^{(k+1)}}=1bit=0.6931471806nat C(k+1)C(k+1)=1bit=0.6931471806nat

测试结果(C++)

在这里插入图片描述

测试结果(Matlab)

在这里插入图片描述

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值