<jupyter_start><jupyter_text>Basic Example Vector AdditionAdd a fixed value to an array with numbers in the range [0..99].The example uses the vector addition kernel included in the [hello world](https://github.com/Xilinx/Vitis_Accel_Examples/tree/63bae10d581df40cf9402ed71ea825476751305d/hello_world) application of the [Vitis Accel Examples' Repository](https://github.com/Xilinx/Vitis_Accel_Examples/tree/63bae10d581df40cf9402ed71ea825476751305d).![vadd](img/vadd.png "Vector Addition")See below for a [breakdown of the code](Step-by-step-walkthrough-of-the-example).<jupyter_code>import pynq
import numpy as np

# program the device
ol = pynq.Overlay("intro.xclbin")
vadd = ol.vadd_1

# allocate buffers
size = 1024*1024
in1_vadd = pynq.allocate((1024, 1024), np.uint32)
in2_vadd = pynq.allocate((1024, 1024), np.uint32)
out = pynq.allocate((1024, 1024), np.uint32)

# initialize input
in1_vadd[:] = np.random.randint(low=0, high=100, size=(1024, 1024), dtype=np.uint32)
in2_vadd[:] = 200

# send data to the device
in1_vadd.sync_to_device()
in2_vadd.sync_to_device()

# call kernel
vadd.call(in1_vadd, in2_vadd, out, size)

# get data from the device
out.sync_from_device()

# check results
msg = "SUCCESS!" if np.array_equal(out, in1_vadd + in2_vadd) else "FAILURE!"
print(msg)

# clean up
del in1_vadd
del in2_vadd
del out
ol.free()<jupyter_output><empty_output><jupyter_text>Step-by-step walkthrough of the example Overlay downloadFirst, let's import `pynq`, download the overlay, and assign the vadd kernel IP to a variable called `vadd`.<jupyter_code>import pynq
ol = pynq.Overlay("intro.xclbin")

vadd = ol.vadd_1<jupyter_output><empty_output><jupyter_text>Buffers allocationLet's first take a look at the signature of the vadd kernel. To do so, we use the `.signature` property. The accelerator takes two input vectors, the output vector, and the vectors' size as arguments<jupyter_code>vadd.signature<jupyter_output><empty_output><jupyter_text>Data types in the signature that have the *pointer* (`*`) qualifier represent *buffers* that must be allocated in memory. Non-pointer data types represent registers and are set directly when the kernel is executed with `.call()`.Buffers allocation is carried by [`pynq.allocate`](https://pynq.readthedocs.io/en/v2.5/pynq_libraries/allocate.html), which provides the same interface as a [`numpy.ndarray`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html). The `numpy.ndarray` constructor represents the low-level API to instantiate multidimensional arrays in NumPy. ```pythonimport numpy as npfoo = np.ndarray(shape=(10,), dtype=int)```The `pynq.allocate` API provides a buffer object that can be used to interact with both host and device buffers. Host and FPGA buffers here are transparently managed, and the user is only presented with a single interface for both. The user is only asked to explicitly sync host and FPGA buffers before and after a kernel call through the `.sync_to_device()` and `.sync_from_device()` API, as will be shown later. If you are familiar with the PYNQ embedded API `sync_to_device` and `sync_from_device` are the mirrored buffer equivalent to `flush` and `invalidate` functions used for cache-coherent buffers.In this case we're going to create 3 1024x1024 arrays, two input and one output. Since the kernel uses unsigned integers we specify `u4` as data type when performing allocation, which is shorthand for `numpy.uint32`, as explained in the [`numpy.dtypes`](https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.htmlarrays-dtypes) documentation.<jupyter_code>size = 1024*1024
in1_vadd = pynq.allocate((1024, 1024), 'u4')
in2_vadd = pynq.allocate((1024, 1024), 'u4')
out = pynq.allocate((1024, 1024), 'u4')<jupyter_output><empty_output><jupyter_text>We can use numpy to easily initialize one of the input arrays with random data, with numbers in the range [0, 100). We instead set all the elements of the second input array to a fixed value so we can see at a glance whether the addition was successful.<jupyter_code>import numpy as np
in1_vadd[:] = np.random.randint(low=0, high=100, size=(1024, 1024), dtype='u4')
in2_vadd[:] = 200<jupyter_output><empty_output><jupyter_text>Run the kernelBefore we can start the kernel we need to make sure that the buffers are synced to the FPGA card. We do this by calling `.sync_to_device()` on each of our input arrays.To start the accelerator, we can use the `.call()` function and pass the kernel arguments. The function will take care of correctly setting the `register_map` of the IP and send the start signal. We pass the arguments to `.call()` following the `.signature` we previously inspected.Once the kernel has completed, we can `.sync_from_device()` the output buffer to ensure that data from the FPGA is transferred back to the host memory.We use the `%%timeit` magic to get the average execution time. This magic will automatically decide how many runs to perform to get a reliable average.<jupyter_code>%%timeit
in1_vadd.sync_to_device()
in2_vadd.sync_to_device()

vadd.call(in1_vadd, in2_vadd, out, size)

out.sync_from_device()<jupyter_output>17.5 ms ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)<jupyter_text>Finally, let's compare the FPGA results with software, using [`numpy.array_equal`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.array_equal.html)<jupyter_code>np.array_equal(out, in1_vadd + in2_vadd)<jupyter_output><empty_output><jupyter_text>Cleaning upFinally, we have to deallocate the buffers and free the FPGA context using `Overlay.free`.In case buffers are used as output of a cell, we will have to use the [`%xdel`](https://ipython.readthedocs.io/en/stable/interactive/magics.htmlmagic-xdel) magic to also remove any reference to these buffers in Jupyter/IPython. IPython holds on to references of cell outputs so a standard `del` isn’t sufficient to remove all references to the array and hence trigger the memory to be freed.The same effect can also be achieved by *shutting down* the notebook.<jupyter_code>%xdel in1_vadd
%xdel in2_vadd
%xdel out
ol.free()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09421000981354269, 'fraction_numerical': 0.035819430814524045, 'mean_word_length': 5.727172717271727, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 32, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '14173', 'license': 'Apache-2.0', 'n_tokens_mistral': 2114, 'n_tokens_neox': 1930, 'n_words': 700, 'path': 'pynq_alveo_examples/notebooks/1_introduction/1-vector-addition.ipynb', 'repo_name': 'PeterOgden/Alveo-PYNQ', 'size': '6114'}