假设a
是我的n
元素数组。
约束:
假设对于给定的alpha和beta值,这样的数组总是可行的
这就是我的想法:
在alpha和beta之间随机分配值。找到数组元素的总和。 如果sum> 1,则用x减去所有元素,使得满足约束。如果和< 1,则用x添加所有元素,以满足约束。
但我发现很难找到新映射的值。
答案 0 :(得分:2)
如果fα×n≤1≤β×n,则可以满足。
你可以通过选择n个随机数来做到这一点。设r i 为i th 随机数,设R为随机数之和,S =(β-alpha)/(1-n×alpha)× R.设置[i] = alpha + r i / S *(beta - alpha)。只要S不小于最大随机数,则a
的所有元素都在alpha和beta之间,并且它们的总和为1.
#include <iostream>
#include <cassert>
#include <random>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
const double alpha = 0.05, beta = 0.15;
const int n = 10;
if (!(n * alpha <= 1.0 && 1.0 <= n * beta)) {
std::cout << "unable to satisfy costraints.\n";
return 0;
}
if (alpha == beta || std::fabs(1.0 - n * alpha) < 1e-6 || std::fabs(1.0 - n * beta) < 1e-6) {
std::cout << "Solution for alpha = " << alpha << ", beta = " << beta << " n = " << n << ":\n";
std::fill_n(std::ostream_iterator<double>(std::cout, " "), n, 1.0/n);
std::cout << "\nSum: 1.0\n";
return 0;
}
std::vector<int> r;
double S;
{
std::random_device rd;
std::seed_seq seed{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()};
std::mt19937 eng(seed);
std::uniform_int_distribution<> dist(0, 1000);
do {
r.clear();
std::generate_n(back_inserter(r), n, std::bind(dist, std::ref(eng)));
int sum = std::accumulate(begin(r), end(r), 0);
S = (beta - alpha) / (1 - n * alpha) * sum;
} while (S < *std::max_element(begin(r), end(r)));
}
std::vector<double> a(n);
std::transform(begin(r), end(r), begin(a), [&] (int ri) { return alpha + ri/S * (beta - alpha); });
for (double ai : a) {
assert(alpha <= ai && ai <= beta);
}
std::cout << "Solution for alpha = " << alpha << ", beta = " << beta << " n = " << n << ":\n";
std::copy(begin(a), end(a), std::ostream_iterator<double>(std::cout, " "));
std::cout << '\n';
std::cout << "Sum: " << std::accumulate(begin(a), end(a), 0.0) << '\n';
}
α= 0.05的解,β= 0.15,n = 10:
0.073923 0.117644 0.0834555 0.139368 0.101696 0.0846471 0.115261 0.0759395 0.0918882 0.116178
总和:1
你没有指定你希望算法提供的特定分布,但我想我会指出这个算法不一定能以相同的概率产生所有可能的解决方案;我相信有些解决方案比其他解决方案更容易产生。
答案 1 :(得分:2)
(正如我在评论中提到的,这里有一个隐藏的要求。如果我们查看数字范围,至少应该有一个元素<= (1/n)
,否则总和将是> 1
。所以我们必须强制alpha <= 1/n
。同样我们需要强制beta >= 1/n
。)
我们可以做到以下几点:
x_i = 0
允许i = 0
。[x_i, C]
中选择一个随机数。设为x_(i+1)
。我们将在下面描述这个常量C
。n-1
次以获得{x_1, x_2, ...., x_(n-1)}
。{(x_1 - x_0), ..., (1 - x_(n-1))}
为正数,总和为C
。这些是{y_1, y_2, ..., y_n}
。k_i = alpha + y_i * (beta - alpha)
。由于y_i
位于(0, C)
,k_i
如果alpha
,beta
也会介于C <= 1
和k_i
之间。n * alpha + (beta - alpha) * (sum of y_i)
的总和为n * alpha + (beta - alpha) * C
。这与1
相同。这应该等于C
。解决C = (1 - n * alpha) / (beta - alpha)
,我们得到alpha = 0.4
。
说明:
如果beta = 1
,n = 2
,C = (1 - 0.8) / 0.6 = 1/3
,我们会:
x_i
{1/8}
的随机值是:(n-1) = 1
(因为我们只关心y_i = {1/8, (1/3 - 1/8)} = {1/8, 5/24}
)
beta - alpha = 0.6
k_i = {0.4 + 0.6/8, 0.4 + 3/24} = {0.475, 0.525}
{0.475 and 0.525}
因此,所需数组为1
,其总和为C < 1
。
这里的基本假设是C < 1
。我认为我们可能能够证明(0, C)
是对问题可行性的强烈要求,但现在为时已经来不及证明这一点。
请注意,上面会产生一致的随机数,因为数字x_i是在{{1}}范围内随机选择的。
答案 2 :(得分:1)
我意识到问题本身并不是很简单,但我发现一个简单的算法,我认为(尚未证明)将在所有可能的值上生成均匀分布。我想这个算法必定已经被某些人考虑过了,因为它非常简单,但我还没有尝试过寻找这种算法的分析。算法如下:
代码:
# -*- coding: utf-8 -*-
"""
To produce an array of random numbers between alpha and beta, which sums to 1
Assumption: there is always a solution for the given constraint.
"""
# Import statements
import random
import sys
def shuffle(arr):
result = []
while len(arr) > 0:
idx = random.randint(0, len(arr)-1)
result.append(arr[idx])
del(arr[idx])
return result
def main():
if len(sys.argv) < 4:
print('Usage: random_constrained.py <n> <alpha> <beta>\nWhere:\n\tn is an integer\n\t0 <= alpha <= beta <= 1')
sys.exit(0)
n = int(sys.argv[1])
alpha = float(sys.argv[2])
beta = float(sys.argv[3])
result = []
total = 0
for i in range(n):
low = max(alpha, 1-total-((n-i-1)*beta))
high = min(beta, 1-total-((n-i-1)*alpha))
if high < low - 1e-10:
print('Error: constraint not satisfiable (high={:.3f}, low={:.3f})'.format(high, low))
sys.exit(1)
num = random.uniform(low, high)
result.append(num)
total += num
result = shuffle(result)
print(result)
if __name__ == '__main__':
main()
示例输出:
$ python random_constrained.py 4 0 0.5 [0.06852504971359885, 0.39391285249108765, 0.24215492185626314, 0.2954071759390503] $ python random_constrained.py 4 0 0.5 [0.2519926400714304, 0.4138640296394964, 0.27906367876610466, 0.055079651522968565] $ python random_constrained.py 4 0 0.5 [0.11505150404455633, 0.16665881845206237, 0.45371668123772924, 0.264572996265652] $ python random_constrained.py 4 0 0.5 [0.31689744182294444, 0.11233051635974067, 0.3599600067081529, 0.21081203510916197] $ python random_constrained.py 4 0 0.5 [0.16158825078700828, 0.18989326608974527, 0.1782112102703714, 0.470307272852875] $ python random_constrained.py 5 0 0.2 [0.19999999999999998, 0.2, 0.19999999999999996, 0.19999999999999996, 0.20000000000000004] $ python random_constrained.py 5 0 0.2 [0.2, 0.2, 0.19999999999999998, 0.2, 0.19999999999999996] $ python random_constrained.py 5 0 0.2 [0.20000000000000004, 0.19999999999999998, 0.19999999999999996, 0.19999999999999998, 0.2] $ python random_constrained.py 5 0 0.2 [0.2, 0.20000000000000004, 0.19999999999999996, 0.19999999999999996, 0.19999999999999996] $ python random_constrained.py 2 0.4 1 [0.5254259945319483, 0.47457400546805173] $ python random_constrained.py 2 0.4 1 [0.5071103628251259, 0.4928896371748741] $ python random_constrained.py 2 0.4 1 [0.4595236988530377, 0.5404763011469623] $ python random_constrained.py 2 0.4 1 [0.44218002983240046, 0.5578199701675995] $ python random_constrained.py 2 0.4 1 [0.4330169754142243, 0.5669830245857757] $ python random_constrained.py 2 0.4 1 [0.543183373724851, 0.45681662627514896]
我还不确定如何处理那里的精度错误。
我运行了一些测试以检查n=2
的情况下的一致性,生成100000个数组(使用alpha=0.4, beta=0.6
)并将值从alpha到beta的10个相同大小的桶中获取,计算出现的次数:
First number: [9998, 9966, 9938, 9952, 10038, 10161, 9899, 10007, 10054, 9987] Second number: [9987, 10054, 10007, 9899, 10161, 10038, 9952, 9938, 9966, 9998]
对于n=4, alpha=0, beta=0.3
,10000次尝试:
[0, 0, 0, 304, 430, 569, 730, 1135, 1874, 4958] [0, 0, 0, 285, 492, 576, 805, 1113, 1775, 4954] [0, 0, 0, 248, 465, 578, 769, 1077, 1839, 5024] [0, 0, 0, 252, 474, 564, 800, 1100, 1808, 5002]
我们可以看到每个数字的分布大致相同,因此对任何位置都没有偏见。