Haskell 中的随机数采样序列

2024-03-27

我需要小列表的高斯随机数进行模拟,所以我尝试了以下操作:

import System.Random

seed = 10101
gen = mkStdGen seed

boxMuller mu sigma (r1,r2) =  mu + sigma * sqrt (-2 * log r1) * cos (2 * pi * r2) 

这只是 Box-Muller 算法 - 给定 [0,1] 区间内的 r1, r2 均匀随机数,它返回一个高斯随机数。

normals 0 g = [] 
normals n g = take n $ map (boxMuller 0 1) $ pairs $ randoms g
    where pairs (x:y:zs) = (x,y):(pairs zs)

所以我用了这个normals每当我需要随机数列表时,它都会起作用。

问题一定很明显:它总是生成相同的序列,因为我总是使用相同的种子!我没有得到新的序列,我一直只得到序列的前 n 个值。

当我输入时,我明显假装的是:

x = normal 10 
y = normal 50

我会让 x 成为前 10 个值map (boxMuller 0 1) $ pairs $ randoms gy 是该列表中接下来的 50 个值,依此类推。

当然这是不可能的,因为给定相同的输入,函数必须始终返回相同的值。我该如何逃脱这个陷阱?


我认为,在抽象生成器的 monad 中进行需要随​​机数的计算是最干净的事情。该代码如下所示:

我们将把 StdGen 实例放入状态 monad 中,然后在状态 monad 的 get 和 set 方法上提供一些糖,以给我们随机数。

首先,加载模块:

import Control.Monad.State (State, evalState, get, put)
import System.Random (StdGen, mkStdGen, random)
import Control.Applicative ((<$>))

(通常我可能不会指定导入,但这使得很容易理解每​​个函数的来源。)

然后我们将定义“需要随机数的计算”monad;在本例中,别名为State StdGen called R。 (因为“随机”和“兰德”已经意味着其他含义。)

type R a = State StdGen a

R 的工作方式是:定义一个需要随机数流(单子“动作”)的计算,然后使用runRandom:

runRandom :: R a -> Int -> a
runRandom action seed = evalState action $ mkStdGen seed

这需要一个操作和一个种子,并返回操作的结果。就像平常一样evalState, runReader, etc.

现在我们只需要 State monad 周围的糖。我们用get获取 StdGen,我们使用put安装一个新状态。这意味着,要获得一个随机数,我们可以这样写:

rand :: R Double
rand = do
  gen <- get
  let (r, gen') = random gen
  put gen'
  return r

我们获取随机数生成器的当前状态,用它来获取新的随机数和新的生成器,保存随机数,安装新的生成器状态,然后返回随机数。

这是一个可以用 runRandom 运行的“动作”,所以让我们尝试一下:

ghci> runRandom rand 42
0.11040701265689151                           
it :: Double     

这是一个纯函数,因此如果您使用相同的参数再次运行它,您将得到相同的结果。杂质保留在您传递给 runRandom 的“动作”内。

不管怎样,你的函数需要成对的随机数,所以让我们编写一个动作来生成一个pair随机数:

randPair :: R (Double, Double)
randPair = do
  x <- rand
  y <- rand
  return (x,y)

使用 runRandom 运行此命令,您将看到这对数字中的两个不同数字,正如您所期望的那样。但请注意,您不必为“rand”提供参数;这是因为函数是纯粹的,但“rand”是一个动作,它不必是纯粹的。

现在我们可以实施您的normals功能。boxMuller正如您在上面定义的那样,我只是添加了一个类型签名,这样我就可以了解发生了什么而不必阅读整个函数:

boxMuller :: Double -> Double -> (Double, Double) -> Double
boxMuller mu sigma (r1,r2) =  mu + sigma * sqrt (-2 * log r1) * cos (2 * pi * r2)

实现了所有辅助函数/操作后,我们终于可以编写normals,一个 0 个参数的操作,返回一个(延迟生成的)正态分布双精度数的无限列表:

normals :: R [Double]
normals = mapM (\_ -> boxMuller 0 1 <$> randPair) $ repeat ()

如果你愿意的话,你也可以写得更简洁:

oneNormal :: R Double
oneNormal = do
    pair <- randPair
    return $ boxMuller 0 1 pair

normals :: R [Double]
normals = mapM (\_ -> oneNormal) $ repeat ()

repeat ()为单子动作提供无限的流来调用函数(这也是法线结果无限长的原因)。我最初写的是[1..],但我重写了它以删除无意义的1从程序文本。我们不是对整数进行操作,我们只是想要一个无限列表。

无论如何,就是这样。要在实际程序中使用它,您只需在 R 动作中执行需要随机法线的工作:

someNormals :: Int -> R [Double]
someNormals x = liftM (take x) normals

myAlgorithm :: R [Bool]
myAlgorithm = do
   xs <- someNormals 10
   ys <- someNormals 10
   let xys = zip xs ys
   return $ uncurry (<) <$> xys

runRandom myAlgorithm 42

适用于对一元操作进行编程的常用技术;保留尽可能少的应用程序R尽可能的,事情不会太混乱。

哦,还有另一件事:惰性可以干净地“泄漏”到 monad 边界之外。这意味着你可以写:

take 10 $ runRandom normals 42

它会起作用的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 中的随机数采样序列 的相关文章

随机推荐

  • 数据库子类型/超级类型[重复]

    这个问题在这里已经有答案了 我有 农作物 玉米 大豆 和 谷物 表 Crop 中的一个条目对应于其他表之一中的单个条目 裁剪应仅与其他一张表一对一 但不得超过一张 Crop 表是必需的 因为它结合了其他表中的许多通用数据 并使代码端的信息查
  • 将双精度值转换为二进制值

    如何将双精度值转换为二进制值 我有一些像下面这样的值 125252525235558554452221545332224587265 我想将其转换为二进制格式 所以我将其保留为双精度 然后尝试转换为二进制 1 0 s 我正在使用 C net
  • 如何缓存或预加载SKLabelNode字体?

    我正在制作一个 Sprite Kit 应用程序 并在我的场景中添加了一个 SKLabelNode 当我加载 SKScene 时 我注意到有一个相当大的滞后峰值 在对应用程序进行分析后 我发现它来自于使用纸莎草字体创建 SKLabelNode
  • 如何使用 python 读取专辑封面? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 在我的搜索中 我发现有一些库可以通过读取 ID3 标签来做到这一点 如果是这样 哪一个最好用 我不打算
  • 将委托定义为函数指针

    我正在使用调用非托管函数指针的委托 这会导致垃圾收集器在使用之前对其进行收集 如 MSDN 上的 CallbackOnCollectedDelegate MDA 页面中所述 CallbackOnCollectedDelegate MDA 的
  • 在 WPF (MVVM) 中动态更改窗口的用户控件

    我是新来的WPF我只是用做一个简单的菜单MVVM with bindings and commands但我想我做错了什么 我只想更改所有窗口内容导入新的UserControl我定义了 每次按下菜单按钮时 这意味着我想消失菜单并显示新内容 我
  • mongodb 聚合 $lookup 与查找和填充

    我有一个像这样的视频架构 const VideoSchema new mongoose Schema caption type String trim true maxlength 512 required true owner type
  • 为什么应用程序突然关闭而没有显示任何错误?

    我的应用程序有什么作用 该应用程序正在从照片库中选择一张照片 我的问题是什么 一旦我从图库中选择照片 它就会毫无错误地关闭 我做了什么 我增加了设备的内存 但它不起作用 我把它从项目中取出来 活动运行良好 然后又回到了活动中 主要问题是什么
  • Python Ctypes Null 终止字符串块

    我正在使用 ctypes 实现使用登录创建进程 http msdn microsoft com en us library ms682429 aspx 一切正常 除了我不知道如何处理这一部分 指向新进程的环境块的指针 如果该参数为NULL
  • 如何处理 RxJava 中 Observable 中的 map() 中的异常

    我想做这个 Observable just bitmap map new Func1
  • HttpContext.Current.Request.ServerVariables["HTTP_REFERER"] null

    我正在尝试使用以下代码来获取 global asax session start 中的引用 url HttpContext Current Request ServerVariables HTTP REFERER 我尝试使用Request
  • 将默认 Python 版本从 2.4 更改为 2.6

    我想使用一些需要 Python 的新软件2 6 我们目前都有2 4 and 2 6安装在我们专用的 CentOS 服务器上 如下所示 which python usr local bin python which python2 6 usr
  • Javascript 倒计时每周六上午 11 点

    我有一个请求 要求它看起来与我在这里找到的大多数答案略有不同 我正在寻找一个 Javascript 倒计时时钟 它根据服务器的时钟在每周六上午 11 点重复 但服务器位于 CA 并且时钟需要为 EST 我分叉了另一个时钟作为开始 但是当涉及
  • 方法“train_test_split”中的参数“stratify”(scikit Learn)

    我正在尝试使用train test split来自 scikit Learn 包 但我在参数方面遇到问题stratify 以下是代码 from sklearn import cross validation datasets X iris
  • htmlagilitypack - 删除脚本和样式?

    我使用以下方法从 html 中提取文本 public string getAllText string html string allText try HtmlAgilityPack HtmlDocument document new Ht
  • 在 import 语句之前设置 pythonpath

    我的代码是 import scriptlib abc import scriptlib xyz def foo some operations 但 scriptlib 位于其他目录中 因此我必须将该目录包含在环境变量 PYTHONPATH
  • 运行时检查失败 #0 - ESP 的值未在函数调用中正确保存

    我创建了一个简单的程序 演示了使用多重继承的 Qt 应用程序遇到的运行时错误 继承树如下所示 QGraphicsItem abstract QGraphicsLineItem MyInterface abstract MySubclass
  • jQuery 图像悬停效果

    我正在努力实现这个效果 http stuff maikeldaloo com jq img hover mousescroll swf使用 jQuery 我写了一些代码 但它有错误 移到右下角你就会看到 一探究竟 http stuff ma
  • MySQL 服务器版本,用于在 '('id') 附近使用正确的语法

    当我尝试导入数据库时 出现此错误 您的 SQL 语法有错误 检查与您的 MySQL 服务器版本相对应的手册 了解在 id 附近使用的正确语法 第 4 行 TYPE MyISAM AUTO INCRMENT 6 DROP TABLE IF E
  • Haskell 中的随机数采样序列

    我需要小列表的高斯随机数进行模拟 所以我尝试了以下操作 import System Random seed 10101 gen mkStdGen seed boxMuller mu sigma r1 r2 mu sigma sqrt 2 l