Algorytmy i struktury danych

Podobne dokumenty
Algorytmy i struktury danych

Wstęp do programowania

Laboratorium kryptograficzne dla licealistów 6

Zaawansowane algorytmy i struktury danych

TEORETYCZNE PODSTAWY INFORMATYKI

Algorytm. a programowanie -

Logarytmy. Funkcje logarytmiczna i wykładnicza. Równania i nierówności wykładnicze i logarytmiczne.

Wstęp do Informatyki zadania ze złożoności obliczeniowej z rozwiązaniami

1 Wprowadzenie do algorytmiki

Plan. krótkie opisy modułów. 1 Uwagi na temat wydajności CPython a. 2 Podstawowe techniki poprawiające wydajność obliczeniową

FUNKCJA POTĘGOWA, WYKŁADNICZA I LOGARYTMICZNA

Wykład 4. Określimy teraz pewną ważną klasę pierścieni.

2.8. Algorytmy, schematy, programy

Języki i metody programowania

Szukanie rozwiązań funkcji uwikłanych (równań nieliniowych)

PROGRAMOWANIE W PYTHONIE OD PIERWSZYCH KROKÓW

Algorytmy i struktury danych

Złożoność obliczeniowa algorytmu ilość zasobów komputera jakiej potrzebuje dany algorytm. Pojęcie to

Podstawy Programowania Algorytmy i programowanie

TEORETYCZNE PODSTAWY INFORMATYKI

Algorytm i złożoność obliczeniowa algorytmu

Algorytmy w teorii liczb

Programowanie w języku Python. Grażyna Koba

Podstawy programowania funkcjonalnego

Algorytmy, reprezentacja algorytmów.

Wstęp do programowania

Ataki na RSA. Andrzej Chmielowiec. Centrum Modelowania Matematycznego Sigma. Ataki na RSA p. 1

Podstawowe algorytmy i ich implementacje w C. Wykład 9

Wstęp do Informatyki

Technologie cyfrowe. Artur Kalinowski. Zakład Cząstek i Oddziaływań Fundamentalnych Pasteura 5, pokój 4.15

Wprowadzenie do Python

Wykład IV Algorytmy metody prezentacji i zapisu Rzut oka na język PASCAL

Algorytm selekcji Hoare a. Łukasz Miemus

Wstęp do programowania

Zadanie 1 Przygotuj algorytm programu - sortowanie przez wstawianie.

Rekurencja (rekursja)

Ciągi liczbowe. Zbigniew Koza. Wydział Fizyki i Astronomii

Technologie Informacyjne Mechatronika 2012/2013 Błędy obliczeń. Python.

Maciej Piotr Jankowski

RÓWNANIA NIELINIOWE Maciej Patan

ALGORYTMY I STRUKTURY DANYCH

Liczby losowe i pętla while w języku Python

Podstawy programowania w Pythonie

Programowanie w Baltie klasa VII

1. Liczby wymierne. x dla x 0 (wartością bezwzględną liczby nieujemnej jest ta sama liczba)

Podstawy programowania. Podstawy C# Przykłady algorytmów

Zadania z rysowania i dopasowania funkcji

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

do instrukcja while(wyrażenie);

Optymalizacja ciągła

Python. Wprowadzenie. Jolanta Bachan

Programowanie proceduralne INP001210WL rok akademicki 2017/18 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Za pierwszy niebanalny algorytm uważa się algorytm Euklidesa wyszukiwanie NWD dwóch liczb (400 a 300 rok przed narodzeniem Chrystusa).

5. Rozwiązywanie układów równań liniowych

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 13. Karol Tarnowski A-1 p.

Wstęp do programowania INP001213Wcl rok akademicki 2018/19 semestr zimowy. Wykład 13. Karol Tarnowski A-1 p.

Wrocław, Wstęp do informatyki i programowania: liczby pierwsze. Wydział Matematyki Politechniki Wrocławskiej.

Wykład 1. Na początku zajmować się będziemy zbiorem liczb całkowitych

Wstęp do programowania

Matematyka dyskretna. Andrzej Łachwa, UJ, /14

Teoretyczne podstawy informatyki

Schematy blokowe I. 1. Dostępne bloki: 2. Prosty program drukujący tekst.

Matematyka dyskretna. Andrzej Łachwa, UJ, /15

Teoretyczne podstawy informatyki

Wprowadzenie do złożoności obliczeniowej

Lekcja 3: Pierwsze kroki z Pythonem. Pętle

Wykresy i interfejsy użytkownika

a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10]

Algorytmy. Programowanie Proceduralne 1

Algorytm. Krótka historia algorytmów

Nazwa implementacji: Nauka języka Python wyrażenia warunkowe. Autor: Piotr Fiorek. Opis implementacji: Poznanie wyrażeń warunkowych if elif - else.

Podstawy programowania. Wykład: 13. Rekurencja. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Wstęp do programowania

Laboratorium Metrologii

Algorytm poprawny jednoznaczny szczegółowy uniwersalny skończoność efektywność (sprawność) zmiennych liniowy warunkowy iteracyjny

Wprowadzenie do algorytmiki

7. Pętle for. Przykłady

Warsztaty dla nauczycieli

Algorytmy i złożoność obliczeniowa. Wojciech Horzelski

Dydaktyka matematyki III-IV etap edukacyjny (wykłady) Wykład nr 6: Nauczanie algorytmów w szkole Semestr zimowy 2018/2019

Podstawy programowania w Pythonie

O LICZBACH NIEOBLICZALNYCH I ICH ZWIĄZKACH Z INFORMATYKĄ

Regresja linearyzowalna

Podstawy Informatyki. Sprawność algorytmów

Wstęp do programowania

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 1. Karol Tarnowski A-1 p.

//warunki początkowe m=500; T=30; c=0.4; t=linspace(0,t,m); y0=[-2.5;2.5];

Metody numeryczne. materiały do wykładu dla studentów. 1. Teoria błędów, notacja O

CIĄGI wiadomości podstawowe

Przygotowanie kilku wersji kodu zgodnie z wymogami wersji zadania,

Algorytmy i struktury danych

Elżbieta Kula - wprowadzenie do Turbo Pascala i algorytmiki

ALGORYTMY MATEMATYCZNE Ćwiczenie 1 Na podstawie schematu blokowego pewnego algorytmu (rys 1), napisz listę kroków tego algorytmu:

Jeśli czas działania algorytmu zależy nie tylko od rozmiaru danych wejściowych i przyjmuje różne wartości dla różnych danych o tym samym rozmiarze,

Zadania do wykonania. Rozwiązując poniższe zadania użyj pętlę for.

Wstęp do informatyki. Maszyna RAM. Schemat logiczny komputera. Maszyna RAM. RAM: szczegóły. Realizacja algorytmu przez komputer

INFORMATYKA SORTOWANIE DANYCH.

Wykład 2. Poprawność algorytmów

Indukcja. Materiały pomocnicze do wykładu. wykładowca: dr Magdalena Kacprzak

Transkrypt:

Algorytmy i struktury danych Wykład 4 Algorytmy i ich analiza Janusz Szwabiński Plan wykładu: Co to jest algorytm? Analiza algorytmów motywacja Cele analizy Analiza eksperymentalna Studium przypadku 3SUM

Co to jest algorytm? Algorytm to skończony ciąg jasno zdefiniowanych czynności, koniecznych do wykonania pewnego rodzaju zadań. Innymi słowy to przepis na rozwiązanie problemu lub osiągnięcie jakiegoś celu. Istnieje kilka różnych metod zapisu algorytmu. Załóżmy, że naszym zadaniem jest obliczenie funkcji f(0) = 0 przy założeniu, że. f(x) = x x Słowny opis algorytmu 1. dla liczb ujemnych, więc, 2. dla liczb dodatnich, więc, x = 0 3. jeśli, to z definicji $f(0)=0. x = x f(x) = x/( x) = 1 x = x f(x) = x/x = 1 Opis słowny czasami da się w prosty sposób wyrazić wzorem matematycznym: f(x) = 1, 0, 1, x < 0 x = 0 x > 0 Lista kroków 1. Wczytaj wartość danej. 2. Jeśli, to. Zakończ algorytm. 3. Jeśli, to. Zakończ algorytm. x x > 0 f(x) = 1 x = 0 f(x) = 0 x < 0 f(x) = 1 4. Jeśli, to. Zakończ algorytm. Schemat blokowy Poszczególne elementy na powyższym schemacie mają następujące znaczenie:

Drzewo algorytmu Program komputerowy to nic innego jak algorytm zapisany w wybranym języku programowania. Powyższy algorytm zapisany w Pythonie mógłby mieć postać:

Dlaczego warto poznać algorytmy? cały obszar IT opiera się na algorytmach niektóre z nich są ponadczasowe: Euklides z Aleksandrii zajmował się badaniem algorytmów już w IV w p.n.e. (Źródło: Wikipedia) jego algorytm wyznaczania największego wspólnego dzielnika dwóch liczb (NWD) jest znany do dziś NWD jest stosowany w algorytmie RSA najpopularniejszym obecnie asymetrycznym algorytmie kryptograficznym z kluczem publicznym (https://pl.wikipedia.org/wiki/kryptografia_klucza_publicznego (https://pl.wikipedia.org/wiki/kryptografia_klucza_publicznego)) pozwalają rozwiązać zagadnienia, które inaczej pozostałyby nierozwiązane: problem komiwojażera, np. wyznaczenie najkrótszej trasy pozwalającej na zwiedzenie wszystkich stolic województw pozwalają stać się profesjonalnym programistą I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships. (Linus Torvalds, twórca Linuksa) stymulują intelektualnie przynoszą zysk <table class="image" width=50%> (Źródło: http://www.marketwatch.com)

Analiza algorytmów motywacja Często bywa tak, że ten sam algorytm zaimplementowany jest na wiele różnych sposobów. Nasuwa się wtedy pytanie, która z implementacji jest lepsza od pozostałych. Dla przykładu porównajmy dwa programy: In [1]: def sumofn(n): thesum = 0 for i in range(1,n+1): thesum = thesum + i return thesum print(sumofn(10)) 55 In [2]: def foo(tom): fred = 0 for bill in range(1,tom+1): barney = bill fred = fred + barney return fred print(foo(10)) 55 Mimo, że na pierwszy rzut oka tego nie widać, oba robią to samo sumują liczby od do, i na dodatek robią to w ten sam sposób. Mimo to powiemy, że pierwszy program jest lepszy ze względu na czytelność. Ogólnie rzecz biorąc, aby dokonać porównania między programami, musimy zdefiniować odpowiednie kryteria. Oprócz czytelności mogą to być: liczba operacji niezbędnych do wykonania "zasobożerność" wydajność czas wykonania 1 n Analiza algorytmów zajmuje się właśnie ich porównywaniem pod względem nakładów obliczeniowych niezbędnych do uzyskania rozwiązania. Wróćmy jeszcze raz do pierwszego z powyższych programów i zmodyfikujmy go tak, aby wyliczał jeszcze czas sumowania:

In [3]: import time def sumofn2(n): start = time.time() thesum = 0 for i in range(1,n+1): thesum = thesum + i end = time.time() return thesum,end-start Wyniki pięciu wywołań funkcji sumofn2dla n = 10000 są następujące: In [4]: for i in range(5): print("suma wynosi %d, czas wykonania: %10.7f sekund"%sumofn2(10000)) Suma wynosi 50005000, czas wykonania: 0.0010314 sekund Suma wynosi 50005000, czas wykonania: 0.0009410 sekund Suma wynosi 50005000, czas wykonania: 0.0009718 sekund Suma wynosi 50005000, czas wykonania: 0.0010254 sekund Suma wynosi 50005000, czas wykonania: 0.0009537 sekund Czasy wykonania poszczególnych wywołań różnią się nieznacznie od siebie (zależą od chwilowego obciążenia komputera), jednak rząd wielkości pozostaje ten sam. Zobaczmy, co stanie się, jeżeli zwiększymy o jeden rząd: n In [5]: for i in range(5): print("suma wynosi %d, czas wykonania: %10.7f sekund"%sumofn2(100000)) Suma wynosi 5000050000, czas wykonania: 0.0113173 sekund Suma wynosi 5000050000, czas wykonania: 0.0105736 sekund Suma wynosi 5000050000, czas wykonania: 0.0092735 sekund Suma wynosi 5000050000, czas wykonania: 0.0099654 sekund Suma wynosi 5000050000, czas wykonania: 0.0109329 sekund I znowu, czasy wykonania są dość podobne do siebie, jednak w porównaniu z poprzednim przykładem wzrosły mniej więcej dziesięciokrotnie. Dla jeszcze większego otrzymamy: n In [6]: for i in range(5): print("suma wynosi %d, czas wykonania: %10.7f sekund"%sumofn2(1000000)) Suma wynosi 500000500000, czas wykonania: 0.0880532 sekund Suma wynosi 500000500000, czas wykonania: 0.0663662 sekund Suma wynosi 500000500000, czas wykonania: 0.0571766 sekund Suma wynosi 500000500000, czas wykonania: 0.0511684 sekund Suma wynosi 500000500000, czas wykonania: 0.0486953 sekund

Widzimy, że czas wykonania ponownie wzrósł. Zauważmy teraz, że program sumofn2wylicza sumę częściową ciągu arytmetycznego o różnicy i wyrazie początkowym 1. Korzystając z własności ciągu sumę tę możemy wyliczyć przy pomocy wyrażenia: n In [7]: def sumofn3(n): start = time.time() thesum = n*(n+1)/2 end = time.time() return thesum,end-start i = i=1 n(n + 1) 2 r = 1 In [8]: for n in (10000,100000,1000000,10000000): print("suma wynosi %d, czas wykonania: %10.7f sekund"%sumofn3(n)) Suma wynosi 50005000, czas wykonania: 0.0000021 sekund Suma wynosi 5000050000, czas wykonania: 0.0000012 sekund Suma wynosi 500000500000, czas wykonania: 0.0000007 sekund Suma wynosi 50000005000000, czas wykonania: 0.0000007 sekund Analizując te wyniki dochodzimy do dwóch wniosków: 1. sumofn3wykonuje się dużo szybciej niż sumofn2 2. w przypadku sumofn3czas wykonania funkcji nieznacznie zależy od n Cele analizy przewidywanie wydajności algorytmów kiedy program się zakończy? ile pamięci będzie potrzebował? porównywanie algorytmów co zmienić, aby program działał szybciej? czy wprowadzenie zmiany spowoduje, że program zadziała szybciej? gwarancja poprawności algorytmów czy program się zakończy? czy dla prawidłowych danych zwróci prawidłowy wynik? zrozumienie algorytmów unikanie błędów wykonania

Analiza eksperymentalna obserwacja pewnych własności świata naturalnego, np. czasu pracy programu na komputerze opracowanie hipotezy (modelu), który jest zgodny z obserwacjami przewidywanie zdarzeń za pomocą opracowanej hipotezy, np. czasu pracy programu dla danych wejściowych o dużych rozmiarach lub czasu wykonania na innym komputerze weryfikacja przewidywań poprzez dalsze obserwacje walidacja poprzez powtarzanie weryfikacji do momentu, kiedy hipotezy i obserwacje są zgodne Zasady powtarzalność eksperymentów ktoś inny powinien być w stanie je przeprowadzić falsyfikowalność hipotez można wykazać fałszywość hipotezy przez wskazanie przypadku, który jej nie spełnia Studium przypadku 3SUM 3SUM (https://en.wikipedia.org/wiki/3sum (https://en.wikipedia.org/wiki/3sum)) to znany problem w teorii złożoności obliczeniowej: czy dla danego zbioru liczb N naturalnych istnieją elementy a, b i c z tego zbioru takie, że Jeśli tak, to ile ich jest? Dla zainteresowanych (jeden z nierozwiązanych problemów w informatyce): Czy istnieje algorytm rozwiązujący zagadnienie 3SUM w czasie ϵ > 0? a + b + c = 0 O( n 2 ϵ ) dla pewnego In [9]: import random In [13]: tab = [] for i in range(8): tab.append(random.randint(-50,50)) In [14]: tab Out[14]: [-41, -45, -22, 23, -30, 11, 30, -25] Metoda naiwna:

In [15]: count = 0 for i in range(len(tab)): for j in range(i+1, len(tab)): for k in range(j+1, len(tab)): if (tab[i]+tab[j]+tab[k]==0): count = count + 1 print(tab[i],tab[j],tab[k]) print("in total: %d"%count) -41 11 30 In total: 1 Krok 1 Program Stwórzmy program w oparciu o powyższy algorytm. Program ten powinien wczytywać wielkość zbioru liczb z linii poleceń: In [18]: %%writefile 3sum.py """3SUM problem solved with brute-force algorithm""" def counttriplets(tab): count = 0 triplets = [] for i in range(len(tab)): for j in range(i+1, len(tab)): for k in range(j+1, len(tab)): if (tab[i]+tab[j]+tab[k]==0): count = count + 1 triplets.append((tab[i],tab[j],tab[k])) return triplets if name == " main ": import sys import random n = int(sys.argv[1]) tab = [] for i in range(n): tab.append(random.randint(-50,50)) triplets = counttriplets(tab) if triplets: for t in triplets: print(t) print("in total: %d"%len(triplets)) else: print("no triplets found") Overwriting 3sum.py

In [19]:!python3 3sum.py 10 (-4, 12, -8) (4, 12, -16) In total: 2 Krok 2 pomiar czasu pracy programu Metoda 1 pomiar ręczny możliwe do przeprowadzenia, ale uciążliwe w zasadzie nie po to używamy komputerów Metoda 2 pomiar z poziomu systemu operacyjnego In [20]:!time python3 3sum.py 10 No triplets found real user sys 0m0.037s 0m0.032s 0m0.004s

In [21]:!time python3 3sum.py 20 (32, -3, -29) (32, -45, 13) (32, -49, 17) (-3, -41, 44) (-3, 37, -34) (-3, 37, -34) (-25, 13, 12) (-13, 19, -6) (45, -39, -6) (-49, 12, 37) (12, 17, -29) In total: 11 real user sys 0m0.035s 0m0.028s 0m0.004s

In [22]:!time python3 3sum.py 100

(-31, 38, -7) (-31, 38, -7) (-31, -17, 48) (-31, -1, 32) (-31, 49, -18) (-31, 37, -6) (-31, 30, 1) (-31, 9, 22) (-31, -5, 36) (-31, 36, -5) (-31, 37, -6) (-31, -8, 39) (-31, 25, 6) (-31, 25, 6) (-31, 22, 9) (-31, 14, 17) (-31, 25, 6) (-31, 25, 6) (-31, 17, 14) (-31, 37, -6) (-31, 37, -6) (-31, -1, 32) (-31, 37, -6) (-31, -10, 41) (-31, 0, 31) (-31, 31, 0) (-31, 49, -18) (-31, 37, -6) (-12, -34, 46) (-12, -34, 46) (-12, -20, 32) (-12, -27, 39) (-12, -25, 37) (-12, -25, 37) (-12, -25, 37) (-12, -25, 37) (-12, -25, 37) (-12, -25, 37) (-12, 8, 4) (-12, 3, 9) (-12, 3, 9) (-12, -29, 41) (-12, -17, 29) (-12, -17, 29) (-12, -27, 39) (-12, 49, -37) (-12, 49, -37) (-12, 37, -25) (-12, 30, -18) (-12, 9, 3) (-12, 9, 3) (-12, 48, -36) (-12, 48, -36) (-12, -5, 17) (-12, 20, -8) (-12, 37, -25) (-12, -37, 49) (-12, 12, 0) (-12, 12, 0) (-12, -8, 20) (-12, 22, -10)

(-12, 14, -2) (-12, 3, 9) (-12, -2, 14) (-12, -25, 37) (-12, -25, 37) (-12, -25, 37) (-12, -25, 37) (-12, 17, -5) (-12, 8, 4) (-12, 41, -29) (-12, -27, 39) (-12, 9, 3) (-12, 6, 6) (-12, 12, 0) (-12, 12, 0) (-12, 49, -37) (-12, -27, 39) (-34, 38, -4) (-34, 38, -4) (-34, 38, -4) (-34, 8, 26) (-34, 3, 31) (-34, -7, 41) (-34, 30, 4) (-34, 40, -6) (-34, 9, 25) (-34, 9, 25) (-34, -5, 39) (-34, 36, -2) (-34, 44, -10) (-34, -7, 41) (-34, 20, 14) (-34, 20, 14) (-34, 12, 22) (-34, -8, 42) (-34, -8, 42) (-34, 25, 9) (-34, 22, 12) (-34, 14, 20) (-34, 3, 31) (-34, 25, 9) (-34, 34, 0) (-34, 34, 0) (-34, -5, 39) (-34, 20, 14) (-34, 8, 26) (-34, 44, -10) (-34, 31, 3) (46, -25, -21) (46, -29, -17) (46, -17, -29) (46, -5, -41) (46, -36, -10) (46, -46, 0) (46, -46, 0) (46, -40, -6) (46, -21, -25) (46, -41, -5) (46, -10, -36) (46, -50, 4) (46, -6, -40)

(38, -20, -18) (38, 8, -46) (38, 3, -41) (38, -7, -31) (38, -17, -21) (38, -1, -37) (38, -1, -37) (38, -5, -33) (38, -7, -31) (38, -36, -2) (38, -46, 8) (38, -37, -1) (38, 12, -50) (38, -41, 3) (38, -41, 3) (38, -2, -36) (38, -5, -33) (38, -1, -37) (38, -48, 10) (38, -48, 10) (38, -50, 12) (50, -27, -23) (50, -25, -25) (50, -7, -43) (50, -7, -43) (50, -29, -21) (50, -17, -33) (50, -27, -23) (50, -43, -7) (50, -43, -7) (50, -46, -4) (50, -46, -4) (50, -46, -4) (50, -40, -10) (50, -21, -29) (50, -2, -48) (50, -10, -40) (50, -23, -27) (50, -23, -27) (50, -50, 0) (50, -50, 0) (-20, 8, 12) (-20, 8, 12) (-20, 3, 17) (-20, -29, 49) (-20, -29, 49) (-20, -17, 37) (-20, -17, 37) (-20, -17, 37) (-20, -17, 37) (-20, -17, 37) (-20, -17, 37) (-20, 49, -29) (-20, 30, -10) (-20, -5, 25) (-20, -5, 25) (-20, 20, 0) (-20, 20, 0) (-20, 12, 8) (-20, 25, -5) (-20, -21, 41)

(-20, 22, -2) (-20, 14, 6) (-20, 14, 6) (-20, 3, 17) (-20, 25, -5) (-20, 17, 3) (-20, 20, 0) (-20, 20, 0) (-20, 8, 12) (-20, 10, 10) (-20, 6, 14) (-20, 6, 14) (-20, 49, -29) (-20, -6, 26) (-27, 7, 20) (-27, 7, 20) (-27, -7, 34) (-27, -17, 44) (-27, -17, 44) (-27, 37, -10) (-27, 48, -21) (-27, -5, 32) (-27, -7, 34) (-27, 20, 7) (-27, 37, -10) (-27, -4, 31) (-27, -2, 29) (-27, -2, 29) (-27, 17, 10) (-27, 17, 10) (-27, -5, 32) (-27, 37, -10) (-27, 1, 26) (-27, 20, 7) (-27, 37, -10) (-27, 37, -10) (-27, -10, 37) (-27, -23, 50) (-27, -4, 31) (-27, 31, -4) (-25, 8, 17) (-25, 3, 22) (-25, -7, 32) (-25, -17, 42) (-25, -17, 42) (-25, -1, 26) (-25, 30, -5) (-25, 30, -5) (-25, 48, -23) (-25, -7, 32) (-25, 25, 0) (-25, 25, 0) (-25, -21, 46) (-25, 22, 3) (-25, 22, 3) (-25, 25, 0) (-25, 25, 0) (-25, -4, 29) (-25, -4, 29) (-25, -25, 50) (-25, 17, 8)

(-25, 29, -4) (-25, 29, -4) (-25, -1, 26) (-25, -4, 29) (-25, 31, -6) (-25, 29, -4) (8, -7, -1) (8, -7, -1) (8, -17, 9) (8, -17, 9) (8, -1, -7) (8, 40, -48) (8, -7, -1) (8, -37, 29) (8, -37, 29) (8, -8, 0) (8, -8, 0) (8, -40, 32) (8, 25, -33) (8, 25, -33) (8, -4, -4) (8, -4, -4) (8, -2, -6) (8, -25, 17) (8, 42, -50) (8, 29, -37) (8, 10, -18) (8, -50, 42) (8, 10, -18) (8, -4, -4) (8, 29, -37) (8, 32, -40) (3, 7, -10) (3, -7, 4) (3, -29, 26) (3, -17, 14) (3, -17, 14) (3, -1, -2) (3, -43, 40) (3, 37, -40) (3, 37, -40) (3, 30, -33) (3, 40, -43) (3, -7, 4) (3, 20, -23) (3, 37, -40) (3, 37, -40) (3, -37, 34) (3, -40, 37) (3, -40, 37) (3, -40, 37) (3, -40, 37) (3, 22, -25) (3, 3, -6) (3, -4, 1) (3, -2, -1) (3, 34, -37) (3, 37, -40) (3, 1, -4) (3, 1, -4) (3, 20, -23)

(3, 37, -40) (3, 37, -40) (3, -35, 32) (3, -10, 7) (3, 37, -40) (3, 3, -6) (3, 26, -29) (7, -7, 0) (7, -7, 0) (7, -29, 22) (7, -17, 10) (7, -17, 10) (7, -27, 20) (7, -27, 20) (7, -1, -6) (7, -43, 36) (7, 30, -37) (7, 30, -37) (7, -5, -2) (7, 36, -43) (7, -7, 0) (7, -7, 0) (7, 20, -27) (7, 20, -27) (7, -36, 29) (7, -36, 29) (7, -46, 39) (7, -8, 1) (7, -21, 14) (7, -21, 14) (7, 22, -29) (7, -41, 34) (7, 3, -10) (7, -2, -5) (7, 20, -27) (7, 20, -27) (7, 29, -36) (7, -1, -6) (7, -48, 41) (7, -33, 26) (7, -10, 3) (7, 29, -36) (-7, -29, 36) (-7, -27, 34) (-7, -1, 8) (-7, -43, 50) (-7, 30, -23) (-7, 40, -33) (-7, 9, -2) (-7, 48, -41) (-7, -5, 12) (-7, -5, 12) (-7, 36, -29) (-7, 44, -37) (-7, 44, -37) (-7, -43, 50) (-7, -7, 14) (-7, -7, 14) (-7, -37, 44) (-7, 12, -5) (-7, 25, -18)

(-7, 3, 4) (-7, 25, -18) (-7, -2, 9) (-7, 34, -27) (-7, 34, -27) (-7, -25, 32) (-7, 17, -10) (-7, -5, 12) (-7, 1, 6) (-7, 1, 6) (-7, 42, -35) (-7, 8, -1) (-7, 44, -37) (-7, -35, 42) (-7, 0, 7) (-7, 4, 3) (-7, 0, 7) (-29, -17, 46) (-29, -1, 30) (-29, 37, -8) (-29, 30, -1) (-29, 9, 20) (-29, 9, 20) (-29, -5, 34) (-29, 36, -7) (-29, 20, 9) (-29, 37, -8) (-29, 12, 17) (-29, -8, 37) (-29, -8, 37) (-29, -8, 37) (-29, -8, 37) (-29, 25, 4) (-29, -21, 50) (-29, 22, 7) (-29, 3, 26) (-29, 25, 4) (-29, -2, 31) (-29, 34, -5) (-29, 17, 12) (-29, 20, 9) (-29, 29, 0) (-29, 29, 0) (-29, -10, 39) (-29, 0, 29) (-29, 29, 0) (-29, 3, 26) (-17, -27, 44) (-17, -27, 44) (-17, 40, -23) (-17, 9, 8) (-17, 48, -31) (-17, -5, 22) (-17, 44, -27) (-17, 44, -27) (-17, -8, 25) (-17, -8, 25) (-17, 22, -5) (-17, 14, 3) (-17, 14, 3) (-17, 3, 14)

(-17, -25, 42) (-17, -25, 42) (-17, 46, -29) (-17, 17, 0) (-17, 17, 0) (-17, 8, 9) (-17, 44, -27) (-17, 44, -27) (-17, -33, 50) (-17, 10, 7) (-17, 10, 7) (-17, 3, 14) (-27, 37, -10) (-27, 48, -21) (-27, -5, 32) (-27, -7, 34) (-27, 20, 7) (-27, 37, -10) (-27, -4, 31) (-27, -2, 29) (-27, -2, 29) (-27, 17, 10) (-27, 17, 10) (-27, -5, 32) (-27, 37, -10) (-27, 1, 26) (-27, 20, 7) (-27, 37, -10) (-27, 37, -10) (-27, -10, 37) (-27, -23, 50) (-27, -4, 31) (-27, 31, -4) (-1, 49, -48) (-1, -43, 44) (-1, -43, 44) (-1, 37, -36) (-1, 37, -36) (-1, 30, -29) (-1, 9, -8) (-1, -5, 6) (-1, -5, 6) (-1, 36, -35) (-1, 44, -43) (-1, -43, 44) (-1, -7, 8) (-1, 37, -36) (-1, 37, -36) (-1, -36, 37) (-1, -36, 37) (-1, -36, 37) (-1, -36, 37) (-1, -8, 9) (-1, -40, 41) (-1, -31, 32) (-1, -21, 22) (-1, -41, 42) (-1, -41, 42) (-1, 3, -2) (-1, -2, 3) (-1, 34, -33)

(-1, -25, 26) (-1, -5, 6) (-1, -5, 6) (-1, 37, -36) (-1, 1, 0) (-1, 1, 0) (-1, 37, -36) (-1, 37, -36) (-1, -48, 49) (-1, 41, -40) (-1, 37, -36) (-1, -6, 7) (49, -43, -6) (49, -43, -6) (49, -8, -41) (49, -31, -18) (49, 1, -50) (49, -1, -48) (-43, 37, 6) (-43, 37, 6) (-43, 40, 3) (-43, 40, 3) (-43, 9, 34) (-43, 48, -5) (-43, 48, -5) (-43, 36, 7) (-43, 44, -1) (-43, -7, 50) (-43, 37, 6) (-43, 37, 6) (-43, 12, 31) (-43, 14, 29) (-43, 14, 29) (-43, 34, 9) (-43, 17, 26) (-43, 37, 6) (-43, 37, 6) (-43, 1, 42) (-43, 1, 42) (-43, 37, 6) (-43, 37, 6) (-43, 29, 14) (-43, -1, 44) (-43, 37, 6) (-43, 37, 6) (-43, 6, 37) (-43, 12, 31) (-43, 4, 39) (-43, 6, 37) (-43, 49, -6) (-43, 29, 14) (37, 9, -46) (37, -43, 6) (37, -43, 6) (37, -36, -1) (37, -46, 9) (37, -37, 0) (37, -37, 0) (37, -8, -29) (37, -40, 3) (37, -40, 3)

(37, -31, -6) (37, -41, 4) (37, 3, -40) (37, -4, -33) (37, -2, -35) (37, -1, -36) (37, -33, -4) (37, -33, -4) (37, -10, -27) (37, -10, -27) (37, 0, -37) (37, 3, -40) (37, -37, 0) (30, -5, -25) (30, -7, -23) (30, 20, -50) (30, -36, 6) (30, -36, 6) (30, -37, 7) (30, -40, 10) (30, -40, 10) (30, -31, 1) (30, 3, -33) (30, -25, -5) (30, 20, -50) (30, -1, -29) (30, -33, 3) (30, 10, -40) (30, 10, -40) (30, 6, -36) (30, 6, -36) (30, -37, 7) (40, -5, -35) (40, -43, 3) (40, -43, 3) (40, -7, -33) (40, -36, -4) (40, -36, -4) (40, -36, -4) (40, -46, 6) (40, -46, 6) (40, -40, 0) (40, -40, 0) (40, -41, 1) (40, -4, -36) (40, -5, -35) (40, 8, -48) (40, 10, -50) (40, -50, 10) (40, -4, -36) (40, 0, -40) (40, -36, -4) (40, 0, -40) (9, -5, -4) (9, -5, -4) (9, -5, -4) (9, -43, 34) (9, -7, -2) (9, 20, -29) (9, 37, -46) (9, -46, 37)

(9, -46, 37) (9, -46, 37) (9, -46, 37) (9, 12, -21) (9, -8, -1) (9, -40, 31) (9, -31, 22) (9, -21, 12) (9, -41, 32) (9, 14, -23) (9, -4, -5) (9, -5, -4) (9, -5, -4) (9, 1, -10) (9, 20, -29) (9, -48, 39) (9, -35, 26) (9, -23, 14) (9, 41, -50) (9, 9, -18) (9, 31, -40) (48, -5, -43) (48, -43, -5) (48, -7, -41) (48, -46, -2) (48, -8, -40) (48, -8, -40) (48, -21, -27) (48, -21, -27) (48, -25, -23) (48, -48, 0) (48, -48, 0) (-5, 36, -31) (-5, -7, 12) (-5, -7, 12) (-5, -36, 41) (-5, -37, 42) (-5, -37, 42) (-5, -21, 26) (-5, -41, 46) (-5, -4, 9) (-5, -2, 7) (-5, 34, -29) (-5, -5, 10) (-5, -5, 10) (-5, 1, 4) (-5, 42, -37) (-5, -1, 6) (-5, -1, 6) (-5, 41, -36) (-5, -27, 32) (-5, 9, -4) (-5, 9, -4) (-5, 32, -27) (-5, -37, 42) (36, -43, 7) (36, -7, -29) (36, -36, 0) (36, -36, 0) (36, -46, 10) (36, -46, 10)

(36, -37, 1) (36, 12, -48) (36, -40, 4) (36, -31, -5) (36, 14, -50) (36, 1, -37) (36, -1, -35) (36, -48, 12) (36, -50, 14) (36, 0, -36) (36, 4, -40) (36, -36, 0) (44, -43, -1) (44, -7, -37) (44, -7, -37) (44, -36, -8) (44, -8, -36) (44, -40, -4) (44, -40, -4) (44, -40, -4) (44, -21, -23) (44, -4, -40) (44, -48, 4) (44, -50, 6) (44, -50, 6) (44, -4, -40) (44, -4, -40) (-43, -7, 50) (-43, 37, 6) (-43, 37, 6) (-43, 12, 31) (-43, 14, 29) (-43, 14, 29) (-43, 34, 9) (-43, 17, 26) (-43, 37, 6) (-43, 37, 6) (-43, 1, 42) (-43, 1, 42) (-43, 37, 6) (-43, 37, 6) (-43, 29, 14) (-43, -1, 44) (-43, 37, 6) (-43, 37, 6) (-43, 6, 37) (-43, 12, 31) (-43, 4, 39) (-43, 6, 37) (-43, 49, -6) (-43, 29, 14) (-7, -37, 44) (-7, 12, -5) (-7, 25, -18) (-7, 3, 4) (-7, 25, -18) (-7, -2, 9) (-7, 34, -27) (-7, 34, -27) (-7, -25, 32) (-7, 17, -10)

(-7, -5, 12) (-7, 1, 6) (-7, 1, 6) (-7, 42, -35) (-7, 8, -1) (-7, 44, -37) (-7, -35, 42) (-7, 0, 7) (-7, 4, 3) (-7, 0, 7) (20, -46, 26) (20, -37, 17) (20, -40, 20) (20, -21, 1) (20, 3, -23) (20, -2, -18) (20, 17, -37) (20, 20, -40) (20, -23, 3) (20, -27, 7) (20, 9, -29) (20, -27, 7) (37, -36, -1) (37, -46, 9) (37, -37, 0) (37, -37, 0) (37, -8, -29) (37, -40, 3) (37, -40, 3) (37, -31, -6) (37, -41, 4) (37, 3, -40) (37, -4, -33) (37, -2, -35) (37, -1, -36) (37, -33, -4) (37, -33, -4) (37, -10, -27) (37, -10, -27) (37, 0, -37) (37, 3, -40) (37, -37, 0) (-36, -8, 44) (-36, 22, 14) (-36, 22, 14) (-36, 46, -10) (-36, -5, 41) (-36, 37, -1) (-36, 42, -6) (-36, 37, -1) (-36, 29, 7) (-36, -1, 37) (-36, -1, 37) (-36, 10, 26) (-36, 10, 26) (-36, 4, 32) (-36, 29, 7) (-36, -6, 42) (-46, 12, 34) (-46, 14, 32) (-46, -4, 50)

(-46, 34, 12) (-46, 46, 0) (-46, 46, 0) (-46, 17, 29) (-46, 17, 29) (-46, 37, 9) (-46, 20, 26) (-46, 42, 4) (-46, 37, 9) (-46, 37, 9) (-46, 50, -4) (-46, 50, -4) (-46, 9, 37) (-46, 4, 42) (-46, 32, 14) (-46, 39, 7) (-37, 12, 25) (-37, 12, 25) (-37, 25, 12) (-37, 3, 34) (-37, 25, 12) (-37, -4, 41) (-37, -2, 39) (-37, 34, 3) (-37, 17, 20) (-37, -5, 42) (-37, -5, 42) (-37, 37, 0) (-37, 37, 0) (-37, 8, 29) (-37, 8, 29) (-37, 37, 0) (-37, 37, 0) (-37, 37, 0) (-37, 37, 0) (-37, 41, -4) (-37, 41, -4) (-37, 6, 31) (-37, 0, 37) (-37, 31, 6) (-37, 37, 0) (12, -8, -4) (12, -8, -4) (12, -8, -4) (12, 25, -37) (12, -21, 9) (12, -41, 29) (12, -41, 29) (12, 25, -37) (12, -2, -10) (12, 17, -29) (12, 6, -18) (12, 6, -18) (-8, -31, 39) (-8, -21, 29) (-8, -21, 29) (-8, -41, 49) (-8, 14, -6) (-8, -4, 12) (-8, -2, 10) (-8, -2, 10)

(-8, 37, -29) (-8, 1, 7) (-8, 8, 0) (-8, 8, 0) (-8, 37, -29) (-8, -1, 9) (-8, 37, -29) (-8, 44, -36) (-8, -33, 41) (-8, -23, 31) (-8, -4, 12) (-8, 12, -4) (-8, 37, -29) (-8, 14, -6) (-8, 26, -18) (-40, 14, 26) (-40, 3, 37) (-40, 3, 37) (-40, 3, 37) (-40, 3, 37) (-40, -4, 44) (-40, -2, 42) (-40, -2, 42) (-40, 34, 6) (-40, 34, 6) (-40, 46, -6) (-40, 37, 3) (-40, 1, 39) (-40, 8, 32) (-40, 37, 3) (-40, -1, 41) (-40, 37, 3) (-40, 44, -4) (-40, 44, -4) (-40, -10, 50) (-40, 9, 31) (-40, 37, 3) (-40, 14, 26) (-31, 25, 6) (-31, 25, 6) (-31, 22, 9) (-31, 14, 17) (-31, 25, 6) (-31, 25, 6) (-31, 17, 14) (-31, 37, -6) (-31, 37, -6) (-31, -1, 32) (-31, 37, -6) (-31, -10, 41) (-31, 0, 31) (-31, 31, 0) (-31, 49, -18) (-31, 37, -6) (25, -21, -4) (25, -21, -4) (25, -21, -4) (25, 25, -50) (25, -2, -23) (25, -25, 0) (25, -25, 0)

(25, 8, -33) (25, -35, 10) (25, -35, 10) (25, 12, -37) (25, 4, -29) (-21, 22, -1) (-21, 14, 7) (-21, 25, -4) (-21, 25, -4) (-21, 25, -4) (-21, -25, 46) (-21, 17, 4) (-21, -5, 26) (-21, 1, 20) (-21, 44, -23) (-21, -10, 31) (-21, 50, -29) (-21, 9, 12) (-21, 14, 7) (-21, 39, -18) (22, 14, -36) (22, 3, -25) (22, -4, -18) (22, -25, 3) (22, 1, -23) (22, -48, 26) (22, -4, -18) (22, -36, 14) (22, -4, -18) (22, -29, 7) (-41, 34, 7) (-41, 46, -5) (-41, 37, 4) (-41, 42, -1) (-41, 37, 4) (-41, 29, 12) (-41, -1, 42) (-41, 37, 4) (-41, 10, 31) (-41, 41, 0) (-41, 41, 0) (-41, 9, 32) (-41, 10, 31) (-41, 12, 29) (-41, 4, 37) (14, -4, -10) (14, 34, -48) (14, -10, -4) (14, -10, -4) (14, -23, 9) (14, 4, -18) (14, -40, 26) (3, -4, 1) (3, -2, -1) (3, 34, -37) (3, 37, -40) (3, 1, -4) (3, 1, -4) (3, 20, -23) (3, 37, -40) (3, 37, -40)

(3, -35, 32) (3, -10, 7) (3, 37, -40) (3, 3, -6) (3, 26, -29) (25, -2, -23) (25, -25, 0) (25, -25, 0) (25, 8, -33) (25, -35, 10) (25, -35, 10) (25, 12, -37) (25, 4, -29) (-4, -2, 6) (-4, -2, 6) (-4, -25, 29) (-4, -25, 29) (-4, -5, 9) (-4, 37, -33) (-4, 1, 3) (-4, 8, -4) (-4, 8, -4) (-4, 37, -33) (-4, 37, -33) (-4, 44, -40) (-4, -35, 39) (-4, -33, 37) (-4, -10, 14) (-4, 10, -6) (-4, 41, -37) (-4, -27, 31) (-4, 10, -6) (-4, 0, 4) (-4, 4, 0) (-4, 31, -27) (-2, -5, 7) (-2, 37, -35) (-2, 20, -18) (-2, 42, -40) (-2, 8, -6) (-2, 37, -35) (-2, 29, -27) (-2, 29, -27) (-2, -1, 3) (-2, 37, -35) (-2, -48, 50) (-2, -35, 37) (-2, -10, 12) (-2, -27, 29) (-2, -4, 6) (-2, -4, 6) (-2, 6, -4) (-2, 31, -29) (-2, 6, -4) (-2, 29, -27) (-2, -37, 39) (-2, -40, 42) (34, -5, -29) (34, 1, -35) (34, -1, -33) (34, -48, 14)

(34, 6, -40) (34, 6, -40) (34, 3, -37) (-25, 17, 8) (-25, 29, -4) (-25, 29, -4) (-25, -1, 26) (-25, -4, 29) (-25, 31, -6) (-25, 29, -4) (46, -10, -36) (46, -50, 4) (46, -6, -40) (17, 1, -18) (17, 20, -37) (17, -48, 31) (17, 10, -27) (17, 10, -27) (17, -23, 6) (17, -23, 6) (17, -27, 10) (17, 10, -27) (17, 12, -29) (-5, 1, 4) (-5, 42, -37) (-5, -1, 6) (-5, -1, 6) (-5, 41, -36) (-5, -27, 32) (-5, 9, -4) (-5, 9, -4) (-5, 32, -27) (-5, -37, 42) (37, -1, -36) (37, -33, -4) (37, -33, -4) (37, -10, -27) (37, -10, -27) (37, 0, -37) (37, 3, -40) (37, -37, 0) (1, -1, 0) (1, -1, 0) (1, -33, 32) (1, -10, 9) (1, -27, 26) (1, -50, 49) (1, -4, 3) (1, 3, -4) (1, -27, 26) (1, 39, -40) (20, -23, 3) (20, -27, 7) (20, 9, -29) (20, -27, 7) (42, 8, -50) (42, -48, 6) (42, -48, 6) (42, -36, -6) (8, 29, -37) (8, 10, -18)

(8, -50, 42) (8, 10, -18) (8, -4, -4) (8, 29, -37) (8, 32, -40) (37, -1, -36) (37, -33, -4) (37, -33, -4) (37, -10, -27) (37, -10, -27) (37, 0, -37) (37, 3, -40) (37, -37, 0) (29, -35, 6) (29, -35, 6) (29, -33, 4) (29, -23, -6) (29, 0, -29) (29, -36, 7) (29, 0, -29) (-1, 37, -36) (-1, -48, 49) (-1, 41, -40) (-1, 37, -36) (-1, -6, 7) (37, -33, -4) (37, -33, -4) (37, -10, -27) (37, -10, -27) (37, 0, -37) (37, 3, -40) (37, -37, 0) (44, -48, 4) (44, -50, 6) (44, -50, 6) (44, -4, -40) (44, -4, -40) (-48, 41, 7) (-48, 9, 39) (-48, 6, 42) (-48, 6, 42) (-35, 41, -6) (-35, 9, 26) (-35, -4, 39) (-35, 6, 29) (-35, 4, 31) (-35, 6, 29) (-35, 32, 3) (-35, 39, -4) (-33, -4, 37) (-33, 4, 29) (-33, 37, -4) (-33, 39, -6) (-33, 26, 7) (-10, 10, 0) (-10, 10, 0) (-10, -27, 37) (-10, 50, -40) (-10, 10, 0) (-10, 10, 0) (-10, -4, 14)

(-10, 6, 4) (-10, 4, 6) (-10, 37, -27) (-10, 3, 7) (-10, 14, -4) (-10, 39, -29) (10, -4, -6) (10, -36, 26) (10, -6, -4) (-23, 41, -18) (-23, -27, 50) (-23, 50, -27) (-23, 9, 14) (-23, 29, -6) (41, 9, -50) (41, -4, -37) (41, -37, -4) (-27, -4, 31) (-27, 31, -4) (50, -50, 0) (50, -50, 0) (9, 31, -40) (10, -4, -6) (10, -36, 26) (10, -6, -4) (-4, 0, 4) (-4, 4, 0) (-4, 31, -27) (6, 12, -18) (6, 0, -6) (6, 31, -37) (6, -6, 0) (12, 6, -18) (0, 4, -4) (0, 6, -6) (0, 29, -29) (0, 37, -37) (4, 32, -36) (4, 14, -18) (4, -4, 0) (31, 6, -37) (31, -27, -4) (6, -6, 0) (29, -36, 7) (29, 0, -29) (37, 3, -40) (37, -37, 0) (3, 26, -29) (-36, -6, 42) (14, -40, 26) In total: 1209 real user sys 0m0.085s 0m0.076s 0m0.008s Uwaga! Użytkownicy Windowsa mają do dyspozycji Measure-Commandw Powershellu. Korzystając z możliwości powłoki, nie musimy uruchamiać programu dla każdego rozmiaru ręcznie:

In [23]:!for N in 10 20 30 40 50; do time python3 3sum.py $N; done

(-31, 20, 11) (26, 9, -35) In total: 2 real 0m0.039s user 0m0.036s sys 0m0.000s (-3, 45, -42) (-28, -10, 38) (-28, -10, 38) (-28, -10, 38) (0, 14, -14) (41, 1, -42) (1, -10, 9) (1, -10, 9) (1, 9, -10) (-10, 6, 4) (-10, -28, 38) (-10, 6, 4) (-10, -28, 38) (9, -42, 33) (9, 5, -14) (6, -10, 4) (-28, -10, 38) (-42, 4, 38) In total: 18 real 0m0.035s user 0m0.028s sys 0m0.004s (41, -1, -40) (41, -1, -40) (41, -40, -1) (41, -45, 4) (41, -45, 4) (41, -49, 8) (41, -44, 3) (41, -1, -40) (-1, 39, -38) (-40, 37, 3) (-45, 35, 10) (-45, 10, 35) (-45, 37, 8) (-49, 10, 39) (-49, 12, 37) (35, 3, -38) (10, -18, 8) (10, -27, 17) (10, 3, -13) (35, 3, -38) (39, -1, -38) (39, 3, -42) (4, 11, -15) (12, 3, -15) (11, -15, 4) (37, -40, 3) (-27, 3, 24) In total: 27 real user 0m0.028s 0m0.024s

sys 0m0.000s (15, 14, -29) (15, 17, -32) (15, -36, 21) (15, -36, 21) (15, -14, -1) (14, 17, -31) (14, 10, -24) (14, -24, 10) (11, -38, 27) (11, 5, -16) (11, -36, 25) (11, -36, 25) (11, -32, 21) (11, -32, 21) (11, 20, -31) (-22, -5, 27) (-22, 17, 5) (-22, -24, 46) (-22, -14, 36) (-22, -5, 27) (-22, -5, 27) (45, -16, -29) (45, -14, -31) (-5, -38, 43) (-5, 41, -36) (-5, 10, -5) (-5, 10, -5) (-5, -24, 29) (-5, -16, 21) (-5, -16, 21) (-5, -5, 10) (-5, -31, 36) (-5, -5, 10) (-38, 17, 21) (-38, 17, 21) (-38, -5, 43) (-38, -5, 43) (17, -16, -1) (-48, 5, 43) (-48, 21, 27) (-48, 21, 27) (41, -36, -5) (41, -36, -5) (10, -36, 26) (10, 21, -31) (10, -5, -5) (10, -31, 21) (-24, -16, 40) (-24, -1, 25) (-24, -1, 25) (-24, 29, -5) (-24, 29, -5) (-33, -11, 44) (46, -32, -14) (5, -32, 27) (5, 26, -31) (-36, 26, 10) (-36, -14, 50) (-16, -11, 27) (-16, 21, -5)

(-16, 21, -5) (-16, -5, 21) (-16, -5, 21) (-32, -11, 43) (-14, -11, 25) (-14, -11, 25) (-14, -29, 43) (-11, -33, 44) (-11, -29, 40) (21, -31, 10) (-5, -31, 36) (-5, -5, 10) (-31, -5, 36) (-31, 21, 10) In total: 74 real 0m0.028s user 0m0.024s sys 0m0.000s (11, -18, 7) (11, -18, 7) (11, -4, -7) (11, -20, 9) (11, -20, 9) (11, -20, 9) (11, -20, 9) (11, -11, 0) (11, 7, -18) (11, 13, -24) (11, -18, 7) (-39, -4, 43) (-39, 1, 38) (-39, 48, -9) (-39, -11, 50) (-39, -9, 48) (-17, -4, 21) (-17, -20, 37) (-17, 10, 7) (-17, 10, 7) (-17, -20, 37) (-17, 10, 7) (-17, 10, 7) (-17, 31, -14) (-17, -14, 31) (-17, -24, 41) (-18, 40, -22) (-18, -20, 38) (-18, -20, 38) (-18, -27, 45) (-18, 9, 9) (-18, -13, 31) (-18, -13, 31) (-18, 27, -9) (-18, 42, -24) (-18, 42, -24) (-18, -24, 42) (-4, 40, -36) (-4, 40, -36) (-4, 48, -44) (-4, -27, 31) (-4, -27, 31)

(-4, -44, 48) (-4, 13, -9) (47, -20, -27) (47, -20, -27) (47, -36, -11) (47, -11, -36) (40, -20, -20) (40, -50, 10) (40, -50, 10) (40, 10, -50) (40, -27, -13) (40, 10, -50) (40, -22, -18) (-20, 10, 10) (-20, -27, 47) (-20, -27, 47) (-20, -11, 31) (-20, -11, 31) (-20, 7, 13) (-20, 13, 7) (-20, -22, 42) (-20, -22, 42) (-20, -22, 42) (-20, 27, -7) (-20, -18, 38) (-50, 49, 1) (-50, 43, 7) (-50, 43, 7) (-50, 9, 41) (-50, 37, 13) (-50, 9, 41) (-50, 0, 50) (49, 1, -50) (49, -36, -13) (49, -27, -22) (49, -13, -36) (10, 1, -11) (10, -20, 10) (1, 43, -44) (1, -11, 10) (1, 13, -14) (1, -22, 21) (43, -36, -7) (43, 7, -50) (43, -36, -7) (43, 7, -50) (-20, -27, 47) (-20, -27, 47) (-20, -11, 31) (-20, -11, 31) (-20, 7, 13) (-20, 13, 7) (-20, -22, 42) (-20, -22, 42) (-20, -22, 42) (-20, 27, -7) (-20, -18, 38) (-36, -11, 47) (-36, -11, 47) (-36, 9, 27) (-36, -14, 50)

(-36, 9, 27) (-36, -9, 45) (-27, -11, 38) (-27, -14, 41) (-27, 27, 0) (-27, -18, 45) (-11, 47, -36) (-11, -36, 47) (9, 13, -22) (9, 9, -18) (9, 27, -36) (9, -9, 0) (9, -50, 41) (-44, 7, 37) (-44, 37, 7) (-44, 31, 13) (-44, 13, 31) (7, -14, 7) (7, 0, -7) (37, -13, -24) (37, 13, -50) (-13, 31, -18) (-13, 13, 0) (-13, -14, 27) (-13, -18, 31) (31, -22, -9) (31, -7, -24) (13, -22, 9) (-22, -9, 31) (-14, -36, 50) (-14, 21, -7) (-14, 38, -24) (9, 27, -36) (9, -9, 0) (9, -50, 41) (27, -9, -18) (-36, -9, 45) (-18, 42, -24) (-18, 42, -24) (-18, -24, 42) (7, 0, -7) (0, -50, 50) (31, -7, -24) In total: 146 real user sys 0m0.033s 0m0.024s 0m0.008s Nie jest to zbyt przejrzyste, dlatego zmodyfikujemy nieco nasz program:

In [24]: %%writefile 3sum_2.py """3SUM problem solved with brute-force algorithm""" def counttriplets(tab): count = 0 triplets = [] for i in range(len(tab)): for j in range(i+1, len(tab)): for k in range(j+1, len(tab)): if (tab[i]+tab[j]+tab[k]==0): count = count + 1 triplets.append((tab[i],tab[j],tab[k])) return triplets if name == " main ": import sys import random n = int(sys.argv[1]) tab = [] for i in range(n): tab.append(random.randint(-50,50)) triplets = counttriplets(tab) print("\nsystem size: %d"%n) Overwriting 3sum_2.py

In [25]:!for N in 10 20 30 40 50; do time python3 3sum_2.py $N; done System size: 10 real user sys 0m0.031s 0m0.028s 0m0.000s System size: 20 real user sys 0m0.029s 0m0.024s 0m0.004s System size: 30 real user sys 0m0.027s 0m0.024s 0m0.000s System size: 40 real user sys 0m0.029s 0m0.024s 0m0.004s System size: 50 real user sys 0m0.029s 0m0.024s 0m0.004s Metoda 3 pomiar z poziomu programu Jeżeli wyników pomiaru czasu chcemy potem używać do analiz, najwygodniejszy może okazać się pomiar czasu wykonywania z poziomu analizowanego programu. Najprościej jest użyć do tego modułu time: In [26]: import time

In [27]: #sekundy... time.time() Out[27]: 1474631774.1989377 In [28]: #... które upłynęły od time.gmtime(0)[:6] Out[28]: (1970, 1, 1, 0, 0, 0) In [29]: #jak mierzyć? def procedure(): time.sleep(2.5) In [30]: # czas procesora, jaki został skonsumowany # przez proces ("process time") t0 = time.clock() procedure() t1 = time.clock() print("czas procesora:", t1-t0, "s") Czas procesora: 0.0019679999999999698 s In [31]: # rzeczywisty czas ("wall time") t0 = time.time() procedure() t1 = time.time() print("rzeczywisty czas:", t1-t0, "s") Rzeczywisty czas: 2.5009217262268066 s Warto wiedzieć, że nie wszystkie systemy (z Windows włącznie) mogą mierzyć czas procesora. Funkcja clockpokaże wówczas czas rzeczywisty. Wróćmy do naszego programu:

In [34]: %%writefile 3sum_3.py """3SUM problem solved with brute-force algorithm""" def counttriplets(tab): count = 0 triplets = [] for i in range(len(tab)): for j in range(i+1, len(tab)): for k in range(j+1, len(tab)): if (tab[i]+tab[j]+tab[k]==0): count = count + 1 triplets.append((tab[i],tab[j],tab[k])) return triplets if name == " main ": import sys import time import random n = int(sys.argv[1]) tab = [] for i in range(n): tab.append(random.randint(-50,50)) t = time.clock() #czas start triplets = counttriplets(tab) t = time.clock() - t #ile trwało? print("%d %f"%(n,t)) Overwriting 3sum_3.py In [35]:!python3 3sum_3.py 10 10 0.000057

In [39]:!for N in 10 20 50 100 200 500 1000; do python3 3sum_3.py $N; done 10 0.000059 20 0.000282 50 0.003865 100 0.025720 200 0.174831 500 2.695456 1000 21.228454 Zamiast wypisywać na ekran, zapiszmy te wyniki do pliku: In [40]:!for N in 10 20 50 100 200 500 1000 2000; do python3 3sum_3.py $N >> wyniki.dat; done In [32]:!cat wyniki.dat 10 0.000066 20 0.000292 50 0.003632 100 0.025550 200 0.173205 500 2.665352 1000 22.351571 2000 171.924855 Krok 3 wykres czasu wykonania w funkcji rozmiaru danych wejściowych In [34]: %matplotlib inline In [36]: import matplotlib.pyplot as plt import numpy as np x,y = np.loadtxt("wyniki.dat",unpack=true) #wczytujemy dane z pliku print(x) print(y) [ 10. 20. 50. 100. 200. 500. 1000. 2000.] [ 6.60000000e-05 2.92000000e-04 3.63200000e-03 2.55500000e-0 2 1.73205000e-01 2.66535200e+00 2.23515710e+01 1.71924855e+0 2]

In [39]: plt.plot(x,y,'ro',label="dane") plt.xlabel("rozmiar") plt.ylabel("czas wykonania") plt.legend(loc='upper left') plt.title("zagadnienie 3SUM metodą brute-force") plt.show() Wykres logarytmiczny powinien być bardziej czytelny:

In [41]: plt.loglog(x,y,'ro',label="dane") plt.xlabel("rozmiar") plt.ylabel("czas wykonania") plt.legend(loc='upper left') plt.title("zagadnienie 3SUM metodą brute-force") plt.show()

Krok 4 hipoteza Spróbujmy teraz przybliżyć dane przedstawione na powyższym wykresie jakąś "prostą" funkcją matematyczną. Ponieważ na wykresie logarytmicznym układają się w linię prostą, spodziewamy się zależności potęgowej: Rzeczywiście, jeśli zlogarytmujemy obustronnie powyższe równanie, otrzymamy czyli równanie prostej. y = ax b log y = b log x + log a Ponadto, algorytm użyty w programie 3sumwykorzystuje potrójne zagnieżdżenie. Dlatego przypuszczamy, że czas jego wykonania będzie proporcjonalny do, gdzie to rozmiar danych wejściowych. N 3 N In [44]: from scipy.optimize import curve_fit def func(x, a, b): return a*x**3 + b popt, pcov = curve_fit(func, x, y) print("a = %s, b = %s" % (popt[0], popt[1])) a = 2.1488626911e-08, b = 0.108065584827 Wynika stąd, że czas wykonania naszego algorytmu spełnia zależność: T(N) = 0.0000000214886 N 3 + 0.108065 Porównajmy dane i funkcję aproksymującą na wykresie:

In [46]: x2 = np.arange(1,2000) plt.plot(x,y,'ro',label="dane") plt.plot(x2, func(x2, *popt), label="hipoteza") plt.xlabel("rozmiar") plt.ylabel("czas wykonania") plt.legend(loc='upper left') plt.title("zagadnienie 3SUM metodą brute-force") plt.show() Krok 5 przewidywanie Interesuje nas, ile będzie wykonywał się program dla np. N = 1200:

In [47]: func(1200,*popt) Out[47]: 37.240412886967256 Krok 6 weryfikacja In [48]:!python3 3sum_3.py 1200 1200 36.325262 Dane empiryczne potwierdzają naszą hipotezę. Hipoteza podwojenia Istnieje sposób na szybkie oszacowanie współczynnika w prawie potęgowym Hipoteza podwojenia (ang. doubling hypothesis) związana jest z próbą odpowiedzi na pytanie: b T(N) = an b Jaki wpływ na czas pracy programu ma podwojenie rozmiaru danych wejściowych? Sposób postępowania: przygotowujemy tabelę, która zawiera 4 kolumny: rozmiar danych N czas wykonania T(N) stosunek czasów wykonania logarytm poprzedniej wielkości, tzn. T(2N)/T(N) log 2 (T(2N)/T(N)) rozmiary wybieramy tak, aby kolejny był dwa razy większy od poprzedniego uruchamiamy program dla tych rozmiarów i mierzymy czasy jego wykonania In [59]:!for N in 16 32 64 128 256 512 1024; do python3 3sum_3.py $N >> podwojenie.dat; done In [61]:!cat podwojenie.dat 16 0.000233 32 0.001232 64 0.007805 128 0.054047 256 0.389704 512 3.221152 1024 24.491979

In [62]: xtab = [] ytab = [] with open("podwojenie.dat") as f: for line in f: x, y = line.split() xtab.append(int(x)) ytab.append(float(y)) In [63]: xtab Out[63]: [16, 32, 64, 128, 256, 512, 1024] In [64]: ytab Out[64]: [0.000233, 0.001232, 0.007805, 0.054047, 0.389704, 3.221152, 24.491 979] In [65]: ratio = [None]*len(ytab) In [66]: ratio Out[66]: [None, None, None, None, None, None, None] In [67]: for i in range(1,len(ytab)): ratio[i] = ytab[i]/ytab[i-1] In [68]: ratio Out[68]: [None, 5.28755364806867, 6.3352272727272725, 6.924663677130044, 7.210464965678021, 8.265637509494386, 7.603484405579122]

In [72]: import math lratio = [None] In [73]: for val in ratio: if val: lratio.append(math.log(val,2)) In [74]: lratio Out[74]: [None, 2.4026003960406213, 2.66339637617037, 2.7917440028413196, 2.8500922944243596, 3.0471260955389763, 2.9266607057458383] In [76]: print("{} \t {} \t {} \t {}".format("n", "T", "Ratio", "Log")) for i in range(len(ytab)): print("{} \t {} \t {} \t {}".format(xtab[i], ytab[i], ratio[i], lratio[i])) N T Ratio Log 16 0.000233 None None 32 0.001232 5.28755364806867 2.4026003960406213 64 0.007805 6.3352272727272725 2.66339637617037 128 0.054047 6.924663677130044 2.7917440028413196 256 0.389704 7.210464965678021 2.8500922944243596 512 3.221152 8.265637509494386 3.0471260955389763 1024 24.491979 7.603484405579122 2.9266607057458383 Kontynuując te obliczenia zobaczylibyśmy, że wartość Wartość stałej czyli a lo g2(t(2n)/t(n)) 3 T(N) = an 3 zbiega do wartości, tzn.: możemy wyznaczyć rozwiązując to równanie dla wybranego rozmiaru danych, np.: 3.221152 = a 512 3 a = 0, 000000024