<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Instructions
Work on a copy of this notebook
Step1:  Now, let's create and test a pipeline
Step2:  Let's first create a simple CUDA kernel within Bifrost.
We will generate 1000 integers, feed them into Bifrost as a CUDA array, perform a kernel operation x * 3, then copy them back.
Step6:  Now, let's generate a full pipeline
<ASSISTANT_TASK:>
Python Code:
# @title Install C++ deps
%%shell
sudo apt-get -qq install exuberant-ctags libopenblas-dev software-properties-common build-essential
# @title Install python deps
%%shell
pip install -q contextlib2 pint simplejson ctypesgen==1.0.2
# @title Build and Install Bifrost
%%shell
cd "${HOME}"
if [ -d "${HOME}/bifrost_repo" ]; then
    echo "Already cloned."
else
    git clone https://github.com/ledatelescope/bifrost bifrost_repo
fi
cd "${HOME}/bifrost_repo"
git pull --all
./configure
# Build and install:
make -j all
sudo make install
export LD_LIBRARY_PATH=/usr/local/lib:${LD_LIBRARY_PATH}
Explanation: Instructions
Work on a copy of this notebook: File > Save a copy in Drive (you will need a Google account). Alternatively, you can download the notebook using File > Download .ipynb, then upload it to Colab.
Turn on the GPU with Edit->Notebook settings->Hardware accelerator->GPU
Execute the following cell (click on it and press Ctrl+Enter) to install dependencies.
Continue to the next section.
Notes:
* If your Colab Runtime gets reset (e.g., due to inactivity), repeat steps 3, 4.
* After installation, if you want to activate/deactivate the GPU, you will need to reset the Runtime: Runtime > Factory reset runtime and repeat steps 2-4.
End of explanation
import os
# Environment path doesn't propagate, so add it manually:
if "/usr/local/lib" not in os.environ['LD_LIBRARY_PATH']:
    os.environ['LD_LIBRARY_PATH'] += ":/usr/local/lib"
import bifrost as bf
import numpy as np
Explanation: Now, let's create and test a pipeline:
End of explanation
x = np.random.randint(256, size=1000)
x_orig = x
x = bf.asarray(x, 'cuda')
y = bf.empty_like(x)
x.flags['WRITEABLE'] = False
x.bf.immutable = True
for _ in range(3):
    bf.map("y = x * 3", {'x': x, 'y': y})
x = x.copy('system')
y = y.copy('system')
if isinstance(x_orig, bf.ndarray):
    x_orig = x
np.testing.assert_equal(y, x_orig * 3)
Explanation: Let's first create a simple CUDA kernel within Bifrost.
We will generate 1000 integers, feed them into Bifrost as a CUDA array, perform a kernel operation x * 3, then copy them back.
End of explanation
from bifrost.block import Pipeline, NumpyBlock, NumpySourceBlock
def generate_different_arrays():
    Yield four different groups of two arrays
    dtypes = ['float32', 'float64', 'complex64', 'int8']
    shapes = [(4,), (4, 5), (4, 5, 6), (2,) * 8]
    for array_index in range(4):
        yield np.ones(
            shape=shapes[array_index],
            dtype=dtypes[array_index])
        yield 2 * np.ones(
            shape=shapes[array_index],
            dtype=dtypes[array_index])
def switch_types(array):
    Return two copies of the array, one with a different type
    return np.copy(array), np.copy(array).astype(np.complex128)
occurences = 0
def compare_arrays(array1, array2):
    Make sure that all arrays coming in are equal
    global occurences
    occurences += 1
    np.testing.assert_almost_equal(array1, array2)
blocks = [
    (NumpySourceBlock(generate_different_arrays), {'out_1': 0}),
    (NumpyBlock(switch_types, outputs=2), {'in_1': 0, 'out_1': 1, 'out_2': 2}),
    (NumpyBlock(np.fft.fft), {'in_1': 2, 'out_1': 3}),
    (NumpyBlock(np.fft.ifft), {'in_1': 3, 'out_1': 4}),
    (NumpyBlock(compare_arrays, inputs=2, outputs=0), {'in_1': 1, 'in_2': 4})]
Pipeline(blocks).main()
# The function `compare_arrays` should be hit 8 times:
assert occurences == 8
Explanation: Now, let's generate a full pipeline:
End of explanation
<END_TASK>