load test

This commit is contained in:
Daniel Tsvetkov 2019-12-05 11:00:34 +01:00
parent de00aaac47
commit c2ee459ec7
9 changed files with 21487 additions and 5 deletions

Binary file not shown.

0
ckron/__init__.py Normal file
View File

2
ckron/build.sh Executable file
View File

@ -0,0 +1,2 @@
cython cythkrn.pyx
python3 setup.py build

21320
ckron/cythkrn.c Normal file

File diff suppressed because it is too large Load Diff

20
ckron/cythkrn.pyx Normal file
View File

@ -0,0 +1,20 @@
import cython
cimport scipy.linalg.cython_blas as blas
import numpy as np
@cython.boundscheck(False)
@cython.wraparound(False)
def kron(double[:, ::1] a, double[:, ::1] b):
cdef int i = a.shape[0]
cdef int j = a.shape[1]
cdef int k = b.shape[0]
cdef int l = b.shape[1]
cdef int onei = 1
cdef double oned = 1
cdef int m, n
result = np.zeros((i*k, j*l), float)
cdef double[:, ::1] result_v = result
for n in range(i):
for m in range(k):
blas.dger(&l, &j, &oned, &b[m, 0], &onei, &a[n, 0], &onei, &result_v[m+k*n, 0], &l)
return result

5
ckron/setup.py Normal file
View File

@ -0,0 +1,5 @@
from distutils.core import setup
from Cython.Build import cythonize
setup(name='kronecker',
ext_modules=cythonize("cythkrn.pyx"))

View File

@ -1,15 +1,20 @@
import random
import numpy as np
import pyximport
from numba import jit
pyximport.install()
from ckron import cythkrn
# Raw matrixes to be used for initialization of qubits and gates
# |0> and |1>
__0 = [[1],
[0]]
__0 = [[1.],
[0.]]
__1 = [[0],
[1]]
__1 = [[0.],
[1.]]
# |+> and |->
__p = [[1 / np.sqrt(2)],
@ -107,6 +112,7 @@ class State(object):
return random.choices(choices, weights)[0]
@jit()
def kron(_list):
"""Calculates a Kronicker product of a list of matrices
This is essentially a np.kron(*args) since np.kron takes (a,b)"""
@ -114,7 +120,9 @@ def kron(_list):
return np.array([])
rv = np.array(_list[0])
for item in _list[1:]:
rv = np.kron(rv, item)
# rv = np.kron(rv, item)
# TODO: Further optimization with cython - but right now it takes a double only
rv = cythkrn.kron(rv, item)
return rv

127
load_test.py Normal file
View File

@ -0,0 +1,127 @@
from sys import getsizeof
from time import time
import numpy as np
import pyximport
from lib_q_computer import Qubit, __0, kron
pyximport.install()
def sizeof_fmt(num, suffix='B'):
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
def run_load_test(N=20):
"""
Runs a load test with max N qubits (up to and including N).
Expectation is that on a 8GB laptop I should be able to run about 30 qubits using 8-byte numbers.
(2**30 * 8 ) / 1024**3 = 8.0
Example run output with N=27 on 64GB machine **(without jit)**
qbits kron_len mem_used mem_per_q getsizeof getsiz/len nbytes nbytes/len time
2 4 0.0B 0.0B 144.0B 36.0B 32.0B 8.0B 0.0
3 8 0.0B 0.0B 176.0B 22.0B 64.0B 8.0B 0.0
4 16 0.0B 0.0B 240.0B 15.0B 128.0B 8.0B 0.0
5 32 0.0B 0.0B 368.0B 11.5B 256.0B 8.0B 0.0
6 64 0.0B 0.0B 624.0B 9.8B 512.0B 8.0B 0.0
7 128 0.0B 0.0B 1.1KiB 8.9B 1.0KiB 8.0B 0.0
8 256 0.0B 0.0B 2.1KiB 8.4B 2.0KiB 8.0B 0.0
9 512 312.0KiB 624.0B 4.1KiB 8.2B 4.0KiB 8.0B 0.0
10 1024 312.0KiB 312.0B 8.1KiB 8.1B 8.0KiB 8.0B 0.0
11 2048 312.0KiB 156.0B 16.1KiB 8.1B 16.0KiB 8.0B 0.0
12 4096 816.0KiB 204.0B 32.1KiB 8.0B 32.0KiB 8.0B 0.0
13 8192 1.2MiB 150.5B 64.1KiB 8.0B 64.0KiB 8.0B 0.01
14 16384 1.9MiB 123.5B 128.1KiB 8.0B 128.0KiB 8.0B 0.01
15 32768 3.4MiB 110.1B 256.1KiB 8.0B 256.0KiB 8.0B 0.02
16 65536 6.5MiB 103.3B 512.1KiB 8.0B 512.0KiB 8.0B 0.04
17 131072 11.5MiB 91.9B 1.0MiB 8.0B 1.0MiB 8.0B 0.08
18 262144 22.6MiB 90.2B 2.0MiB 8.0B 2.0MiB 8.0B 0.18
19 524288 44.7MiB 89.4B 4.0MiB 8.0B 4.0MiB 8.0B 0.32
20 1048576 88.9MiB 88.9B 8.0MiB 8.0B 8.0MiB 8.0B 0.66
21 2097152 177.5MiB 88.7B 16.0MiB 8.0B 16.0MiB 8.0B 1.31
22 4194304 354.5MiB 88.6B 32.0MiB 8.0B 32.0MiB 8.0B 2.67
23 8388608 676.6MiB 84.6B 64.0MiB 8.0B 64.0MiB 8.0B 5.26
24 16777216 1.3GiB 84.5B 128.0MiB 8.0B 128.0MiB 8.0B 10.59
25 33554432 2.6GiB 84.5B 256.0MiB 8.0B 256.0MiB 8.0B 21.3
26 67108864 5.3GiB 84.5B 512.0MiB 8.0B 512.0MiB 8.0B 41.81
27 134217728 10.6GiB 84.5B 1.0GiB 8.0B 1.0GiB 8.0B 83.76
TODO: Understand numby.jit magic (look at the results differences > 20qbits, mem usage /10; time /4)
...
20 1048576 39.7MiB 39.7B 112.0B 0.0B 8.0MiB 8.0B 0.16
21 2097152 51.7MiB 25.9B 112.0B 0.0B 16.0MiB 8.0B 0.33
22 4194304 75.7MiB 18.9B 112.0B 0.0B 32.0MiB 8.0B 0.63
23 8388608 123.7MiB 15.5B 112.0B 0.0B 64.0MiB 8.0B 1.26
24 16777216 187.7MiB 11.7B 112.0B 0.0B 128.0MiB 8.0B 2.51
25 33554432 315.7MiB 9.9B 112.0B 0.0B 256.0MiB 8.0B 5.05
26 67108864 571.7MiB 8.9B 112.0B 0.0B 512.0MiB 8.0B 10.05
27 134217728 1.1GiB 8.5B 112.0B 0.0B 1.0GiB 8.0B 19.86
28 268435456 2.1GiB 8.2B 112.0B 0.0B 2.0GiB 8.0B 40.79
29 536870912 4.1GiB 8.1B 112.0B 0.0B 4.0GiB 8.0B 81.07
30 1073741824 8.1GiB 8.1B 112.0B 0.0B 8.0GiB 8.0B 161.68
...
Also together with cython optimization (time /4) (but right now it seems to take only doubles):
...
20 1048576 23.7MiB 23.7B 8.0MiB 8.0B 8.0MiB 8.0B 0.04
21 2097152 35.7MiB 17.8B 16.0MiB 8.0B 16.0MiB 8.0B 0.08
22 4194304 59.7MiB 14.9B 32.0MiB 8.0B 32.0MiB 8.0B 0.15
23 8388608 107.7MiB 13.5B 64.0MiB 8.0B 64.0MiB 8.0B 0.3
24 16777216 171.7MiB 10.7B 128.0MiB 8.0B 128.0MiB 8.0B 0.59
25 33554432 299.7MiB 9.4B 256.0MiB 8.0B 256.0MiB 8.0B 1.18
26 67108864 555.7MiB 8.7B 512.0MiB 8.0B 512.0MiB 8.0B 2.35
27 134217728 1.0GiB 8.3B 1.0GiB 8.0B 1.0GiB 8.0B 4.7
28 268435456 2.0GiB 8.2B 2.0GiB 8.0B 2.0GiB 8.0B 9.52
29 536870912 4.0GiB 8.1B 4.0GiB 8.0B 4.0GiB 8.0B 19.32
30 1073741824 8.0GiB 8.0B 8.0GiB 8.0B 8.0GiB 8.0B 37.76
"""
_0 = Qubit(__0)
import os
import psutil
import gc
print("{:>10} {:>10} {:>10} {:>10} {:>10} {:>10} {:>10} {:>10} {:>10}".format(
"qbits",
"kron_len",
"mem_used",
"mem_per_q",
"getsizeof",
"getsiz/len",
"nbytes",
"nbytes/len",
"time"))
process = psutil.Process(os.getpid())
mem_init = process.memory_info().rss
for i in range(2, N + 1):
start = time()
qbits = [_0.matrix_state for _ in range(i)]
m = kron(qbits)
len_m = len(m)
elapsed = time() - start
mem_b = process.memory_info().rss - mem_init
print("{:>10} {:>10} {:>10} {:>10} {:>10} {:>10} {:>10} {:>10} {:>10}".format(
i,
len(m),
sizeof_fmt(mem_b),
sizeof_fmt(mem_b / len_m),
sizeof_fmt(getsizeof(m)),
sizeof_fmt(getsizeof(m) / len_m),
sizeof_fmt(m.nbytes),
sizeof_fmt(m.nbytes / len_m),
np.round(elapsed, 2)))
gc.collect()
if __name__ == "__main__":
run_load_test(30)