diff --git a/b_asic/gui_utils/__init__.py b/b_asic/gui_utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/b_asic/research/__init__.py b/b_asic/research/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/b_asic/research/interleaver.py b/b_asic/research/interleaver.py
new file mode 100644
index 0000000000000000000000000000000000000000..83eb4b3bb415c81bb767e0e6dcd1d124d536e589
--- /dev/null
+++ b/b_asic/research/interleaver.py
@@ -0,0 +1,112 @@
+"""
+Functions to generate memory-variable test data that are used for research.
+"""
+
+import random
+from typing import Optional, Set
+
+from b_asic.process import PlainMemoryVariable
+
+
+def _insert_delays(inputorder, outputorder, min_lifetime, cyclic):
+    size = len(inputorder)
+    maxdiff = min(outputorder[i] - inputorder[i] for i in range(size))
+    outputorder = [o - maxdiff + min_lifetime for o in outputorder]
+    maxdelay = max(outputorder[i] - inputorder[i] for i in range(size))
+    if cyclic:
+        if maxdelay < size:
+            outputorder = [o % size for o in outputorder]
+        else:
+            inputorder = inputorder + [i + size for i in inputorder]
+            outputorder = outputorder + [o + size for o in outputorder]
+    return inputorder, outputorder
+
+
+def generate_random_interleaver(
+    size: int, min_lifetime: int = 0, cyclic: bool = True
+) -> Set[PlainMemoryVariable]:
+    """
+    Generate a ProcessCollection with memory variable corresponding to a random
+    interleaver with length *size*.
+
+    Parameters
+    ----------
+    size : int
+        The size of the random interleaver sequence.
+    min_lifetime : int, default: 0
+        The minimum lifetime for a memory variable. Default is 0 meaning that at least
+        one variable is passed from the input to the output directly,
+    cyclic : bool, default: True
+        If the interleaver should operate continuously in a cyclic manner. That is,
+        start a new interleaving operation directly after the previous.
+
+    Returns
+    -------
+        ProcessCollection
+
+    """
+    inputorder = list(range(size))
+    outputorder = inputorder[:]
+    random.shuffle(outputorder)
+    print(inputorder, outputorder)
+    inputorder, outputorder = _insert_delays(
+        inputorder, outputorder, min_lifetime, cyclic
+    )
+    print(inputorder, outputorder)
+    return {
+        PlainMemoryVariable(inputorder[i], 0, {0: outputorder[i]})
+        for i in range(size)
+    }
+
+
+def generate_matrix_transposer(
+    height: int,
+    width: Optional[int] = None,
+    min_lifetime: int = 0,
+    cyclic: bool = True,
+) -> Set[PlainMemoryVariable]:
+    r"""
+    Generate a ProcessCollection with memory variable corresponding to transposing a
+    matrix of size *height* :math:`\times` *width*. If *width* is not provided, a
+    square matrix of size *height* :math:`\times` *height* is used.
+
+    Parameters
+    ----------
+    height : int
+        Matrix height.
+    width : int, optional
+        Matrix width. If not provided assumed to be equal to height, i.e., a square
+        matrix.
+    min_lifetime : int, default: 0
+        The minimum lifetime for a memory variable. Default is 0 meaning that at
+        least one variable is passed from the input to the output directly,
+    cyclic : bool, default: True
+        If the interleaver should operate continuously in a cyclic manner. That is,
+        start a new interleaving operation directly after the previous.
+
+    Returns
+    -------
+        ProcessCollection
+    """
+    if width is None:
+        width = height
+
+    inputorder = []
+    for row in range(height):
+        for col in range(width):
+            inputorder.append(col + width * row)
+
+    outputorder = []
+    for row in range(width):
+        for col in range(height):
+            outputorder.append(col * width + row)
+
+    print(inputorder, outputorder)
+    inputorder, outputorder = _insert_delays(
+        inputorder, outputorder, min_lifetime, cyclic
+    )
+    print(inputorder, outputorder)
+    return {
+        PlainMemoryVariable(inputorder[i], 0, {0: outputorder[i]})
+        for i in range(width * height)
+    }
diff --git a/docs_sphinx/Makefile b/docs_sphinx/Makefile
index a5036b7aae1767750445666bc41d5c4c495b3c11..1bede10d4c691064a14a196b5a7d13ab23b919ca 100644
--- a/docs_sphinx/Makefile
+++ b/docs_sphinx/Makefile
@@ -20,7 +20,7 @@ clean:
 	rm -rf "$(SOURCEDIR)/examples"
 
 show:
-	@python -c "import webbrowser; webbrowser.open_new_tab('file://$(shell pwd)/build/html/index.html')"
+	@python -c "import webbrowser; webbrowser.open_new_tab('file://$(shell pwd)/_build/html/index.html')"
 
 # Catch-all target: route all unknown targets to Sphinx using the new
 # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
diff --git a/docs_sphinx/gui_utils.rst b/docs_sphinx/gui_utils.rst
new file mode 100644
index 0000000000000000000000000000000000000000..2396b29cd4565df5be5043e05417ced43a893285
--- /dev/null
+++ b/docs_sphinx/gui_utils.rst
@@ -0,0 +1,9 @@
+gui\_utils package
+==================
+
+gui\_utils.about\_window module
+-------------------------------
+
+.. automodule:: b_asic.gui_utils.about_window
+   :members:
+   :undoc-members:
diff --git a/docs_sphinx/index.rst b/docs_sphinx/index.rst
index 9ebbd2b451078b509aed29f7ed6cb37c5abdb519..3242ce5459d5104f5088e7887bc86b16966352e3 100644
--- a/docs_sphinx/index.rst
+++ b/docs_sphinx/index.rst
@@ -28,4 +28,6 @@ Table of Contents
    api/index
    GUI
    scheduler_gui
+   gui_utils
    examples/index
+   research
diff --git a/docs_sphinx/research.rst b/docs_sphinx/research.rst
new file mode 100644
index 0000000000000000000000000000000000000000..e64712dfe5122b09d0338f7109fff34958e2dd7e
--- /dev/null
+++ b/docs_sphinx/research.rst
@@ -0,0 +1,9 @@
+Research functions
+==================
+
+research.interleaver module
+---------------------------
+
+.. automodule:: b_asic.research.interleaver
+   :members:
+   :undoc-members: