Python - необычное вещание для загадки особого случая

1

Я хочу сделать некоторые вычисления сил между вершинами, и поскольку силы симметричны, у меня есть список пар вершин, которым нужны эти силы. Я уверен, что это возможно с фантастическим индексированием, но я действительно могу заставить его работать с медленным питоном for-loop. по симметричным соображениям, правая часть массива индекса нуждается в отрицательном знаке при добавлении сил.

предположим, что у вас есть индексный массив вершин:

>>> I = np.array([[0,1],[1,2],[2,0]])
I = [[0 1]
     [1 2]
     [2 0]]

и массив x, y для каждой пары:

>>> F = np.array([[3,6],[4,7],[5,8]])
F = [[3 6]
     [4 7]
     [5 8]]

желаемая операция может быть описана как:

"vertice #0 sums the force vectors (3,6) and (-5,-8),
 vertice #1 sums the force vectors (-3,-6) and (4,7),
 vertice #2 sums the force vectors (-4,-7) and (5,8)"

Желаемые результаты:

     [ 3  6 ]   [ 0  0 ]   [-5 -8 ]   [-2 -2 ] //resulting force Vertice #0
A =  [-3 -6 ] + [ 4  7 ] + [ 0  0 ] = [ 1  1 ] //resulting force Vertice #1
     [ 0  0 ]   [-4 -7 ]   [ 5  8 ]   [ 1  1 ] //resulting force Vertice #2

редактировать:

мое уродливое решение для циклы:

import numpy as np

I = np.array([[0,1],[1,2],[2,0]])
F = np.array([[3,6],[4,7],[5,8]])
A = np.zeros((3,2))

A_x = np.zeros((3,2))
A_y = np.zeros((3,2))

for row in range(0,len(F)):


    A_x[I[row][0],0]= F[row][0]
    A_x[I[row][1],1]= -F[row][0] 

    A_y[I[row][0],0]= F[row][1]
    A_y[I[row][1],1]= -F[row][1] 


A = np.hstack((np.sum(A_x,axis=1).reshape((3,1)),np.sum(A_y,axis=1).reshape((3,1)))) 

print(A)

A=  [[-2. -2.]
     [ 1.  1.]
     [ 1.  1.]]
Теги:
arrays
numpy
indexing

3 ответа

0
Лучший ответ

Вы можете предварительно выделить массив для хранения перетасованных сил, а затем использовать индекс так:

>>> N = I.max() + 1
>>> out = np.zeros((N, 2, 2), F.dtype)
>>> out[I, [1, 0]] = F[:, None, :]
>>> np.diff(out, axis=1).squeeze()
array([[-2, -2],
       [ 1,  1],
       [ 1,  1]])

или, что то же самое,

>>> out = np.zeros((2, N, 2), F.dtype)
>>> out[[[1], [0]], I.T] = F
>>> np.diff(out, axis=0).squeeze()
array([[-2, -2],
       [ 1,  1],
       [ 1,  1]])
  • 0
    Фантастическая космическая магия +1! Мне нужно некоторое время, чтобы полностью понять этот ответ. В моем случае с реальным миром я борюсь с возможностью иметь 2 силы, действующие на 3 вершины. Массивы не обязательно имеют одинаковую длину.
  • 0
    @JPK. Я немного адаптировал ответ, чтобы быть более гибким. Теперь должна быть возможность обработать случай, когда число сил не равно числу вершин.
Показать ещё 1 комментарий
1

Ваша текущая интерпретация I "push-style"

Для индекса строки k в I возьмем силы из F[k] и добавим/вычитаем их out[I[k], :]

I = np.array([[0,1],[1,2],[2,0]])
out = numpy.zeros_like(F)
for k, d in enumerate(I):
    out[d[0], :] += F[k]
    out[d[1], :] -= F[k]
out
# array([[-2, -2],
#        [ 1,  1],
#        [ 1,  1]])

Однако вы также можете изменить значение I на голове и сделать его "pull-style", поэтому он говорит

Для индекса строки k в I задайте вершину out[k] как разность F[I[k]]

I = np.array([[0,2],[1,0],[2,1]])
out = numpy.zeros_like(F)
for k, d in enumerate(I):
    out[k, :] = F[d[0], :] - F[d[1], :]
out
# array([[-2, -2],
#        [ 1,  1],
#        [ 1,  1]])

В этом случае операция просто упрощает простое причудливое индексирование:

out = F[I[:, 0], :] - F[I[:, 1], :]
# array([[-2, -2],
#        [ 1,  1],
#        [ 1,  1]])
  • 0
    Отличное решение! Очень нравится. +1
  • 0
    Не отвечает на вопрос, хотя. (Порядок элементов I в OP не является «неправильным».)
Показать ещё 4 комментария
0

То, как я понимаю вопрос, значения в массиве I представляют число вихрей или имя вихря. Они не являются фактическим позиционным индексом. Основываясь на этой мысли, у меня есть другое решение, которое использует исходный массив I Это не совсем получается без циклов, но должно быть хорошо для разумного количества вершин:

I = np.array([[0,1],[1,2],[2,0]])   
F = np.array([[3,6],[4,7],[5,8]])

pos = I[:, 0]
neg = I[:, 1]
A = np.zeros_like(F)

unique = np.unique(I)
for i, vortex_number in enumerate(unique):
    A[i] = F[np.where(pos==vortex_number)] - F[np.where(neg==vortex_number)]

# produces the expected result
# [[-2 -2]
#  [ 1  1]
#  [ 1  1]]

Возможно, этот цикл также может быть заменен некоторой маской numpy.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню