Недавно я начал изучать Юлию, кодируя простую реализацию самоорганизующихся карт. Я хочу, чтобы размер и размеры карты указывались пользователем, а это значит, что я не могу использовать циклы для работы с массивами карт, потому что я не знаю заранее, сколько слоев циклов мне понадобится. Поэтому мне абсолютно необходимы функции широковещания и нарезки, которые работают на массивах произвольных измерений.Нарезка и трансляция многомерных массивов в Джулии: пример meshgrid
Прямо сейчас мне нужно построить массив индексов карты. Скажем, моя карта определена массивом размера mapsize = (5, 10, 15)
, мне нужно построить массив indices
размера (3, 5, 10, 15)
, где indices[:, a, b, c]
должен вернуть [a, b, c]
.
Я родом из фона Python/NumPy, в котором решение уже задается определенной «функции», MGRID:
indices = numpy.mgrid[:5, :10, :15]
print indices.shape # gives (3, 5, 10, 15)
print indices[:, 1, 2, 3] gives [1, 2, 3]
Я не ожидал, что Джулия иметь такую функцию на ГЭТ -go, поэтому я обратился к вещанию. В NumPy трансляция основана на наборе правил, которые я нахожу вполне ясными и логичными. Вы можете использовать массивы разных размеров в одном выражении, пока размеры в каждом матче измерения или один из него является 1:
(5, 10, 15) broadcasts to (5, 10, 15)
(10, 1)
(5, 1, 15) also broadcasts to (5, 10, 15)
(1, 10, 1)
Чтобы помочь с этим, вы можете также использовать numpy.newaxis или Нет, чтобы легко добавлять новые размеры в массив:
array = numpy.zeros((5, 15))
array[:,None,:] has shape (5, 1, 15)
Это помогает широковещательные массивы легко:
A = numpy.arange(5)
B = numpy.arange(10)
C = numpy.arange(15)
bA, bB, bC = numpy.broadcast_arrays(A[:,None,None], B[None,:,None], C[None,None,:])
bA.shape == bB.shape == bC.shape = (5, 10, 15)
Используя это, создавая indices
массив довольно straightfo rward:
indices = numpy.array(numpy.broadcast_arrays(A[:,None,None], B[None,:,None], C[None,None,:]))
(indices == numpy.mgrid[:5,:10,:15]).all() returns True
Общий случай, конечно, немного сложнее, но можно обойти, используя список понимание и ломтиков:
arrays = [ numpy.arange(i)[tuple([None if m!=n else slice(None) for m in range(len(mapsize))])] for n, i in enumerate(mapsize) ]
indices = numpy.array(numpy.broadcast_arrays(*arrays))
Итак, вернемся к Джулии. Я попытался применить такое же обоснование и в итоге получил эквивалент списка arrays
приведенного выше кода. Это закончилось тем, что было довольно проще, чем на партнерской благодаря NumPy выражению соединения синтаксиса:
arrays = [ (idx = ones(Int, length(mapsize)); idx[n] = i;reshape([1:i], tuple(idx...))) for (n,i)=enumerate(mapsize) ]
Теперь я застрял здесь, как я не знаю, как применить вещание в мой список генерации массивов здесь ... Функции broadcast[!]
требуют применения функции f, и у меня ее нет. Я попытался с помощью для цикла, чтобы попытаться заставить вещания:
indices = Array(Int, tuple(unshift!([i for i=mapsize], length(mapsize))...))
for i=1:length(mapsize)
A[i] = arrays[i]
end
Но это дает мне ошибку: ERROR: convert has no method matching convert(::Type{Int64}, ::Array{Int64,3})
я делаю это правильный путь? Упустил ли я что-то важное? Любая помощь приветствуется.
Удивительный! Я немного изменил код, чтобы получить результат одного тензора: 2-я строка: 'X = Array (Int, tuple (unshift! ([I для i = dims], length (dims)) ...))'; 8-я строка: 'X [d, cur_idx ...] = i' – Nathan