在Matlab中获得满足线性方程的最佳答案的方法是什么?

3
我有一个一次方程:
vt = v1*x1 + v2*x2 + v3*x3

"vt,v1,v2,v3是取值在0到1之间的标量。生成一个满足上述方程并且满足条件的x1、x2和x3的最佳方法是什么?"
x1>0
x2>0
x3>0

我有几千套 vt、v1、v2 和 v3,因此我需要能够以编程方式生成 x1、x2 和 x3。

最快的方法是将 x1x2 设为已知,并解出 x3x1x2 可以由您设置,也可以随机生成。如果您随机生成它们,应确保 vt 小于 v1*x1 + v2*x2。您还可以使用 linprog 并将其转化为线性规划来解决。x1x2 是否相同有影响吗? - rayryeng
@rayryeng 这也是我的初步想法。我无法想到一种聪明的方法来随机生成x1和x2,并确保vt<v1x1 + v2x2(我知道我可以不断地随机生成x1和x2直到满足条件)。 - Cici
@rayryeng 另外,如果 x1 和 x2 是从某个分布(例如均匀分布)随机抽取的,则更好(在一定约束条件下随机抽取)。 - Cici
1
没问题。我们可以通过使用linprog来避免这个问题。我会为您编写一个答案。 - rayryeng
1个回答

3

您可以有两种方法来解决这个问题:

  1. 从您在帖子中设计的方法。随机生成x1x2,并确保vt < v1*x1 + v2*x2,然后继续解决x3
  2. 将其制定为线性规划。线性规划基本上是解决一组受不等式或等式约束的方程组。换句话说:

blah

因此,我们可以将您的问题转化为线性规划问题。"最大化"语句是所谓的目标函数 - 您试图实现的总体目标。在线性规划问题中,我们试图最小化或最大化这个目标。为了做到这一点,我们必须满足在"约束条件"中看到的不等式。通常,这个程序以"标准形式"表示,因此每个变量的约束条件应该是正的。
最大化条件可以是任意的,因为您不关心目标。您只关心任何解决方案。这整个范例可以通过MATLAB中的linprog实现。您需要注意的是如何指定linprog。实际上,目标被最小化而不是最大化。然而,除了确保所有变量都是正的之外,条件是相同的。我们将不得不自己编码。
在任意目标方面,我们可以简单地执行 x1 + x2 + x3。因此,c = [1 1 1]。我们的等式约束是:v1*x1 + v2*x2 + v3*x3 = vt。我们还必须确保x为正。为了编码这个问题,我们可以选择一个小常数,使得所有x值都大于这个值。目前,linprog不支持严格不等式(即x > 0),所以我们必须通过这种方法来规避这个问题。另外,为了确保值为正,linprog假设Ax <= b。因此,一个常用的技巧是否定x >= 0的不等式,因此这相当于-x <= 0。为了确保值非零,我们实际上会做:-x <= -eps,其中eps是一个小常数。然而,在我进行实验时,通过这种方式做,两个变量最终会成为同一个解。因此,我建议我们生成每次随机的好解决方案,让我们像你说的那样从均匀随机分布中抽取b。这将为我们提供每次解决这个问题的起点。
因此,我们的不等式为:
 -x1 <= -rand1
 -x2 <= -rand2
 -x3 <= -rand3

rand1, rand2, rand3是三个随机生成的数字,它们的取值范围在01之间。以矩阵形式表示:

 [-1 0 0][x1]      [-rand1]
 [0 -1 0][x2]  <=  [-rand2]
 [0 0 -1][x3]      [-rand3]

最后,我们之前的等式约束是:

[v1 v2 v3][x1]     [vt] 
          [x2]  = 
          [x3]

现在,要使用linprog,您需要执行以下操作:
X = linprog(c, A, b, Aeq, beq);

c 是一个系数数组,用于定义目标函数。在这种情况下,它将被定义为 [1 1 1]Ab 是不等式约束所定义的矩阵和列向量,Aeqbeq 是等式约束所定义的矩阵和列向量。因此,X 将在 linprog 收敛后给出解决方案(即 x1,x2,x3)。因此,您需要执行以下操作:

A = -eye(3,3);
b = -rand(3,1);
Aeq = [v1 v2 v3];
beq = vt;
c = [1 1 1];
X = linprog(c, A, b, Aeq, beq);

作为一个例子,假设 v1 = 0.33, v2 = 0.5, v3 = 0.2,以及 vt = 2.5。因此:
rng(123); %// Set seed for reproducibility
v1 = 0.33; v2 = 0.5; v3 = 0.2;
vt = 2.5;
A = -eye(3,3);
b = -rand(3,1);
Aeq = [v1 v2 v3];
beq = vt;
c = [1 1 1];
X = linprog(c, A, b, Aeq, beq);

我得到:
X =

0.6964
4.4495
0.2268

为了验证这是否等于vt,我们需要执行:

s = Aeq*X

s = 2.5000

上面的内容简单地计算了 v1*x1 + v2*x2 + v3*x3。 这是以点积形式计算的,以使事情变得容易,因为 X 是列向量,而 v1、v2、v3 已经在 Aeq 中设置为行向量。
因此,两种方法都可以,但至少使用 linprog,您不必一直循环直到满足条件!

小注意事项

在上述方法中我忘了提及的一个小注意事项是,您需要确保 vt >= v1*rand1 + v2*rand2 + v3*rand3 以确保收敛。由于您说 v1,v2,v3 介于 01 之间,最坏情况是当 v1,v2,v3 都等于 1 时。因此,我们确实需要确保 vt > rand1 + rand2 + rand3。如果这不是这种情况,则只需取每个 rand1, rand2, rand3 的值,并除以 (rand1 + rand2 + rand3) / vt。这将确保总和等于 vt(假设所有权重都为 1),并且这将使线性规划正确收敛。

如果不这样做,由于为b设置的不等式条件,解决方案将无法收敛,您将无法得到正确的答案。这只是一些思考的食物!因此,在运行linprog之前,请先对b执行此操作。
if sum(-b) > vt
   b = b ./ (sum(-b) / vt);
end

祝你好运!


谢谢你的回答!有一个问题,向量b是否对应于-eps?如果是这种情况,做类似b = -rand(3,1)*0.0001这样的事情是否有意义?@rayryeng - Cici
@Cici - 是的,这就是我在我的小提示中提到的。将rand乘以一个很小的数确保我们得到一个答案。除此之外,这应该会给你带来你想要的东西。 - rayryeng
现在我明白为什么 b = -rand(3,1)*0.0001 不是一个非常好的主意了!因为有时它会返回一个非常接近零的答案。 - Cici
@Cici - 这就是为什么你应该按照我在我的小注意事项中指定的比例进行缩放。这样,你就不会得到距离0太近的解决方案。 - rayryeng
感谢您的出色回答!我应该补充说,您的答案非常容易扩展到线性方程中具有N个变量的系统。超级棒!@rayryeng - Cici
@Cici - 非常欢迎!我对小细节进行了一些小的更正。我没有正确地进行除法。祝你好运! - rayryeng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接