[Редагувати: чарівність 4-го разу, нарешті щось розумне]
Я дійшов до цього зворотного шляху: я почав з іншої відповіді, що показує підхід, заснований на фільтрі, і використовував цю функцію для створення всіх допустимих комбінацій для ряду значень , і роздивився послідовність в онлайновій базі даних цілих послідовностей. Кількість комбінацій - , що виглядає малоймовірним (чому 3?). Це також де - трикутне число , . Отримавши це, ми повинні знати, чому.нн2( н2+ 3 )t ( t ( n ) ) + t ( t ( n - 1 ) )t ( a )аt ( a ) = a ( a + 1 ) / 2
Перший член простіший - пари пар, де і , де - трикутний індекс . Це виконується такою функцією:i ≥ jt i d( i , j ) ≥ t i d( k , l )t i d( а , б )а , б
def ascendings(n):
idx = 0
for i in range(1,n+1):
for j in range(1,i+1):
for k in range(1,i):
for l in range(1,k+1):
idx = idx + 1
print(i,j,k,l)
k=i
for l in range(1,j+1):
idx = idx + 1
print(i,j,k,l)
return idx
де друга петля є, тому що ми не можемо вкласти цикл повністю всередині циклу без if / пропустити, щоб перевірити трикутні показники.ллк
Другий додаток - це там, де перша пара зростає, а друга пара спадає (зверніть увагу, ні ==, як вони обробляються вище).t ( t ( n - 1 ) )
def mixcendings(n):
idx = 0
for j in range(2,n+1):
for i in range(1,j):
for k in range(1,j):
for l in range(1,k):
print(i,j,k,l)
idx = idx + 1
k=j
for l in range(1,i+1):
print(i,j,k,l)
idx = idx + 1
return idx
Поєднання обох цих даних дає повний набір, тому поєднання обох циклів дає нам повний набір індексів.
Суттєвою проблемою є те, що ці закономірності важко обчислити для довільних i, j, k, l. Тому я б запропонував карту, яка дає індекс, заданий i, j, k, l. Відверто кажучи, якщо ви це взагалі робите, ви можете також скористатися підходом "+ + фільтр", оскільки вам потрібно це зробити лише один раз для заданої . Плюсом вищевказаного методу є те, що у вас є принаймні передбачувана структура циклу.н
У python ми можемо написати наступний ітератор, щоб дати нам значення idx та i, j, k, l для кожного різного сценарію:
def iterate_quad(n):
idx = 0
for i in range(1,n+1):
for j in range(1,i+1):
for k in range(1,i):
for l in range(1,k+1):
idx = idx + 1
yield (idx,i,j,k,l)
#print(i,j,k,l)
k=i
for l in range(1,j+1):
idx = idx + 1
yield (idx,i,j,k,l)
for i in range(2,n+1):
for j in range(1,i):
for k in range(1,i):
for l in range(1,k):
idx = idx + 1
yield (idx,i,j,k,l)
k=i
for l in range(1,j+1):
idx = idx + 1
yield (idx,i,j,k,l)
У fortran нам просто доведеться запустити цикл і зберегти значення. Ми можемо використовувати простий індекс для зберігання комбінації i, j, k, l як єдине значення ( ) і зберігати ці значення в масиві, індекс якого такий же, як індекс вище. Потім ми можемо повторити цей масив і отримати значення i, j, k, l зі значень. Щоб отримати idx для довільних i, j, k, l, знадобиться зворотна карта та фільтр для обробки симетрії, хоча, можливо, ми могли б побудувати функцію з наведеної структури. Функцією генерації масиву idx у фортран буде:я н3+ j n2+ k n + l
integer function squareindex(i,j,k,l,n)
integer,intent(in)::i,j,k,l,n
squareindex = (((i-1)*n + (j-1))*n + (k-1))*n + l
end function
integer function generate_order_array(n,arr)
integer,intent(in)::n,arr(*)
integer::total,idx,i,j,k,l
total = n**2 * (n**2 + 3)
reshape(arr,total)
idx = 0
do i=1,n
do j=1,i
do k=1,i-1
do l=1,k
idx = idx+1
arr(idx) = squareindex(i,j,k,l,n)
end do
end do
k=i
do l=1,j
idx = idx+1
arr(idx) = squareindex(i,j,k,l,n)
end do
end do
end do
do i=2,n
do j=1,i-1
do k=1,i-1
do l=1,j
idx = idx+1
arr(idx) = squareindex(i,j,k,l,n)
end do
end do
k=i
do l=1,j
idx = idx+1
arr(idx) = squareindex(i,j,k,l,n)
end do
end do
end do
generate_order_array = idx
end function
А потім петлю на неї таким чином:
maxidx = generate_order_array(n,arr)
do idx=1,maxidx
i = idx/(n**3) + 1
t_idx = idx - (i-1)*n**3
j = t_idx/(n**2) + 1
t_idx = t_idx - (j-1)*n**2
k = t_idx/n + 1
t_idx = t_idx - (k-1)*n
l = t_idx
! now have i,j,k,l, so do stuff
! ...
end do