Лучший способ получить один ответ, который удовлетворяет линейному уравнению в Matlab

У меня есть линейное уравнение:

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 программно.

1 ответ

Решение

Есть два способа подойти к этому:

  1. Из метода, который вы разработали в своем посте. Произвольно генерировать x1 а также x2 и убедитесь, что vt < v1*x1 + v2*x2, а затем идти вперед и решить для x3,
  2. Сформулируйте это в линейную программу. Линейная программа - это в основном решение системы уравнений, на которые распространяются ограничения неравенства или равенства. Другими словами:

вздор

Таким образом, мы можем перевести вашу проблему в задачу линейного программирования. Утверждение "максимизировать" - это то, что известно как целевая функция - общая цель того, чего вы пытаетесь достичь. В задачах линейного программирования мы стараемся свести к минимуму или максимизировать эту цель. Чтобы сделать это, мы должны удовлетворить неравенства, видимые в предмете к условию. Обычно эта программа представлена ​​в канонической форме, поэтому ограничения на каждую переменную должны быть положительными.

Условие максимизации может быть произвольным, поскольку вы не заботитесь о цели. Вы просто заботитесь о любом решении. Вся эта парадигма может быть достигнута linprog в MATLAB. То, что вы должны быть осторожны, это как 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 три случайно сгенерированных числа, которые находятся между 0 а также 1, В матричной форме это:

 [-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], A а также b матрица и вектор столбца, определенные для ограничений неравенства и Aeq а также beq матрица и вектор столбца, определенные для ограничений равенства. 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 ограничены между 0 а также 1 в худшем случае v1,v2,v3 все равны 1. Таким образом, мы действительно должны убедиться, что vt > rand1 + rand2 + rand3, Если это не так, то просто возьмите каждое значение rand1, rand2, rand3 и разделить на (rand1 + rand2 + rand3) / vt, Таким образом, это гарантирует, что общее суммирование будет равно vt при условии, что все веса равны 1, и это позволит линейной программе правильно сходиться.

Если вы этого не сделаете, то решение не будет сходиться из-за условий неравенства для b и вы не получите правильный ответ. Просто пища для размышлений! Таким образом, сделать это для b прежде чем бежать linprog

if sum(-b) > vt
   b = b ./ (sum(-b) / vt);
end

Удачи!

Другие вопросы по тегам