#!/usr/bin/env python3 """ Program tworzący tablicę N x N i wypełniający ją naprzemiennie (w pionie i poziomie) zerami i jedynkami, w sposób analogiczny do szachownicy. """ import numpy as np import timeit #do pomiaru czasu def naprzemian(N): """ Podejście, w którym do macierzy zerowej dodajemy macierze z jedynkami na kolejnych diagonalach. Na moim PC dla macierzy 2000x2000 czas: ok. 5.6s. Tak długo, bo w każdym kroku tworzona jest i dodawana kolejna duża macierz. """ A=np.zeros((N,N)) for i in range(-N-N%2+2,N,2): A += np.eye(N,k=i) #eye tworzy macierz z jedynkami na k-tej diagonali i zerami wszędzie indziej return A def naprzemian2(N): """ Podejście, w którym tworzymy tablicę 1D z liczbami od 0 do N**2-1, zwijamy ją do macierzy N x N, po czym końcową wartość ustalamy sprytnie wykorzystując dzielenie z resztą. Na moim PC dla macierzy 2000x2000 czas: ok. 0.085s. """ A = np.arange(N*N,dtype=np.float64).reshape((N,N)) #ten dtype jedynie dla zgodności z pozostałymi #A = (A//N + A%N + 1)%2 #to co niżej, ale bardziej explicite A = (sum(divmod(A,N))+1)%2 return A def naprzemian3(N): """ Podejście, w którym "na piechotę" wstawiamy jedynki w co drugie miejsce, zaczynając naprzemiennie od 0 lub 1 pola w wierszu. Na moim PC dla macierzy 2000x2000 czas: ok. 0.11s. """ A = np.zeros((N,N)) for i in range(N): for j in range(i%2,N,2): A[i,j] = 1 return A def naprzemian4(N): """ Podejście, w którym zmieniamy tylko odpowiednie diagonale. Na moim PC dla macierzy 2000x2000 czas: ok. 0.0085s. Najlepszy wynik, o rząd wielkości lepszy niż następna najepsza metoda! Prawdopodobnie dlatego, że odwołujemy się do jak najmniejszej liczby elementów (same diagonale, i to co druga). """ A = np.zeros((N,N)) for i in range(-N-N%2+2,N,2): D = np.diag(A,k=i) D.setflags(write=1) #konieczne, bo domyślnie wynik np.diag jest tylko do odczytu! D[:] = 1 return A def naprzemian5(N): """ Podejście, w którym wykorzystujemy np.fromfunction, które buduje tablicę na podstawie funkcji zależnej od jej indeksów. Użycie lambda bardziej eleganckie, podaję jednak też wersję ze zdefiniowaniem funkcji. Na moim PC dla macierzy 2000x2000 czas: ok. 0.10s. """ #def funkcja(x,y): # return (x%N+y%N+1)%2 #return np.fromfunction(funkcja,(N,N)) return np.fromfunction(lambda x,y:(x%N+y%N+1)%2,(N,N)) print(naprzemian4(8)) #wywołuję funkcję 10 razy i dzielę całkowity czas przez 10 - by ograniczyć wpływ anomalii #UWAGA: przez to wersja z pierwszą funkcją może wykonywać się dość długo print(timeit.timeit(lambda: naprzemian4(2000),number=10)/10)