2012-02-17 5 views
0

Я пытаюсь написать собственный код для алгоритма «друзей друзей». Этот алгоритм действует на множество трехмерных точек данных и возвращает количество «ореолов» в наборе данных. Каждое гало представляет собой набор точек, расстояние которых меньше длины связывания, b, единственный параметр программы.Алгоритм друзей друзей, написанный на Python, должен быть в Fortran 90/95

Алгоритмическое описание: Алгоритм FOF имеет единственный свободный параметр, называемый длиной связывания. Любые две частицы, которые разделены расстоянием, меньшим или равным длине связывания, называются «друзьями». Затем группа FOF определяется набором частиц, для которых каждая частица внутри множества связана с каждой другой частицей в множестве через сеть друзей.

Комплект группового счетчика FOF j = 1.

  • Для каждой частицы, п, еще не связана с любой группой:

  • Присвоить п к группе J, инициализировать новый список членов, mlist, для группы J с частицей п в качестве первой записи,

  • Рекурсивный, для каждой новой частицы р в mlist:

  • Найти соседей р, лежащих на расстоянии, меньшем или равном длине связующей, добавить к mlist, уже не отнесены к группе J,
  • Запись для группы j, набор j = j + 1.

Это моя попытка закодировать алгоритм. Единственным языком, который мне нравится в этом, является Python. Тем не менее, мне нужен этот код, который будет написан в Fortran или сделать его быстрее. Я действительно надеюсь, что кто-то мне поможет.

Сначала я генерировать множество точек, которые должны имитировать наличие 3 ореолов:

import random 
from random import * 
import math 
from math import * 
import numpy 
from numpy import * 
import time 

points = 1000 

halos=[0,100.,150.] 

x=[] 
y=[] 
z=[] 
id=[] 
for i in arange(0,points,1): 
    x.append(halos[0]+random()) 
    y.append(halos[0]+random()) 
    z.append(halos[0]+random()) 
    id.append(i) 

for i in arange(points,points*2,1): 
    x.append(halos[1]+random()) 
    y.append(halos[1]+random()) 
    z.append(halos[1]+random()) 
    id.append(i) 

for i in arange(points*2,points*3,1): 
    x.append(halos[2]+random()) 
    y.append(halos[2]+random()) 
    z.append(halos[2]+random()) 
    id.append(i) 

Тогда я кодированный алгоритм FoF:

x=array(x) 
    y=array(y) 
    z=array(z) 
    id=array(id) 

    t0 = time.time()       

    id_grp=[] 
    groups=zeros((len(x),1)).tolist() 
    particles=id 
    b=1 # linking length 
    while len(particles)>0: 
    index = particles[0] 
    # remove the particle from the particles list 
    particles.remove(index) 
    groups[index]=[index] 
    print "#N ", index 
    dx=x-x[index] 
    dy=y-y[index] 
    dz=z-z[index] 
    dr=sqrt(dx**2.+dy**2.+dz**2.) 
    id_to_look = where(dr<b)[0].tolist() 
    id_to_look.remove(index) 
    nlist = id_to_look 
    # remove all the neighbors from the particles list 
    for i in nlist: 
     if (i in particles): 
      particles.remove(i) 
    print "--> neighbors", nlist 
    groups[index]=groups[index]+nlist 
    new_nlist = nlist 
    while len(new_nlist)>0: 
      index_n = new_nlist[0] 
      new_nlist.remove(index_n) 
      print "----> neigh", index_n 
      dx=x-x[index_n] 
      dy=y-y[index_n] 
      dz=z-z[index_n] 
      dr=sqrt(dx**2.+dy**2.+dz**2.) 
      id_to_look = where(dr<b)[0].tolist() 
      id_to_look = list(set(id_to_look) & set(particles)) 
      nlist = id_to_look 
      if (len(nlist)==0): 
      print "No new neighbors found" 
      else: 
      groups[index]=groups[index]+nlist 
      new_nlist=new_nlist+nlist 
      print "------> neigh-neigh", new_nlist 
      for k in nlist: 
       particles.remove(k) 

В конце один заканчивает со списком гало в списке groups

Эта часть кода немного не в тему, но я подумал, что было бы неплохо показать ее вам. Я в основном удаляю все группы без частиц, сортируя их по количеству частиц и показывая некоторые свойства.

def select(test,list): 
    selected = [] 
    for item in list: 
    if test(item) == True: 
     selected.append(item) 
    return selected 

    groups=select(lambda x: sum(x)>0.,groups) 
    # sorting groups 
    groups.sort(lambda x,y: cmp(len(x),len(y))) 
    groups.reverse() 

    print time.time() - t0, "seconds" 

    mass=x 
    for i in arange(0,len(groups),1): 
    total_mass=sum([mass[j] for j in groups[i]]) 
    x_cm = sum([mass[j]*x[j] for j in groups[i]])/total_mass 
    y_cm = sum([mass[j]*y[j] for j in groups[i]])/total_mass 
    z_cm = sum([mass[j]*z[j] for j in groups[i]])/total_mass 
    dummy_x_cm = [x[j]-x_cm for j in groups[i]] 
    dummy_y_cm = [y[j]-y_cm for j in groups[i]] 
    dummy_z_cm = [z[j]-z_cm for j in groups[i]] 
    dummy_x_cm = array(dummy_x_cm) 
    dummy_y_cm = array(dummy_y_cm) 
    dummy_z_cm = array(dummy_z_cm) 
    dr = max(sqrt(dummy_x_cm**2.+dummy_y_cm**2.+dummy_z_cm**2.)) 
    dummy_x_cm = max(dummy_x_cm) 
    dummy_y_cm = max(dummy_y_cm) 
    dummy_z_cm = max(dummy_z_cm) 
    print i, len(groups[i]), x_cm, y_cm, z_cm,dummy_x_cm,dummy_y_cm,dummy_z_cm 
+1

Каковы параметры для решения? Нужно ли минимальное количество ореолов? –

+6

У вас есть проблема с алгоритмом или с его внедрением в код? Сначала получите алгоритм правильно, прежде чем пытаться его кодировать. – eriktous

+0

Я добавил описание алгоритма, вы можете мне помочь? – Brian

ответ

4

Я думаю, что вы бы опрометчиво начать обучение Fortran в надежде, что результирующий код будет быстрее, чем текущая реализация. В конце концов, может быть, но я думаю, вам будет лучше советовать сделать вашу реализацию Python так быстро, как вы можете, прежде чем думать о внедрении на другом языке, особенно на иностранном языке.

Я пишу Fortran, и лично я думаю, что его производительность писает по всему Python, но люди, которые знают об этих вещах, дают веские аргументы, которые Python + SciPy + Numpy может, если тщательно обработать, сопоставить Fortran для скорости в вычислительных ядрах многие научно-технические программы. Не забывайте, что вы не оптимизировали свой Python, пока все ядра на вашем компьютере не горят.

Итак:

первый - получить рабочую реализацию в Python.

2nd - сделайте свою реализацию как можно быстрее.

IF (заглавные буквы, потому что это большой «если»), код все еще не достаточно быстрый, и выгодность перевода его на скомпилированный язык благоприятна. THEN рассмотрите, какой скомпилированный язык перевести его на. Если вы находитесь в области, где Fortran широко используется, изучите Fortran всеми способами, но это что-то вроде нишевого языка, и это может принести пользу вашей карьере больше, чтобы изучить C++ или одного из его родственников.

EDIT (слишком долго, чтобы поместиться в поле комментария)

Почему ввести нас в заблуждение свой вопрос? Вы заявляете, что единственным удобным для вас языком является Python, теперь вы говорите, что знаете Fortran. Думаю, тебе должно быть неудобно. И, из вашего комментария, кажется, что, возможно, вам действительно нужна помощь в том, чтобы быстрее реализовать вашу реализацию Python; Sideshow Bob предложил несколько советов. Учитывайте это, затем параллельно.

+0

Хороший совет, хотя я бы не сказал, что вам нужно сначала перейти на многоядерный в python. Получите алгоритм, оптимизированный в python для одного ядра. Если у вас есть «n» ядра, то наибольшее ускорение, которое вы получите от многопоточности, - «2n» (с гиперпотоком, работающим на его теоретическом максимуме). Вы можете легко предсказать, будет ли это достаточно быстро для вас - если это не будет так, как говорит Марк, вы должны начать смотреть на Fortran или, чаще, на C++. –

+0

Спасибо за быстрый ответ. Дело в том, что (к сожалению) я знаю Fortran, но я не знаю, как сделать алгоритм FOF так же быстро, как тот, который я написал в Python. Мне было интересно, может ли кто-нибудь дать мне советы о том, как улучшить свой алгоритм. это оно. – Brian

0

Указатель на более эффективный алгоритм. Если я не ошибаюсь, вы сравниваете точку со всеми остальными точками, чтобы увидеть, насколько они ближе, чем длина связывания. Для большого количества точек быстрее найти близких соседей - пространственное индексирование и деревья KD с головы, но, несомненно, есть и другие методы, которые будут работать для вас.

+0

Спасибо за ответ, но можете ли вы поспорить больше или дать мне несколько ссылок? – Brian

+0

http://en.wikipedia.org/wiki/Kd-tree#Nearest_neighbour_search –

0

Если у вас есть современная видеокарта, вы можете парализовать сотни процессоров (в зависимости от вашей карты) в коде Python, используя PyOpenCL.

Вы можете исследовать, чтобы увидеть, если Algoritm FoF реализуется внутри этого voidfinder F90 code

Вы можете определить расстояние как квадрат расстояния, чтобы избежать использования SQRT() и использовать х * х вместо х ** 2 ...

 Смежные вопросы

  • Нет связанных вопросов^_^