(изменено: Александр Ривилис, 8 ноября 2010г. 11:52:21)

Re: Можно ли ускорить выполнение программы VBA

Есть еще один вариант для ускорения обработки. Заводишь два (одинаковых) массива точек M1 и M2. Сортируешь первый по X, второй по Y. Поиск в таком массиве на порядок быстрее чем при линейном поиске если, например, использовать метод половинного деления. Пусть тебе нужно найти все точки, находящиеся на расстоянии не больше R от заданной точки p. Находишь индекс точки I1 в массиве M1 и I2 в массиве M2. Затем увеличивая и уменьшая индексы на единицу находишь те точки, которые по X и Y отличаются от точки P не больше чем на R. После этого отбираешь из выбранных те, которые в пределах окружности с центром в P и радиусом R. Последние две операции можно совместить. Если R значительно меньше чем размеры прямоугольника, охватывающие массив M точек, то скорость поиска будет значительно выше.

Re: Можно ли ускорить выполнение программы VBA

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

(изменено: Дмитрий Привалов, 9 ноября 2010г. 11:47:57)

Re: Можно ли ускорить выполнение программы VBA

Этот вариант должен значительно ускорить поиск информации в массиве.

Кто применял этот метод, поделитесь пожалуйста опытом.
...вызывает некоторые сомнения необходимость сортировки массивов. Сортировка сама по себе процедура длительная. Не перекроет ли время на сортировку массивов выгоду по ускорению дальнейшей выборки для данной задачи 25000*200?
с какого количества выборок рационально его применять?(200*200.....5000*5000....)

Re: Можно ли ускорить выполнение программы VBA

Дмитрий Привалов пишет:

Кто применял этот метод, поделитесь пожалуйста опытом.

Применял, но не для данного случая и в C++ и использовал стандартную сортировку из библиотеки C++.

Дмитрий Привалов пишет:

Не перекроет ли время на сортировку массивов выгоду по ускорению дальнейшей выборки для данной задачи 25000*200?

Нет. Не перекроет. В моем варианте было порядка 15000 строк.

Дмитрий Привалов пишет:

с какого количества выборок рационально его применять?(200*200.....5000*5000....)

Нужно проверять.

Re: Можно ли ускорить выполнение программы VBA

Теперь Владимиру не придется скучать...кучу всего переделывать))))
....оптимальный алгоритм и для него придется перейти к выборки во внутреннем массиве языка, а не связыванию через COM 200*25000 циклов .....даже на NET/ObjectARX наверно не будет смысла переделывать и так ускорится))))
...не терпится узнать % ускорения)))

(изменено: Александр Ривилис, 9 ноября 2010г. 14:56:19)

Re: Можно ли ускорить выполнение программы VBA

Я только что проверил у себя на тестовом массиве из 15000 точек (почти реальная съемка). Время двойной (отдельно по X и отдельно по Y) сортировки - 15 миллисекунд. Полный алгоритм (на C++) получения для каждой из точек соседних точек (R = 200 метров) сработал за 30 секунд. Это я еще не занимался дополнительными оптимизациями. В моем примере максимальное количество "соседей" было 1200.

(изменено: Владимир Линейцев, 10 ноября 2010г. 19:35:40)

Re: Можно ли ускорить выполнение программы VBA

Дмитрий Привалов пишет:

...вызывает некоторые сомнения необходимость сортировки массивов.


У меня для этого есть процедура быстрого алгоритма сортировки. Время не засекал, но очень быстро. Она написана для линейного массива и ей наверное лет 20. Она ко мне случайно попала из примеров Бейсика или Turbo Basic. На VBA она лего прижилась, на FoxPro тоже, а вот к дельфи я не смог ее адаптировать, а хотелось бы. Пытался разобраться с ее алгоритмом, но ничего не понял. Работает как есть!

Re: Можно ли ускорить выполнение программы VBA

Александр Ривилис пишет:

Полный алгоритм (на C++) получения для каждой из точек соседних точек (R = 200 метров) сработал за 30 секунд.

По вот этому алгоритму?

Александр Ривилис пишет:

Есть еще один вариант для ускорения обработки. Заводишь два (одинаковых) массива точек M1 и M2. Сортируешь первый по X, второй по Y. Поиск в таком массиве на порядок быстрее чем при линейном поиске если, например, использовать метод половинного деления. Пусть тебе нужно найти все точки, находящиеся на расстоянии не больше R от заданной точки p. Находишь индекс точки I1 в массиве M1 и I2 в массиве M2. Затем увеличивая и уменьшая индексы на единицу находишь те точки, которые по X и Y отличаются от точки P не больше чем на R. После этого отбираешь из выбранных те, которые в пределах окружности с центром в P и радиусом R. Последние две операции можно совместить. Если R значительно меньше чем размеры прямоугольника, охватывающие массив M точек, то скорость поиска будет значительно выше.

(изменено: Александр Ривилис, 10 ноября 2010г. 21:09:54)

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

По вот этому алгоритму?

Именно по этому. Возможно чуть видоизмененный. Если нужно - выложу завтра кусочек кода на C++.

Re: Можно ли ускорить выполнение программы VBA

Const NN As Integer = 28224
Const R As Double = 100

Public Type Coord
    X As Integer
    Y As Integer
End Type

Dim VarCoord As Coord
Dim PointArray(NN) As Coord
'--------------------------------------

    
 Sub ArrayProcessing()
    Dim j As Long
    Dim NearestPoint As Integer
            
    j = 1
    For i = 1 To NN - 1
        NearestPoint = 0
        For j = 1 To NN - 1
            If (PointArray(i).X - PointArray(j).X) < R Then
            'check Y
                If (PointArray(i).Y - PointArray(j).Y) < R Then
                'check R
                    If ((PointArray(i).X - PointArray(j).X) ^ 2 + (PointArray(i).Y - PointArray(j).Y) ^ 2) ^ 0.5 < R Then
                       'Call Write_to_file(PointArray(i), PointArray(j))
                        NearestPoint = NearestPoint + 1
                    End If
                End If
            End If
        Next j
    Next i

Вот простенький код, который обрабатывает массив в 28 тыс. точек за 2.6 мин.
Файл VB.exe, компилятор оптимизирован по быстродействию. Среднее кол-во "соседних" точек - 175.

CPU 2.8GHz
RAM 2.0GB

Разумеется, массив получен не путем извлечения данных о точках из файла AutoCAD, а на стадии:

Владимир Линейцев пишет:

1. предварительно прочитан объем данных в массив - набор точек NomerPoint,X,Y,H,kod

Вывод таков, если на практике автора программы устраивает такое время ее работы, то может быть и не стоит особо лезть в дебри.

И еще. Этот пример абстрактный и не зависит от распределения точек в пространстве. Однако, если известно что объект линейный и облако точек растянуто, например, по оси X, то стоит первый цикл проводить именно по этой оси (как в примере). Это позволит отсеять бОльшую часть точек на первом проходе.

Re: Можно ли ускорить выполнение программы VBA

LeonidSN,
Можно как минимум в два раза сократить время вычисления, если записать заголовок второго цикла так:

For j = i + 1 To NN - 1 

В этом случае не будет делаться сравнение точки с самой собой и не будет делаться повторное сравнение точек (сначала PointArray(i) с PointArray(j), а затем PointArray(j) с PointArray(i))

(изменено: SmeL, 12 ноября 2010г. 18:48:25)

Re: Можно ли ускорить выполнение программы VBA

Вот вариант зависит от того как часто вам эти операции необходимы.
Суть такова отдать все ваши данные базе к примеру бесплатной postgresql. Как то был опыт в картографии, и вопросы типо сколько домов находится вдоль реки в радиусе к примеру 1км, решались одним запросом. Если заинтересовало ищите postgres GIS http://postgis.refractions.net/

Re: Можно ли ускорить выполнение программы VBA

Александр Ривилис,
оптимизировал цикл, спасибо за подсказку. Число операций с числами сократилось в два раза, а время выполнения - на 17%. Почему имеет место такая нелинейная зависимость, так и не понял.

(изменено: Дмитрий Привалов, 13 ноября 2010г. 12:35:38)

Re: Можно ли ускорить выполнение программы VBA

оптимизировал цикл, спасибо за подсказку. Число операций с числами сократилось в два раза, а время выполнения - на 17%. Почему имеет место такая нелинейная зависимость, так и не понял.

Маловато ускорилось!
...нелинейная...значит у тебя медленной операцией является не только расчет, и выборки данных.
Прочитай статьи типа "оптимизации программ на VBA", просмотри еще весь цикл обработки начиная с FOR и все что внутри.
Установи таймеры, комментируй строки с расчетами, выборкой, связями с Автокадом и т.д. ищи медленный код!
Посмотри нет ли во время выполнения циклов медленных операций, типа выведения текста в textbox :?:

...найдешь участки медленного кода...можешь выложить сюда или в соответствующих темах по оптимизации кода VBA

Re: Можно ли ускорить выполнение программы VBA

Дмитрий Привалов пишет:

Маловато ускорилось!

Трудно не согласиться.

Статьи почитываем, спасибо.

Собственно говоря, код настолько невелик и прозрачен, что выкладываю его вместе с результатами теста:

Const NN As Integer = 28224
Const R As Double = 100

Public Type Coord
    X As Integer
    Y As Integer
End Type

Dim VarCoord As Coord
Dim PointArray(1 To NN) As Coord

'-------------------------------------------

 
    
 Sub ArrayProcessing()
    Dim j As Integer
    Dim nLoop1 As Long
    Dim nLoop2 As Long
    
    
        Dim startTime As Date
        Dim endTime As Date
                
        startTime = Timer
                
    
    For i = 1 To NN
       'For j = i To NN 'version 1
       For j = i + 1 To NN 'version 2
            If (PointArray(i).X - PointArray(j).X) < R Then
            'check Y
                If (PointArray(i).Y - PointArray(j).Y) < R Then
                'check R
                    If (((PointArray(i).X - PointArray(j).X) ^ 2 + (PointArray(i).Y - PointArray(j).Y) ^ 2) ^ 0.5) < R Then
                       'Call Write_to_file(PointArray(i), PointArray(j))
                      nLoop2 = nLoop2 + 1
                    End If
                End If
            End If
            nLoop1 = nLoop1 + 1
        Next j
    Next i
        
     endTime = Timer
     MsgBox (endTime - startTime) & " sec"
     MsgBox "Loop1 = " & nLoop1
     MsgBox "Loop2 = " & nLoop2
End Sub

version 1:
Time - 169.56 sec
nLoop1 = 796 594 176
nLoop2 = 31 679 452

version 2:
Time - 140.53 sec
nLoop1 = 398 282 976
nLoop2 = 15 825 614

Re: Можно ли ускорить выполнение программы VBA

1. посмотри, есть ли на VBA, как и в c++,c#  ++nLoop1, вместо nLoop1 = nLoop1 + 1
2. Попробуй:
deltaX=PointArray(i).X - PointArray(j).X
If deltaX < R Then
            'check Y
              deltaY=PointArray(i).Y - PointArray(j).Y   
                If deltaY < R Then
                'check R
                    If (deltax*deltax+ deltaY*deltaY) < R*R Then
                       'Call Write_to_file(PointArray(i), PointArray(j))
                      nLoop2 = nLoop2 + 1
                    End If
                End If
            End If
            nLoop1 = nLoop1 + 1

(изменено: Александр Ривилис, 13 ноября 2010г. 19:30:08)

Re: Можно ли ускорить выполнение программы VBA

Дмитрий Привалов пишет:

1. посмотри, есть ли на VBA, как и в c++,c# ++nLoop1, вместо nLoop1 = nLoop1 + 1

Нет. В VBA нет операторов ++ и --. А вот остальное вполне логично. Особенно отказ от использования квадратного корня.
LeonidSN
Ты не использовал сортировку и двоичный поиск. На моем примере их использование дало выигрыш в 8 раз.

Re: Можно ли ускорить выполнение программы VBA

Александр Ривилис,
на мой взляд поиск оптимального решения закончился постом от 01.11.2010 11:47:59 по достижении времени обработки массива - 30 сек. Свой вариант привел исключительно для демонстрации, того как можно ОЧЕНЬ ПРОСТЫМИ средствами достичь ВПОЛНЕ ПРИЕМЛЕМЫХ результатов. И эти варианты не конкурируют.

Re: Можно ли ускорить выполнение программы VBA

Согласен.

Re: Можно ли ускорить выполнение программы VBA

LeonidSN
....в итоге при 25 тысяч точек с 30 минут задача за сколько стала выполняться?

Re: Можно ли ускорить выполнение программы VBA

LeonidSN пишет:

LeonidSN,
Можно как минимум в два раза сократить время вычисления, если записать заголовок второго цикла так:
Можно как минимум в два раза сократить время вычисления, если записать заголовок второго цикла так:
Код
For j = i + 1 To NN - 1
For j = i + 1 To NN - 1

В этом случае не будет делаться сравнение точки с самой собой и не будет делаться повторное сравнение точек (сначала PointArray(i) с PointArray(j), а затем PointArray(j) с PointArray(i))

Я чего не пойму. Т.е. для первой точки "соседи" будут отыскиваться из всех точек, а для последней - ни одного соседа?

(изменено: Владимир Линейцев, 13 ноября 2010г. 23:16:54)

Re: Можно ли ускорить выполнение программы VBA

Начал писать код и понял, что у меня массив сформирован по слоям применительно к железной дороге:
m - id номера пути;
j - id путевой или непутевой точки.

Т.е. мои точки m,j имеют параметры: Nomer, X, Y, H, kod и для каждого пути они находятся в своем слое.

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

Думается так, нужно:
1.сформировать однослойный массив точек;
2.применить к нему алгоритм Александра Ривилиса.

Re: Можно ли ускорить выполнение программы VBA

Вот вариант, думаю, последний:

For i = 1 To NN
       For j = i + 1 To NN
            delta_X = PointArray(i).X - PointArray(j).X
            If (delta_X) < R Then
            'check Y
                delta_Y = PointArray(i).Y - PointArray(j).Y
                If (delta_Y) < R Then
                'check R
                    If (delta_X * delta_X + delta_Y * delta_Y) < R * R Then
                       'Call Write_to_file(PointArray(i), PointArray(j))
                      'nLoop2 = nLoop2 + 1
                    End If
                End If
            End If
            'nLoop1 = nLoop1 + 1
        Next j
    Next i

Time 3.578 sec

(изменено: Александр Ривилис, 13 ноября 2010г. 23:30:47)

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

Я чего не пойму. Т.е. для первой точки "соседи" будут отыскиваться из всех точек, а для последней - ни одного соседа?

Ты уже для них "соседей" нашел. Тебе просто нужно завести для каждой из точек массив, в который дописывать точку если определил, что она соседняя. Т.е. в результате у тебя будет N массивов соседей. Ну а если не хочешь это делать, то во втором цикле начинай с 1. В худшем случае время увеличится в 2 раза. И еще учти, что LeonidSN использовал VB. Думаю, что на VBA будет медленней и возможно значительно.

(изменено: Владимир Линейцев, 16 ноября 2010г. 15:29:48)

Re: Можно ли ускорить выполнение программы VBA

Мне как-то сказали, что в ACAD 2011 уже VBA нет, там Net. Это правда? Тяжело ли адаптировать свои программы на Net?