Лучший способ получить один ответ, который удовлетворяет линейному уравнению в 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 ответ
Есть два способа подойти к этому:
- Из метода, который вы разработали в своем посте. Произвольно генерировать
x1
а такжеx2
и убедитесь, чтоvt < v1*x1 + v2*x2
, а затем идти вперед и решить дляx3
, - Сформулируйте это в линейную программу. Линейная программа - это в основном решение системы уравнений, на которые распространяются ограничения неравенства или равенства. Другими словами:
Таким образом, мы можем перевести вашу проблему в задачу линейного программирования. Утверждение "максимизировать" - это то, что известно как целевая функция - общая цель того, чего вы пытаетесь достичь. В задачах линейного программирования мы стараемся свести к минимуму или максимизировать эту цель. Чтобы сделать это, мы должны удовлетворить неравенства, видимые в предмете к условию. Обычно эта программа представлена в канонической форме, поэтому ограничения на каждую переменную должны быть положительными.
Условие максимизации может быть произвольным, поскольку вы не заботитесь о цели. Вы просто заботитесь о любом решении. Вся эта парадигма может быть достигнута 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
Удачи!