Random 从多值法线绘制,带;genmn“;及;setgmn";

Random 从多值法线绘制,带;genmn“;及;setgmn";,random,fortran,Random,Fortran,我试图从多重正态分布中随机抽取偏差。 我在网上找到了两个子程序:“setgmn”和“genmn”,它们应该就是这样做的。它们来自“ranlib”图书馆 然而,我不知道这些子例程是如何协同工作的。 Setgmn以genmn可以使用的方式组合数据。然而,我与“帕尔姆”的论点斗争,我不确定我必须传递什么。以及这两个子例程需要如何组合才能实际工作 我在网上找不到一个例子。所以我想这里可能有人已经用过了,或者有一个链接到网上的一个例子 来自: 首先,您必须调用setgmn。此过程将设置必须传递到getm

我试图从多重正态分布中随机抽取偏差。 我在网上找到了两个子程序:“setgmn”和“genmn”,它们应该就是这样做的。它们来自“ranlib”图书馆

然而,我不知道这些子例程是如何协同工作的。 Setgmn以genmn可以使用的方式组合数据。然而,我与“帕尔姆”的论点斗争,我不确定我必须传递什么。以及这两个子例程需要如何组合才能实际工作

我在网上找不到一个例子。所以我想这里可能有人已经用过了,或者有一个链接到网上的一个例子

来自:

首先,您必须调用
setgmn
。此过程将设置必须传递到
getmn
的参数
parm

subroutine setgmn ( meanv, covm, p, parm )
  integer ( kind = 4 ) p
  real ( kind = 4 ) covm(p,p)
  real ( kind = 4 ) meanv(p)
  real ( kind = 4 ) parm(p*(p+3)/2+1)
参数

MEANV
:多元正态分布的平均值

COVM
:输入时,多元分布的协方差矩阵。输出时,COVM中的信息已被覆盖

p
:尺寸的数量

PARM
:生成多元正态偏差所需的参数

PARM(1)
包含偏差的大小,p

PARM(2:p+1)
包含平均向量

PARM(p+2:p*(p+3)/2+1)
包含协方差矩阵的Cholesky分解的上半部分


参数

PARM(p*(p+3)/2+1)
:由SETGMN设置的参数

X(p)
:随机偏离分布。将是输出


WORK(p)
:workspace

这里是您所需要的另一种现代实现,它使用MVN协方差矩阵的Cholesky分解,而不是协方差矩阵本身,然后是一个如何使用它的示例:

module RandMVN_mod

    implicit none

contains

!***********************************************************************************************************************************
!***********************************************************************************************************************************

    ! Returns a multivariate normal random number.
    function getRandMVN(nd,MeanVec,CholeskyLower,Diagonal) result(RandMVN)
        use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
        implicit none
        integer(IK), intent(in) :: nd                   ! dimension of the MVN
        real(RK)   , intent(in) :: MeanVec(nd)          ! The Mean vector of the MVN from which points are drawn
        real(RK)   , intent(in) :: CholeskyLower(nd,nd) ! Lower Triangle of the Cholesky Factorization of the covariance matrix of the MVN
        real(RK)   , intent(in) :: Diagonal(nd)         ! Diagonal terms of the Cholesky Factorization of the covariance matrix of the MVN
        real(RK)                :: RandMVN(nd), dummy
        integer(IK)             :: j,i
        RandMVN = 0._RK
        do j = 1,nd
            dummy = getRandGaus()
            RandMVN(j) = RandMVN(j) + Diagonal(j) * dummy
            do i = j+1,nd
                RandMVN(i) = RandMVN(i) + CholeskyLower(i,j) * dummy
            end do
        end do
        RandMVN = RandMVN + MeanVec
    end function getRandMVN

!***********************************************************************************************************************************
!***********************************************************************************************************************************

    ! returns a normally distributed random number with zero mean and unit variance.
    function getRandGaus()

        use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
        implicit none
        integer(IK), save :: iset=0
        real(RK)   , save :: gset
        real(RK)          :: fac,rsq,vec(2)  
        real(RK)          :: getRandGaus

        if (iset == 0) then
            do
                call random_number(vec)
                vec = 2._RK*vec - 1._RK
                rsq = vec(1)**2 + vec(2)**2
                if ( rsq > 0._RK .and. rsq < 1._RK ) exit
            end do
            fac = sqrt(-2._RK*log(rsq)/rsq)
            gset = vec(1)*fac
            getRandGaus = vec(2)*fac
            iset = 1
        else
            getRandGaus = gset
            iset = 0
        endif

    end function getRandGaus

!***********************************************************************************************************************************
!***********************************************************************************************************************************

    ! Returns the the Cholesky factorization of input positive definite matrix PosDefMat
    subroutine getCholeskyFactor(nd,PosDefMat,Diagonal)
        use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
        implicit none
        integer(IK), intent(in)    :: nd
        real(RK)   , intent(inout) :: PosDefMat(nd,nd) ! Upper triangle + diagonal is input matrix, lower is output.
        real(RK)   , intent(out)   :: Diagonal(nd)
        real(RK)                   :: summ
        integer(IK)                :: i
        do i=1,nd
            summ = PosDefMat(i,i) - dot_product(PosDefMat(i,1:i-1),PosDefMat(i,1:i-1))
            if (summ <= 0._RK) then

                error stop
            end if
            Diagonal(i) = sqrt(summ)
            PosDefMat(i+1:nd,i) = ( PosDefMat(i,i+1:nd) - matmul(PosDefMat(i+1:nd,1:i-1),PosDefMat(i,1:i-1)) ) / Diagonal(i)
        end do
    end subroutine getCholeskyFactor

!***********************************************************************************************************************************
!***********************************************************************************************************************************

end module RandMVN_mod

program test_RandMVN

    use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
    use RandMVN_mod
    implicit none
    integer(IK)             :: isample
    integer(IK) , parameter :: nd = 2           ! dimension of the Multivariate distribution (MVN)
    integer(IK) , parameter :: nsample = 100    ! count of random numbers
    real(RK)    , parameter :: CovMat(nd,nd) = reshape([ 1._RK , 0.5_RK , 0.5_RK , 1._RK ], shape=shape(CovMat))  ! covariance matrix of MVN
    real(RK)    , parameter :: MeanVec(nd) = [ 1._RK , 1._RK ]  ! mean vector of the MVN
    real(RK)                :: CholeskyLower(nd,nd), Diagonal(nd)

    ! get the Cholesky factorization of the Covariance Matrix
    CholeskyLower = CovMat
    call getCholeskyFactor(nd,CholeskyLower,Diagonal)

    ! get random MVN vectors form the MVN distribution
    do isample = 1,nsample
        write(*,"(*(g0,' '))") getRandMVN(nd,MeanVec,CholeskyLower,Diagonal), " ;"
    end do

end program test_RandMVN
模块RandMVN\u模块
隐式无
包含
!***********************************************************************************************************************************
!***********************************************************************************************************************************
! 返回多元正态随机数。
函数getRandMVN(nd、MeanVec、CholeskyLower、对角线)结果(RandMVN)
使用,内在::iso_fortran_env,仅限:IK=>int32,RK=>real64
隐式无
整数(IK),意图(in)::nd!MVN的维度
真实(RK),意图(in)::平均(nd)!绘制点的MVN的平均向量
雷亚尔(RK),意图(in)::切洛斯基洛(nd,nd)!MVN协方差矩阵的Cholesky分解的下三角
真实(RK),意图(in)::对角线(nd)!MVN协方差矩阵Cholesky分解的对角项
真实的(RK):随机的(nd),虚拟的
整数(IK)::j,i
RandMVN=0.\u RK
do j=1,nd
dummy=getRandGaus()
RandMVN(j)=RandMVN(j)+对角线(j)*假人
i=j+1,nd
RandMVN(i)=RandMVN(i)+天鹅绒(i,j)*假人
结束
结束
RandMVN=RandMVN+MeanVec
结束函数getRandMVN
!***********************************************************************************************************************************
!***********************************************************************************************************************************
! 返回均值和单位方差为零的正态分布随机数。
函数getRandGaus()
使用,内在::iso_fortran_env,仅限:IK=>int32,RK=>real64
隐式无
整数(IK),保存::iset=0
实(RK),保存::gset
雷亚尔(RK):外交部、区域安全部、外交部(2)
雷亚尔(RK)::格特兰高斯
如果(iset==0),则
做
呼叫随机号码(vec)
vec=2._RK*vec-1._RK
rsq=vec(1)**2+vec(2)**2
如果(rsq>0.\u RK.和.rsq<1.\u RK)退出
结束
fac=sqrt(-2._RK*log(rsq)/rsq)
gset=vec(1)*fac
getRandGaus=vec(2)*fac
iset=1
其他的
getRandGaus=gset
iset=0
恩迪夫
端函数getRandGaus
!***********************************************************************************************************************************
!***********************************************************************************************************************************
! 返回输入正定矩阵PosDefMat的Cholesky分解
子例程getCholeskyFactor(nd、PosDefMat、对角线)
使用,内在::iso_fortran_env,仅限:IK=>int32,RK=>real64
隐式无
整数(IK),意图(in)::nd
真实(RK),意图(inout)::PosDefMat(nd,nd)!上部三角形+对角线为输入矩阵,下部为输出矩阵。
真实(RK)、意图(out)::对角线(nd)
雷亚尔(RK)::总和
整数(IK)::i
i=1,nd吗
summ=PosDefMat(i,i)-dot_积(PosDefMat(i,1:i-1),PosDefMat(i,1:i-1))
如果(总和int32,RK=>real64
使用RandMVN_mod
隐式无
整数(IK)::isample
整数(IK),参数::nd=2!多元分布(MVN)的维数
整数(IK),参数::nsample=100!随机数计数
实数(RK),参数::CovMat(nd,nd)=重塑([1._RK,0.5_RK,0.5_RK,1._RK],形状=形状(CovMat))!MVN的协方差矩阵
实数(RK),参数::平均向量(nd)=[1._RK,1._RK]!MVN的平均向量
真实的(
module RandMVN_mod

    implicit none

contains

!***********************************************************************************************************************************
!***********************************************************************************************************************************

    ! Returns a multivariate normal random number.
    function getRandMVN(nd,MeanVec,CholeskyLower,Diagonal) result(RandMVN)
        use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
        implicit none
        integer(IK), intent(in) :: nd                   ! dimension of the MVN
        real(RK)   , intent(in) :: MeanVec(nd)          ! The Mean vector of the MVN from which points are drawn
        real(RK)   , intent(in) :: CholeskyLower(nd,nd) ! Lower Triangle of the Cholesky Factorization of the covariance matrix of the MVN
        real(RK)   , intent(in) :: Diagonal(nd)         ! Diagonal terms of the Cholesky Factorization of the covariance matrix of the MVN
        real(RK)                :: RandMVN(nd), dummy
        integer(IK)             :: j,i
        RandMVN = 0._RK
        do j = 1,nd
            dummy = getRandGaus()
            RandMVN(j) = RandMVN(j) + Diagonal(j) * dummy
            do i = j+1,nd
                RandMVN(i) = RandMVN(i) + CholeskyLower(i,j) * dummy
            end do
        end do
        RandMVN = RandMVN + MeanVec
    end function getRandMVN

!***********************************************************************************************************************************
!***********************************************************************************************************************************

    ! returns a normally distributed random number with zero mean and unit variance.
    function getRandGaus()

        use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
        implicit none
        integer(IK), save :: iset=0
        real(RK)   , save :: gset
        real(RK)          :: fac,rsq,vec(2)  
        real(RK)          :: getRandGaus

        if (iset == 0) then
            do
                call random_number(vec)
                vec = 2._RK*vec - 1._RK
                rsq = vec(1)**2 + vec(2)**2
                if ( rsq > 0._RK .and. rsq < 1._RK ) exit
            end do
            fac = sqrt(-2._RK*log(rsq)/rsq)
            gset = vec(1)*fac
            getRandGaus = vec(2)*fac
            iset = 1
        else
            getRandGaus = gset
            iset = 0
        endif

    end function getRandGaus

!***********************************************************************************************************************************
!***********************************************************************************************************************************

    ! Returns the the Cholesky factorization of input positive definite matrix PosDefMat
    subroutine getCholeskyFactor(nd,PosDefMat,Diagonal)
        use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
        implicit none
        integer(IK), intent(in)    :: nd
        real(RK)   , intent(inout) :: PosDefMat(nd,nd) ! Upper triangle + diagonal is input matrix, lower is output.
        real(RK)   , intent(out)   :: Diagonal(nd)
        real(RK)                   :: summ
        integer(IK)                :: i
        do i=1,nd
            summ = PosDefMat(i,i) - dot_product(PosDefMat(i,1:i-1),PosDefMat(i,1:i-1))
            if (summ <= 0._RK) then

                error stop
            end if
            Diagonal(i) = sqrt(summ)
            PosDefMat(i+1:nd,i) = ( PosDefMat(i,i+1:nd) - matmul(PosDefMat(i+1:nd,1:i-1),PosDefMat(i,1:i-1)) ) / Diagonal(i)
        end do
    end subroutine getCholeskyFactor

!***********************************************************************************************************************************
!***********************************************************************************************************************************

end module RandMVN_mod

program test_RandMVN

    use, intrinsic :: iso_fortran_env, only: IK => int32, RK => real64
    use RandMVN_mod
    implicit none
    integer(IK)             :: isample
    integer(IK) , parameter :: nd = 2           ! dimension of the Multivariate distribution (MVN)
    integer(IK) , parameter :: nsample = 100    ! count of random numbers
    real(RK)    , parameter :: CovMat(nd,nd) = reshape([ 1._RK , 0.5_RK , 0.5_RK , 1._RK ], shape=shape(CovMat))  ! covariance matrix of MVN
    real(RK)    , parameter :: MeanVec(nd) = [ 1._RK , 1._RK ]  ! mean vector of the MVN
    real(RK)                :: CholeskyLower(nd,nd), Diagonal(nd)

    ! get the Cholesky factorization of the Covariance Matrix
    CholeskyLower = CovMat
    call getCholeskyFactor(nd,CholeskyLower,Diagonal)

    ! get random MVN vectors form the MVN distribution
    do isample = 1,nsample
        write(*,"(*(g0,' '))") getRandMVN(nd,MeanVec,CholeskyLower,Diagonal), " ;"
    end do

end program test_RandMVN