diff --git a/b_asic/architecture.py b/b_asic/architecture.py
index 2a9a6074cafff63261b5ab6da1c522c3f6083511..d675dded72de660e28c2dd445229d6d00e50b2a9 100644
--- a/b_asic/architecture.py
+++ b/b_asic/architecture.py
@@ -3,7 +3,18 @@ B-ASIC architecture classes.
 """
 from collections import defaultdict
 from io import TextIOWrapper
-from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple, Union, cast
+from typing import (
+    DefaultDict,
+    Dict,
+    Iterable,
+    Iterator,
+    List,
+    Optional,
+    Set,
+    Tuple,
+    Union,
+    cast,
+)
 
 import matplotlib.pyplot as plt
 from graphviz import Digraph
@@ -30,11 +41,11 @@ class HardwareBlock:
     """
 
     def __init__(self, entity_name: Optional[str] = None):
-        self._entity_name = None
+        self._entity_name: Optional[str] = None
         if entity_name is not None:
             self.set_entity_name(entity_name)
 
-    def set_entity_name(self, entity_name: str):
+    def set_entity_name(self, entity_name: str) -> None:
         """
         Set entity name of hardware block.
 
@@ -44,7 +55,7 @@ class HardwareBlock:
             The entity name.
         """
         if not is_valid_vhdl_identifier(entity_name):
-            raise ValueError(f'{entity_name} is not a valid VHDL indentifier')
+            raise ValueError(f'{entity_name} is not a valid VHDL identifier')
         self._entity_name = entity_name
 
     def write_code(self, path: str) -> None:
@@ -56,7 +67,7 @@ class HardwareBlock:
         path : str
             Directory to write code in.
         """
-        if not self.entity_name:
+        if not self._entity_name:
             raise ValueError("Entity name must be set")
         raise NotImplementedError
 
@@ -173,16 +184,41 @@ class Resource(HardwareBlock):
         # doc-string inherited
         return self._collection.schedule_time
 
-    def plot_content(self, ax: plt.Axes) -> None:
+    def plot_content(self, ax: plt.Axes, **kwargs) -> None:
+        """
+        Plot the content of the resource.
+
+        This plots the assigned processes executed on this resource.
+
+        Parameters
+        ----------
+        ax : Axes
+            Matplotlib Axes to plot in.
+        **kwargs
+            Passed to :meth:`b_asic.resources.ProcessCollection.plot`
+        """
         if not self.is_assigned:
-            self._collection.plot(ax)
+            self._collection.plot(ax, **kwargs)
         else:
             for i, pc in enumerate(self._assignment):  # type: ignore
-                pc.plot(ax=ax, row=i)
+                pc.plot(ax=ax, row=i, **kwargs)
 
-    def show_content(self):
+    def show_content(self, title=None, **kwargs) -> None:
+        """
+        Display the content of the resource.
+
+        This displays the assigned processes executed on this resource.
+
+        Parameters
+        ----------
+        title : str, optional
+        **kwargs
+            Passed to :meth:`b_asic.resources.ProcessCollection.plot`
+        """
         fig, ax = plt.subplots()
-        self.plot_content(ax)
+        self.plot_content(ax, **kwargs)
+        if title:
+            fig.suptitle(title)
         fig.show()  # type: ignore
 
     @property
@@ -201,6 +237,10 @@ class Resource(HardwareBlock):
         self.plot_content(ax)
         return fig
 
+    @property
+    def collection(self) -> ProcessCollection:
+        return self._collection
+
 
 class ProcessingElement(Resource):
     """
@@ -233,10 +273,8 @@ class ProcessingElement(Resource):
         op_type = type(ops[0])
         if not all(isinstance(op, op_type) for op in ops):
             raise TypeError("Different Operation types in ProcessCollection")
-        self._collection = process_collection
         self._operation_type = op_type
         self._type_name = op_type.type_name()
-        self._entity_name = entity_name
         self._input_count = ops[0].input_count
         self._output_count = ops[0].output_count
         self._assignment = list(
@@ -246,8 +284,8 @@ class ProcessingElement(Resource):
             raise ValueError("Cannot map ProcessCollection to single ProcessingElement")
 
     @property
-    def processes(self) -> Set[OperatorProcess]:
-        return {cast(OperatorProcess, p) for p in self._collection}
+    def processes(self) -> List[OperatorProcess]:
+        return [cast(OperatorProcess, p) for p in self._collection]
 
 
 class Memory(Resource):
@@ -322,6 +360,27 @@ class Memory(Resource):
             self._collection.split_on_execution_time(heuristic=heuristic)
         )
 
+    def assign(self, heuristic: str = "left_edge") -> None:
+        """
+        Perform assignment of the memory variables.
+
+        Parameters
+        ----------
+        heuristic : str
+            The assignment algorithm. Depending on memory type the following are
+            available:
+
+                * 'RAM'
+                    * 'left_edge': Left-edge algorithm.
+                    * 'graph_color': Graph-coloring based on exclusion graph.
+                * 'register'
+                    * ...
+        """
+        if self._memory_type == "RAM":
+            self._assign_ram(heuristic=heuristic)
+        else:  # "register"
+            raise NotImplementedError()
+
 
 class Architecture(HardwareBlock):
     """
@@ -350,11 +409,11 @@ of :class:`~b_asic.architecture.ProcessingElement`
     ):
         super().__init__(entity_name)
         self._processing_elements = (
-            set(processing_elements)
+            [processing_elements]
             if isinstance(processing_elements, ProcessingElement)
-            else processing_elements
+            else list(processing_elements)
         )
-        self._memories = set(memories) if isinstance(memories, Memory) else memories
+        self._memories = [memories] if isinstance(memories, Memory) else list(memories)
         self._direct_interconnects = direct_interconnects
         self._variable_inport_to_resource: Dict[InputPort, Tuple[Resource, int]] = {}
         self._variable_outport_to_resource: Dict[OutputPort, Tuple[Resource, int]] = {}
@@ -380,7 +439,7 @@ of :class:`~b_asic.architecture.ProcessingElement`
             raise ValueError(f"Different schedule times: {schedule_times}")
         return schedule_times.pop()
 
-    def _build_dicts(self):
+    def _build_dicts(self) -> None:
         for pe in self.processing_elements:
             for operator in pe.processes:
                 for input_port in operator.operation.inputs:
@@ -406,7 +465,7 @@ of :class:`~b_asic.architecture.ProcessingElement`
                         read_port.index,
                     )
 
-    def validate_ports(self):
+    def validate_ports(self) -> None:
         # Validate inputs and outputs of memory variables in all the memories in this
         # architecture
         memory_read_ports = set()
@@ -442,7 +501,9 @@ of :class:`~b_asic.architecture.ProcessingElement`
             )
         # Make sure all inputs and outputs in the architecture are in use
 
-    def get_interconnects_for_memory(self, mem: Memory):
+    def get_interconnects_for_memory(
+        self, mem: Memory
+    ) -> Tuple[Dict[Resource, int], Dict[Resource, int]]:
         """
         Return a dictionary with interconnect information for a Memory.
 
@@ -457,9 +518,9 @@ of :class:`~b_asic.architecture.ProcessingElement`
             A dictionary with the ProcessingElements that are connected to the write and
             read ports, respectively, with counts of the number of accesses.
         """
-        d_in = defaultdict(_interconnect_dict)
-        d_out = defaultdict(_interconnect_dict)
-        for var in mem._collection:
+        d_in: DefaultDict[Resource, int] = defaultdict(_interconnect_dict)
+        d_out: DefaultDict[Resource, int] = defaultdict(_interconnect_dict)
+        for var in mem.collection:
             var = cast(MemoryVariable, var)
             d_in[self._operation_outport_to_resource[var.write_port]] += 1
             for read_port in var.read_ports:
@@ -490,21 +551,23 @@ of :class:`~b_asic.architecture.ProcessingElement`
             frequency of accesses.
 
         """
-        ops = cast(List[OperatorProcess], list(pe._collection))
-        d_in = [defaultdict(_interconnect_dict) for _ in ops[0].operation.inputs]
-        d_out = [defaultdict(_interconnect_dict) for _ in ops[0].operation.outputs]
-        for var in pe._collection:
+        d_in: List[DefaultDict[Tuple[Resource, int], int]] = [
+            defaultdict(_interconnect_dict) for _ in range(pe.input_count)
+        ]
+        d_out: List[DefaultDict[Tuple[Resource, int], int]] = [
+            defaultdict(_interconnect_dict) for _ in range(pe.output_count)
+        ]
+        for var in pe.collection:
             var = cast(OperatorProcess, var)
-            for i, input in enumerate(var.operation.inputs):
-                d_in[i][self._variable_inport_to_resource[input]] += 1
+            for i, input_ in enumerate(var.operation.inputs):
+                d_in[i][self._variable_inport_to_resource[input_]] += 1
             for i, output in enumerate(var.operation.outputs):
                 d_out[i][self._variable_outport_to_resource[output]] += 1
         return [dict(d) for d in d_in], [dict(d) for d in d_out]
 
     def _digraph(self) -> Digraph:
-        edges = set()
+        edges: Set[Tuple[str, str, str]] = set()
         dg = Digraph(node_attr={'shape': 'record'})
-        # dg.attr(rankdir="LR")
         for i, mem in enumerate(self._memories):
             dg.node(mem.entity_name, mem._struct_def())
         for i, pe in enumerate(self._processing_elements):
@@ -520,8 +583,8 @@ of :class:`~b_asic.architecture.ProcessingElement`
                             f"{cnt}",
                         )
                     )
-            for o, outp in enumerate(outputs):
-                for (dest, port), cnt in outp.items():
+            for o, output in enumerate(outputs):
+                for (dest, port), cnt in output.items():
                     edges.add(
                         (
                             f"{pe.entity_name}:out{o}",
@@ -529,16 +592,16 @@ of :class:`~b_asic.architecture.ProcessingElement`
                             f"{cnt}",
                         )
                     )
-        for src, dest, cnt in edges:
-            dg.edge(src, dest, label=cnt)
+        for src_str, dest_str, cnt_str in edges:
+            dg.edge(src_str, dest_str, label=cnt_str)
         return dg
 
     @property
-    def memories(self) -> Iterable[Memory]:
+    def memories(self) -> List[Memory]:
         return self._memories
 
     @property
-    def processing_elements(self) -> Iterable[ProcessingElement]:
+    def processing_elements(self) -> List[ProcessingElement]:
         return self._processing_elements
 
     @property
diff --git a/docs_sphinx/conf.py b/docs_sphinx/conf.py
index f8148bc4a1b069a0368a746ed085dce0147a851f..7f335128f716a8eb2c9ad8ff62e68b698f909c50 100644
--- a/docs_sphinx/conf.py
+++ b/docs_sphinx/conf.py
@@ -8,7 +8,7 @@
 
 import shutil
 
-import qtgallery
+# import qtgallery
 
 project = 'B-ASIC'
 copyright = '2020-2023, Oscar Gustafsson et al'
@@ -28,7 +28,7 @@ extensions = [
     'sphinx_gallery.gen_gallery',
     'numpydoc',  # Needs to be loaded *after* autodoc.
     'jupyter_sphinx',
-    'qtgallery',
+    #    'qtgallery',
 ]
 
 templates_path = ['_templates']
@@ -71,11 +71,11 @@ sphinx_gallery_conf = {
     'doc_module': ('b_asic',),
     'reference_url': {'b_asic': None},
     'image_scrapers': (
-        qtgallery.qtscraper,
+        #    qtgallery.qtscraper,
         'matplotlib',
     ),
     'reset_modules': (
-        qtgallery.reset_qapp,
+        #    qtgallery.reset_qapp,
         'matplotlib',
     ),
 }
diff --git a/examples/secondorderdirectformiir_architecture.py b/examples/secondorderdirectformiir_architecture.py
index f4e240a4d1241c225e346d5b02c0351a966a4a68..82b50d2f45155e762cfa434981ec51b389579f1f 100644
--- a/examples/secondorderdirectformiir_architecture.py
+++ b/examples/secondorderdirectformiir_architecture.py
@@ -42,7 +42,7 @@ schedule = Schedule(sfg, cyclic=True)
 schedule.show(title='Original schedule')
 
 # %%
-# Rescheudle to only require one adder and one multiplier
+# Reschedule to only require one adder and one multiplier
 schedule.move_operation('add4', 2)
 schedule.move_operation('cmul5', -4)
 schedule.move_operation('cmul4', -5)
@@ -68,18 +68,22 @@ p_in = ProcessingElement(inputs, entity_name='input')
 p_out = ProcessingElement(outputs, entity_name='output')
 
 # %%
-# Extract memory variables
+# Extract and assign memory variables
 mem_vars = schedule.get_memory_variables()
 mem_vars.show(title="All memory variables")
 direct, mem_vars = mem_vars.split_on_length()
-direct.show(title="Direct interconnects")
 mem_vars.show(title="Non-zero time memory variables")
 mem_vars_set = mem_vars.split_on_ports(read_ports=1, write_ports=1, total_ports=2)
 
-memories = set()
+memories = []
 for i, mem in enumerate(mem_vars_set):
-    memories.add(Memory(mem, entity_name=f"memory{i}"))
-    mem.show(title=f"memory{i}")
+    memory = Memory(mem, memory_type="RAM", entity_name=f"memory{i}")
+    memories.append(memory)
+    mem.show(title=f"{memory.entity_name}")
+    memory.assign("left_edge")
+    memory.show_content(title=f"Assigned {memory.entity_name}")
+
+direct.show(title="Direct interconnects")
 
 # %%
 # Create architecture