提问人:woot 提问时间:10/14/2023 最后编辑:woot 更新时间:10/17/2023 访问量:65
根据距离生成具有给定平均乘积的数字的算法
algorithm to generate numbers which have a given average product based on distance
问:
我正在尝试提出一种算法,该算法根据距离生成具有给定平均乘积的数字。例如,假设 x 轴上有 4 个点,x1、x2、x3 和 x4。每个点都有一个位置和一个值。x1 的位置是 x=1,x2 的位置是 x=2,依此类推。所以这意味着 x1 和 x2 之间的距离是 1,而 x2 和 x4 之间的距离是 2,依此类推。
我正在寻找一种方法来生成 x 值,以便它们的平均乘积等于给定的数字。因此,对于每个距离,我们将有一个方程式
d=3:(1/2) * (n1*n4 + n4*n1) = 平均值1
d=2:(1/4) * (n1*n3 + n2*n4 + n3*n1 + n4*n2) = 平均值2
d=1:(1/6) * (n1*n2 + n2*n3 + n3*n4 + n2*n1 + n3*n2 + n4*n3) = 平均值3
d=0:(1/4) * (n1^2 + n2^2 + n3^2 + n4^2) = 平均值4
我尝试将平均值设置为小整数,然后设置 n1=1 并从那里开始。由此产生的代数给我留下了一个没有解的系统。我一直在使用点之间的距离矩阵来帮助可视化正在发生的事情。我假设一个人可以自由地选择x1,就像种子一样,然后尝试根据它推导出其他点。
答:
此操作的内部是非线性的。它可能更好地表示为二次规划 (QP) 问题,但由于 scipy 不直接支持这些问题,我用泛型 .minimize
最好预先计算一个三维因子矩阵,其中包含距离、第一个 n 指数和第二个 n 指数的维度;然后在优化过程中使用一个来简化为均值向量。然后可以从目标均值中减去这些均值,并应用自点积来获得最小二乘成本。einsum
import numpy as np
from scipy.optimize import minimize
N = 4
def make_factors() -> np.ndarray:
factors = np.empty((N, N, N))
for d in range(N):
if d == 0:
num = 1
else:
num = 0.5
diag = np.full(shape=N - d, fill_value=num/(N - d))
addend = np.diag(v=diag, k=d)
factors[d, ...] = addend
if d != 0:
factors[d, ...] += addend.T
return factors
def actual_mean(params: np.ndarray, factors: np.ndarray) -> np.ndarray:
# Equivalent to factors[i, ...] dot outer(params, params)
return np.einsum('ijk,j,k->i', factors, params, params)
def cost(params: np.ndarray, factors: np.ndarray, target_means: np.ndarray) -> float:
error = actual_mean(params, factors) - target_means
return error.dot(error)
def solve(factors: np.ndarray, target_means: np.ndarray) -> np.ndarray:
'''
d=1: 1/2(N-1) * (2(N-1)n^2) = mean1
n = sqrt(mean1) for x0
'''
x0 = np.full(shape=N, fill_value=np.sqrt(target_means[1]))
result = minimize(
fun=cost,
x0=x0,
args=(factors, target_means),
)
if not result.success:
raise ValueError(result.message)
return result.x
def main() -> None:
factors = make_factors()
target_means = np.array((3.4, 3.7, 3.3, 2.5))
fit = solve(factors, target_means)
print('n =', fit)
print(target_means, '~', actual_mean(fit, factors))
if __name__ == '__main__':
main()
n = [1.57903356 2.09332332 2.09332332 1.57903356]
[3.4 3.7 3.3 2.5] ~ [3.43767474 3.66428601 3.30542776 2.49334698]
评论