лучший способ получить один ответ, который удовлетворяет линейному уравнению в 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.


person Cici    schedule 16.07.2014    source источник
comment
Самый быстрый способ — установить известные x1 и x2 и найти x3. x1 и x2 могут быть установлены вами или сгенерированы случайным образом. Если вы генерируете их случайным образом, вы должны убедиться, что vt меньше v1*x1 + v2*x2. Вы также можете использовать linprog и превратить это в линейную программу и решить для нее. Имеет ли значение, если x1 и x2 совпадают?   -  person rayryeng    schedule 16.07.2014
comment
@rayryeng Это была и моя первоначальная мысль. Я не могу придумать какой-нибудь умный способ случайным образом генерировать x1 и x2 и гарантировать, что vt‹v1*x1 + v2*x2 (я знаю, что могу продолжать генерировать x1 и x2 случайным образом, пока условие не будет выполнено).   -  person Cici    schedule 16.07.2014
comment
@rayryeng также предпочтительно, если x1 и x2 взяты из некоторого распределения (например, равномерного распределения) случайным образом (случайно с некоторым ограничением).   -  person Cici    schedule 16.07.2014
comment
Все нормально. Мы можем избежать всего этого вместе, используя linprog. Я напишу вам ответ.   -  person rayryeng    schedule 16.07.2014


Ответы (1)


Есть два способа приблизиться к этому:

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

blah

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

Условие максимизации может быть произвольным, поскольку вас не волнует цель. Вы просто заботитесь о любом решении. Вся эта парадигма может быть достигнута с помощью 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

Удачи!

person rayryeng    schedule 16.07.2014
comment
Спасибо за ответ! Один вопрос, так соответствует ли вектор b -eps? в этом случае имеет смысл сделать что-то вроде b = -rand(3,1)*0,0001? @rayryeng - person Cici; 16.07.2014
comment
@Cici - Да, это то, что я отметил в своем маленьком предостережении. Умножьте rand на что-то маленькое, чтобы убедиться, что мы получили ответ. Кроме этого, мы надеемся, что это даст вам то, что вы ищете. - person rayryeng; 16.07.2014
comment
теперь я понимаю, почему b = -rand(3,1)*0,0001 — не очень хорошая идея! поскольку иногда он просто возвращает ответ, который слишком близок к нулю. - person Cici; 16.07.2014
comment
@Cici - вот почему вы должны масштабировать его в соответствии с тем, что я указал в своем маленьком предостережении. Таким образом, вы не получите решения, близкие к 0. - person rayryeng; 16.07.2014
comment
Спасибо за отличный ответ! Я должен добавить, что ваш ответ очень легко распространить на систему, имеющую N переменных в линейном уравнении. супер классный! @rayryeng - person Cici; 16.07.2014
comment
@Cici - Добро пожаловать! Я сделал небольшую поправку к Маленькой оговорке. Я не правильно разделил. Удачи! - person rayryeng; 16.07.2014