C++ 生成具有一定熵的随机数序列

C++ 生成具有一定熵的随机数序列,c++,random,entropy,C++,Random,Entropy,我需要生成部分随机的数字序列,这样序列整体上有一定的熵水平 例如,如果我将生成的数据馈送到gzip,它将能够对其进行压缩。事实上,这正是代码的应用,测试数据压缩器 我在C++中编程,第一个想法是用随机种子初始化STD::MT1937 PRNG,随机选择一个,并用它随机生成长模式。 std::mt19937每次使用相同的种子重置,以便它始终生成相同的模式: #include <iostream> #include <random> #include <vector&g

我需要生成部分随机的数字序列,这样序列整体上有一定的熵水平

例如,如果我将生成的数据馈送到gzip,它将能够对其进行压缩。事实上,这正是代码的应用,测试数据压缩器

我在C++中编程,第一个想法是用随机种子初始化STD::MT1937 PRNG,随机选择一个,并用它随机生成长模式。 std::mt19937每次使用相同的种子重置,以便它始终生成相同的模式:

#include <iostream>
#include <random>
#include <vector>

int main() {

    std::random_device rd;
    std::vector<std::mt19937> rngs;
    std::vector<int> seeds;

    std::uniform_int_distribution<int> patternrg(0,31);
    std::uniform_int_distribution<int> lenghtrg(1,64);
    std::uniform_int_distribution<int> valuerg(0,255);

    for(int i = 0; i < 32; ++i) {
        seeds.push_back(rd());
        rngs.emplace_back(seeds.back());
    }

    for(;;) {
        // Choose generator and pattern lenght randomly.
        auto gen = patternrg(rd);
        auto len = lenghtrg(rd);
        rngs[gen].seed(seeds[gen]);
        for(int i = 0; i < len; ++i) {
            std::cout << valuerg( rngs[gen] )<<"\n";
        }
    }
}
#包括
#包括
#包括
int main(){
std::随机_装置rd;
std::载体RNG;
std::载体种子;
标准:均匀分布模式rg(0,31);
标准:均匀分布长度(1,64);
标准:均匀分布值RG(0255);
对于(int i=0;i<32;++i){
种子。推回(rd());
rngs.emplace_back(seeds.back());
}
对于(;;){
//随机选择生成器和图案长度。
自动生成=模式RG(rd);
自动长度=长度(rd);
rngs[gen]。种子(种子[gen]);
对于(int i=0;istd::cout让我写几个你会发现有用的句子。假设我们想用给定的熵对一位进行采样。所以它是0或1,你想要的熵等于
e

H(10 | p)=-p log2(p)-(1-p)log2(1-p),其中
p
是得到1的概率。简单测试-在p=1/2的情况下,会得到1的熵-最大熵。所以 选择
e
等于1以下的某个值,求解方程

-log2(p)-(1-p)log2(1-p)=e

并返回P,然后可以开始使用简单的demo进行采样。C++中可以使用标准。 好的,假设你想用给定的熵对一个字节进行采样,它有256个值和熵

H(字节|\vec{p})=-Sum(1…256)pi log2(pi)

同样,如果所有的组合都是等概率的(pi=1/256),你会得到-256/256 log2(1/256)=8,这是最大熵。如果你现在固定你的熵(比如说,我希望它是7),那么pi的解将是无限多的,给定熵没有唯一的实现

你可以简化一个问题-让我们再来考虑一个参数的情况,发现概率< <代码> 1 >代码>是代码> p>代码>,找到代码< 0 >代码>的概率是(1-p)。因此,从256个结果我们现在得到了9个- 00000000, 0000000个1, 000000 11, 00000个111, 00001111,00011111, 00111111个,01111111, 11111111个。 对于每一种情况,我们都可以编写概率,计算熵,将其分配给您想要的任何对象,然后重新求解以找到

p

采样将相对容易-第一步是通过9个组合中的一个进行采样,第二步是使用

同样的方法也可以用于32位或64位——你有33或65个案例,构造熵,分配给你想要的任何东西,找到
p
,对其中一个进行采样,然后 在采样值内洗牌位

现在没有代码,但如果有兴趣的话,我可能以后会写一些代码

更新

请记住固定熵的另一个特殊性质。即使对于单个位的简单情况,如果您试图解决

-log2(p)-(1-p)log2(1-p)=e


对于给定的
e
,您将得到两个答案,并且很容易理解为什么-等式是对称的wrt
p
1-p
(或者用1s替换0s,用0s替换1s)换言之,对于熵而言,如果您主要使用0或1来传输信息,则与熵无关。对于自然文本之类的内容,则与熵无关。

您的构造的熵率(就输出字节值而言,而不是人类可读的字符而言)有一些复杂之处,但是(对于许多比256小得多的生成器)可以很好地近似地说,它是每个选择的熵(选择序列的5位加上其长度的6位)除以子序列的平均长度(65/2),或者每字节8位中的0.338位。(这明显低于正常的英文文本。)您可以通过定义更多序列减少从每个序列中提取的子序列的典型长度来增加熵率。(如果子序列通常只有一个字符,或者序列号为数百,则冲突必然会将熵率降低到低于此估计值,并将其限制为每字节8位。)


另一个易于调整的序列类涉及从[0,n]中绘制单个字节,每个字节的概率为pHow,或者以概率
p
重复上一个字节,或者以概率
随机(1-p)
有很多种具有给定熵率的随机序列。最简单和最通用的可能对压缩测试没有帮助;你想听听它们吗?是的,我很高兴听到这些。我给出的示例代码实际上相当不错,因为它生成随机子串,但我不知道如何控制我建议用真实的文件来测试它,而不是半随机的序列,这些序列与真实的文件没有一定的结构关系。感谢理论部分!我必须承认这个拉比特洞比我想象的要深得多!@JATothrim,不客气。看起来问题是定义熵是必要的条件,但不足以获得您想要的分布。