Создание неквадратной диагональной матрицы из вектора
У меня есть вектор, и я хотел бы, чтобы он повторялся n-раз вперед и n-назад, но по диагонали.
Например, у меня есть вектор: x= [0 0 1 1 0 0]
,
и хотел бы матрицу размером 6x5 следующим образом:
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1
Это означает, что вектор [0 0 1 1 0 0]
(транспонированный) находится посередине, и мне бы хотелось, чтобы матрица была такова, чтобы при перемещении влево элементы перемещались по кругу вверх при каждом сдвиге влево. Аналогично, при перемещении вправо элементы смещаются по кругу вниз к нижней части для каждого сдвига вправо. Поэтому второй столбец будет [0 1 1 0 0 0]
где элементы смещены влево по кругу один раз, тогда первый столбец будет [1 1 0 0 0 0]
где мы сдвигаем все элементы влево дважды по отношению к середине и один раз по отношению ко второму столбцу.
Точно так же четвертый столбец будет [0 0 0 1 1 0]
Это означает, что по отношению к среднему столбцу мы один раз сместим все элементы по кругу вправо, тогда последний столбец будет [0 0 0 0 1 1]
где мы сдвигаем все элементы вправо дважды по отношению к середине и один раз по отношению к четвертому столбцу.
2 ответа
Если вектор всегда состоит из ненулевой части в середине, вы можете использовать convmtx
(из панели инструментов обработки сигналов) следующим образом:
y = convmtx(nonzeros(x), numel(x)-1);
Или, если у вас нет набора инструментов для обработки сигналов, используйте conv2
:
y = conv2(eye(numel(x)-1), nonzeros(x)):
За x = [0 0 1 1 0 0]
любой из вышеперечисленных производит:
y =
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1
convmtx
требуется инструмент обработки сигналов для вычисления результата. Хотя ответ Луиса очень хороший, могу ли я предложить метод, не основанный на наборе инструментов?
n = 2;
ind = mod(bsxfun(@plus, (0:numel(x)-1).', n:-1:-n), numel(x)) + 1;
y = x(ind);
Или, если вы не хотите промежуточную переменную:
n = 2;
y = x(mod(bsxfun(@plus, (0:numel(x)-1).', n:-1:-n), numel(x)) + 1);
За x = [0 0 1 1 0 0];
, мы получаем:
y =
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1
Объяснение этого кода довольно простое. n
обозначает, сколько раз вы хотели бы "повторить" вектор x
влево и вправо, где каждый столбец циклически сдвигает элементы вверх или вниз в зависимости от того, в каком направлении в матрице вы движетесь.
Вторая строка кода является самой сложной. Давайте начнем с bsxfun(...)
вызов:
bsxfun(@plus, (0:numel(x)-1).', n:-1:-n))
Это создает numel(x) x (2*n + 1)
матрица, где каждый столбец просто вектор (0:numel(x)-1)
но к этому добавляется постоянная ценность. Начиная с первого столбца добавляем n
в (0:numel(x)-1)
тогда второй столбец добавим n-1
в (0:numel(x)-1)
пока мы не доберемся до середины, которая просто (0:numel(x)-1)
само собой. После того, как вы пройдете середину, мы затем вычтем вектор с константой, исходя из -1
для n+1
колонка, -2
для n+2
колонка до конца. Результат, который мы получаем за n = 2
является:
ans =
2 1 0 -1 -2
3 2 1 0 -1
4 3 2 1 0
5 4 3 2 1
6 5 4 3 2
7 6 5 4 3
В идеальном мире мы в основном использовали бы эту матрицу для индексации нашего вектора, чтобы получить именно ту матрицу, которая нам нужна. Столбцы слева от середины постепенно обращаются к элементам, определяя индексы, которые увеличиваются на 1, и в результате элементы сдвигаются к вершине матрицы. Аналогично, столбцы справа от средних элементов прогрессивного доступа путем указания индексов, которые задерживаются на 1, и в результате сдвигают элементы к нижней части матрицы.
К сожалению, у нас есть как отрицательные значения, так и значения, которые превышают длину вектора. Вдобавок к этому MATLAB начинает индексирование с 1. Следовательно, вам придется использовать некоторую циклическую логику, чтобы гарантировать, что когда мы превысим длину вектора или создадим отрицательные значения для индекса, мы должны вместо этого обернуться в 1 0 или длина вектора вместо -1. Таким образом, мы можем просто разместить mod
(модуль / остаток) операция, ограниченная общим количеством элементов в x
, затем после добавления 1 ко всей матрице, чтобы мы могли ограничить индексы между 1 и общим количеством элементов, которые теперь приводят нас к завершенной второй строке кода:
>> ind = mod(bsxfun(@plus, (0:numel(x)-1).', n:-1:-n), numel(x)) + 1
ind =
3 2 1 6 5
4 3 2 1 6
5 4 3 2 1
6 5 4 3 2
1 6 5 4 3
2 1 6 5 4
Последний шаг - просто использовать эту матрицу для индексации вашего вектора для достижения желаемой выходной матрицы:
>> y = x(ind)
y =
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1