From 39efd629f1f8ef02762dd1a3d807ae8e66c16dd4 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson <oscar.gustafsson@gmail.com>
Date: Wed, 17 May 2023 11:39:21 +0200
Subject: [PATCH] Fix typing, spelling errors and minor tests

---
 b_asic/codegen/vhdl/__init__.py     | 31 ++++++------
 b_asic/codegen/vhdl/architecture.py | 49 +++++++++----------
 b_asic/codegen/vhdl/common.py       | 75 ++++++++++++++---------------
 b_asic/codegen/vhdl/entity.py       |  7 ++-
 b_asic/quantization.py              | 12 ++++-
 b_asic/resources.py                 | 10 ++--
 b_asic/schedule.py                  | 27 +++++++----
 examples/fivepointwinograddft.py    |  2 +-
 test/test_quantization.py           |  9 ++++
 9 files changed, 122 insertions(+), 100 deletions(-)

diff --git a/b_asic/codegen/vhdl/__init__.py b/b_asic/codegen/vhdl/__init__.py
index fc42a54f..2cce156a 100644
--- a/b_asic/codegen/vhdl/__init__.py
+++ b/b_asic/codegen/vhdl/__init__.py
@@ -2,15 +2,14 @@
 Module for basic VHDL code generation.
 """
 
-from io import TextIOWrapper
-from typing import List, Optional, Tuple, Union
+from typing import List, Optional, TextIO, Tuple, Union
 
 # VHDL code generation tab length
 VHDL_TAB = r"    "
 
 
 def write(
-    f: TextIOWrapper,
+    f: TextIO,
     indent_level: int,
     text: str,
     *,
@@ -20,13 +19,13 @@ def write(
     """
     Base VHDL code generation utility.
 
-    `f'{VHDL_TAB*indent_level}'` is first written to the :class:`io.TextIOWrapper`
-    object `f`. Immediately after the indentation, `text` is written to `f`. Finally,
-    `text` is also written to `f`.
+    ``f'{VHDL_TAB*indent_level}'`` is first written to the TextIO
+    object *f*. Immediately after the indentation, *text* is written to *f*. Finally,
+    *text* is also written to *f*.
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
+    f : TextIO
         The file object to emit VHDL code to.
     indent_level : int
         Indentation level to use. Exactly ``f'{VHDL_TAB*indent_level}`` is written
@@ -43,24 +42,22 @@ def write(
     f.write(f'{VHDL_TAB*indent_level}{text}{end}')
 
 
-def write_lines(
-    f: TextIOWrapper, lines: List[Union[Tuple[int, str], Tuple[int, str, str]]]
-):
+def write_lines(f: TextIO, lines: List[Union[Tuple[int, str], Tuple[int, str, str]]]):
     """
     Multiline VHDL code generation utility.
 
-    Each tuple (int, str, [int]) in the list `lines` is written to the
-    :class:`io.TextIOWrapper` object `f` using the :function:`vhdl.write` function.
+    Each tuple ``(int, str, [int])`` in the list *lines* is written to the
+    TextIO object *f* using the :function:`vhdl.write` function.
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
+    f : TextIO
         The file object to emit VHDL code to.
     lines : list of tuple (int,str) [1], or list of tuple (int,str,str) [2]
-        [1]: The first `int` of the tuple is used as indentation level for the line and
-             the second `str` of the tuple is the content of the line.
-        [2]: Same as [1], but the third `str` of the tuple is passed to parameter `end`
-             when calling :function:`vhdl.write`.
+        [1]: The first ``int`` of the tuple is used as indentation level for the line
+             and the second ``str`` of the tuple is the content of the line.
+        [2]: Same as [1], but the third ``str`` of the tuple is passed to parameter
+             *end* when calling :function:`vhdl.write`.
     """
     for tpl in lines:
         if len(tpl) == 2:
diff --git a/b_asic/codegen/vhdl/architecture.py b/b_asic/codegen/vhdl/architecture.py
index 463f21b3..bc8d8227 100644
--- a/b_asic/codegen/vhdl/architecture.py
+++ b/b_asic/codegen/vhdl/architecture.py
@@ -1,8 +1,7 @@
 """
 Module for code generation of VHDL architectures.
 """
-from io import TextIOWrapper
-from typing import TYPE_CHECKING, Dict, Iterable, Set, Tuple, cast
+from typing import TYPE_CHECKING, Dict, List, Set, TextIO, Tuple, cast
 
 from b_asic.codegen.vhdl import common, write, write_lines
 from b_asic.process import MemoryVariable, PlainMemoryVariable
@@ -12,8 +11,8 @@ if TYPE_CHECKING:
 
 
 def memory_based_storage(
-    f: TextIOWrapper,
-    assignment: Iterable["ProcessCollection"],
+    f: TextIO,
+    assignment: List["ProcessCollection"],
     entity_name: str,
     word_length: int,
     read_ports: int,
@@ -26,9 +25,9 @@ def memory_based_storage(
 
     Parameters
     ----------
-    f : TextIOWrapper
-        File object (or other TextIOWrapper object) to write the architecture onto.
-    assignment : dict
+    f : TextIO
+        File object (or other TextIO object) to write the architecture onto.
+    assignment : list
         A possible cell assignment to use when generating the memory based storage.
         The cell assignment is a dictionary int to ProcessCollection where the integer
         corresponds to the cell to assign all MemoryVariables in corresponding process
@@ -58,7 +57,7 @@ def memory_based_storage(
     write(f, 0, f'architecture {architecture_name} of {entity_name} is', end='\n\n')
 
     #
-    # Architecture declerative region begin
+    # Architecture declarative region begin
     #
     write(f, 1, '-- HDL memory description')
     common.constant_declaration(
@@ -70,7 +69,7 @@ def memory_based_storage(
     common.type_declaration(
         f, 'mem_type', 'array(0 to MEM_DEPTH-1) of std_logic_vector(MEM_WL-1 downto 0)'
     )
-    common.signal_decl(
+    common.signal_declaration(
         f,
         name='memory',
         signal_type='mem_type',
@@ -78,25 +77,25 @@ def memory_based_storage(
         vivado_ram_style='distributed',
     )
     for i in range(read_ports):
-        common.signal_decl(
+        common.signal_declaration(
             f, f'read_port_{i}', 'std_logic_vector(MEM_WL-1 downto 0)', name_pad=14
         )
-        common.signal_decl(
+        common.signal_declaration(
             f, f'read_adr_{i}', f'integer range 0 to {schedule_time}-1', name_pad=14
         )
-        common.signal_decl(f, f'read_en_{i}', 'std_logic', name_pad=14)
+        common.signal_declaration(f, f'read_en_{i}', 'std_logic', name_pad=14)
     for i in range(write_ports):
-        common.signal_decl(
+        common.signal_declaration(
             f, f'write_port_{i}', 'std_logic_vector(MEM_WL-1 downto 0)', name_pad=14
         )
-        common.signal_decl(
+        common.signal_declaration(
             f, f'write_adr_{i}', f'integer range 0 to {schedule_time}-1', name_pad=14
         )
-        common.signal_decl(f, f'write_en_{i}', 'std_logic', name_pad=14)
+        common.signal_declaration(f, f'write_en_{i}', 'std_logic', name_pad=14)
 
     # Schedule time counter
     write(f, 1, '-- Schedule counter', start='\n')
-    common.signal_decl(
+    common.signal_declaration(
         f,
         name='schedule_cnt',
         signal_type=f'integer range 0 to {schedule_time}-1',
@@ -107,7 +106,7 @@ def memory_based_storage(
     if input_sync:
         write(f, 1, '-- Input synchronization', start='\n')
         for i in range(read_ports):
-            common.signal_decl(
+            common.signal_declaration(
                 f, f'p_{i}_in_sync', 'std_logic_vector(WL-1 downto 0)', name_pad=14
             )
 
@@ -191,7 +190,7 @@ def memory_based_storage(
                     f,
                     [
                         (4, f'-- {mv!r}'),
-                        (4, f'when {(mv.start_time) % schedule_time} =>'),
+                        (4, f'when {mv.start_time % schedule_time} =>'),
                         (5, f'write_adr_0 <= {i};'),
                         (5, 'write_en_0 <= \'1\';'),
                     ],
@@ -283,7 +282,7 @@ def memory_based_storage(
 
 
 def register_based_storage(
-    f: TextIOWrapper,
+    f: TextIO,
     forward_backward_table: "_ForwardBackwardTable",
     entity_name: str,
     word_length: int,
@@ -326,7 +325,7 @@ def register_based_storage(
 
     # Schedule time counter
     write(f, 1, '-- Schedule counter')
-    common.signal_decl(
+    common.signal_declaration(
         f,
         name='schedule_cnt',
         signal_type=f'integer range 0 to {schedule_time}-1',
@@ -341,7 +340,7 @@ def register_based_storage(
         name='shift_reg_type',
         alias=f'array(0 to {reg_cnt}-1) of std_logic_vector(WL-1 downto 0)',
     )
-    common.signal_decl(
+    common.signal_declaration(
         f,
         name='shift_reg',
         signal_type='shift_reg_type',
@@ -350,7 +349,7 @@ def register_based_storage(
 
     # Back edge mux decoder
     write(f, 1, '-- Back-edge mux select signal', start='\n')
-    common.signal_decl(
+    common.signal_declaration(
         f,
         name='back_edge_mux_sel',
         signal_type=f'integer range 0 to {len(back_edges)}',
@@ -359,7 +358,7 @@ def register_based_storage(
 
     # Output mux selector
     write(f, 1, '-- Output mux select signal', start='\n')
-    common.signal_decl(
+    common.signal_declaration(
         f,
         name='out_mux_sel',
         signal_type=f'integer range 0 to {len(output_regs) - 1}',
@@ -478,7 +477,7 @@ def register_based_storage(
     )
 
     # Output multiplexer decoding logic
-    write(f, 1, '-- Output muliplexer decoding logic', start='\n')
+    write(f, 1, '-- Output multiplexer decoding logic', start='\n')
     common.synchronous_process_prologue(f, clk='clk', name='out_mux_decode_proc')
     write(f, 3, 'case schedule_cnt is')
     for i, entry in enumerate(forward_backward_table):
@@ -490,7 +489,7 @@ def register_based_storage(
     common.synchronous_process_epilogue(f, clk='clk', name='out_mux_decode_proc')
 
     # Output multiplexer logic
-    write(f, 1, '-- Output muliplexer', start='\n')
+    write(f, 1, '-- Output multiplexer', start='\n')
     common.synchronous_process_prologue(
         f,
         clk='clk',
diff --git a/b_asic/codegen/vhdl/common.py b/b_asic/codegen/vhdl/common.py
index 30b5980b..a1ac777c 100644
--- a/b_asic/codegen/vhdl/common.py
+++ b/b_asic/codegen/vhdl/common.py
@@ -4,20 +4,19 @@ Generation of common VHDL constructs
 
 import re
 from datetime import datetime
-from io import TextIOWrapper
 from subprocess import PIPE, Popen
-from typing import Any, Optional, Set, Tuple
+from typing import Any, Optional, Set, TextIO, Tuple
 
 from b_asic.codegen.vhdl import write, write_lines
 
 
-def b_asic_preamble(f: TextIOWrapper):
+def b_asic_preamble(f: TextIO):
     """
     Write a standard BASIC VHDL preamble comment.
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
+    f : TextIO
         The file object to write the header to.
     """
     # Try to acquire the current git commit hash
@@ -47,7 +46,7 @@ def b_asic_preamble(f: TextIOWrapper):
 
 
 def ieee_header(
-    f: TextIOWrapper,
+    f: TextIO,
     std_logic_1164: bool = True,
     numeric_std: bool = True,
 ):
@@ -57,8 +56,8 @@ def ieee_header(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper object to write the IEEE header to.
+    f : TextIO
+        The TextIO object to write the IEEE header to.
     std_logic_1164 : bool, default: True
         Include the std_logic_1164 header.
     numeric_std : bool, default: True
@@ -72,8 +71,8 @@ def ieee_header(
     write(f, 0, '')
 
 
-def signal_decl(
-    f: TextIOWrapper,
+def signal_declaration(
+    f: TextIO,
     name: str,
     signal_type: str,
     default_value: Optional[str] = None,
@@ -88,8 +87,8 @@ def signal_decl(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper object to write the IEEE header to.
+    f : TextIO
+        The TextIO object to write the IEEE header to.
     name : str
         Signal name.
     signal_type : str
@@ -132,7 +131,7 @@ def signal_decl(
 
 
 def constant_declaration(
-    f: TextIOWrapper,
+    f: TextIO,
     name: str,
     signal_type: str,
     value: Any,
@@ -144,8 +143,8 @@ def constant_declaration(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper object to write the constant declaration to.
+    f : TextIO
+        The TextIO object to write the constant declaration to.
     name : str
         Signal name.
     signal_type : str
@@ -160,7 +159,7 @@ def constant_declaration(
 
 
 def type_declaration(
-    f: TextIOWrapper,
+    f: TextIO,
     name: str,
     alias: str,
 ):
@@ -169,8 +168,8 @@ def type_declaration(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper object to write the type declaration to.
+    f : TextIO
+        The TextIO object to write the type declaration to.
     name : str
         Type name alias.
     alias : str
@@ -180,7 +179,7 @@ def type_declaration(
 
 
 def process_prologue(
-    f: TextIOWrapper,
+    f: TextIO,
     sensitivity_list: str,
     indent: int = 1,
     name: Optional[str] = None,
@@ -192,8 +191,8 @@ def process_prologue(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper object to write the type declaration to.
+    f : TextIO
+        The TextIO object to write the type declaration to.
     sensitivity_list : str
         Content of the process sensitivity list.
     indent : int, default: 1
@@ -209,7 +208,7 @@ def process_prologue(
 
 
 def process_epilogue(
-    f: TextIOWrapper,
+    f: TextIO,
     sensitivity_list: Optional[str] = None,
     indent: int = 1,
     name: Optional[str] = None,
@@ -217,8 +216,8 @@ def process_epilogue(
     """
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper object to write the type declaration to.
+    f : TextIO
+        The TextIO object to write the type declaration to.
     sensitivity_list : str
         Content of the process sensitivity list. Not needed when writing the epilogue.
     indent : int, default: 1
@@ -236,7 +235,7 @@ def process_epilogue(
 
 
 def synchronous_process_prologue(
-    f: TextIOWrapper,
+    f: TextIO,
     clk: str,
     indent: int = 1,
     name: Optional[str] = None,
@@ -251,8 +250,8 @@ def synchronous_process_prologue(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper to write the VHDL code onto.
+    f : TextIO
+        The TextIO to write the VHDL code onto.
     clk : str
         Name of the clock.
     indent : int, default: 1
@@ -265,7 +264,7 @@ def synchronous_process_prologue(
 
 
 def synchronous_process_epilogue(
-    f: TextIOWrapper,
+    f: TextIO,
     clk: Optional[str],
     indent: int = 1,
     name: Optional[str] = None,
@@ -278,8 +277,8 @@ def synchronous_process_epilogue(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper to write the VHDL code onto.
+    f : TextIO
+        The TextIO to write the VHDL code onto.
     clk : str
         Name of the clock.
     indent : int, default: 1
@@ -293,7 +292,7 @@ def synchronous_process_epilogue(
 
 
 def synchronous_process(
-    f: TextIOWrapper,
+    f: TextIO,
     clk: str,
     body: str,
     indent: int = 1,
@@ -307,8 +306,8 @@ def synchronous_process(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper to write the VHDL code onto.
+    f : TextIO
+        The TextIO to write the VHDL code onto.
     clk : str
         Name of the clock.
     body : str
@@ -326,7 +325,7 @@ def synchronous_process(
 
 
 def synchronous_memory(
-    f: TextIOWrapper,
+    f: TextIO,
     clk: str,
     read_ports: Set[Tuple[str, str, str]],
     write_ports: Set[Tuple[str, str, str]],
@@ -337,8 +336,8 @@ def synchronous_memory(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper to write the VHDL code onto.
+    f : TextIO
+        The TextIO to write the VHDL code onto.
     clk : str
         Name of clock identifier to the synchronous memory.
     read_ports : Set[Tuple[str,str]]
@@ -373,7 +372,7 @@ def synchronous_memory(
 
 
 def asynchronous_read_memory(
-    f: TextIOWrapper,
+    f: TextIO,
     clk: str,
     read_ports: Set[Tuple[str, str, str]],
     write_ports: Set[Tuple[str, str, str]],
@@ -384,8 +383,8 @@ def asynchronous_read_memory(
 
     Parameters
     ----------
-    f : :class:`io.TextIOWrapper`
-        The TextIOWrapper to write the VHDL code onto.
+    f : TextIO
+        The TextIO to write the VHDL code onto.
     clk : str
         Name of clock identifier to the synchronous memory.
     read_ports : Set[Tuple[str,str]]
diff --git a/b_asic/codegen/vhdl/entity.py b/b_asic/codegen/vhdl/entity.py
index 8e2328e8..f13d1a17 100644
--- a/b_asic/codegen/vhdl/entity.py
+++ b/b_asic/codegen/vhdl/entity.py
@@ -1,8 +1,7 @@
 """
 Module for code generation of VHDL entity declarations
 """
-from io import TextIOWrapper
-from typing import Set
+from typing import Set, TextIO
 
 from b_asic.codegen.vhdl import VHDL_TAB, write_lines
 from b_asic.port import Port
@@ -11,7 +10,7 @@ from b_asic.resources import ProcessCollection
 
 
 def memory_based_storage(
-    f: TextIOWrapper, entity_name: str, collection: ProcessCollection, word_length: int
+    f: TextIO, entity_name: str, collection: ProcessCollection, word_length: int
 ):
     # Check that this is a ProcessCollection of (Plain)MemoryVariables
     is_memory_variable = all(
@@ -79,6 +78,6 @@ def memory_based_storage(
 
 
 def register_based_storage(
-    f: TextIOWrapper, entity_name: str, collection: ProcessCollection, word_length: int
+    f: TextIO, entity_name: str, collection: ProcessCollection, word_length: int
 ):
     memory_based_storage(f, entity_name, collection, word_length)
diff --git a/b_asic/quantization.py b/b_asic/quantization.py
index 2e70ad4c..5de9a517 100644
--- a/b_asic/quantization.py
+++ b/b_asic/quantization.py
@@ -19,11 +19,14 @@ class Quantization(Enum):
     "Magnitude truncation, i.e., round towards zero."
 
     JAMMING = 4
-    "Jamming/von Neumann rounding, i.e., set the LSB to one"
+    "Jamming/von Neumann rounding, i.e., set the LSB to one."
 
     UNBIASED_ROUNDING = 5
     "Unbiased rounding, i.e., tie rounds towards even."
 
+    UNBIASED_JAMMING = 6
+    "Unbiased jamming/von Neumann rounding."
+
 
 class Overflow(Enum):
     """Overflow types."""
@@ -125,8 +128,13 @@ def quantize(
             v = math.ceil(v)
     elif quantization is Quantization.JAMMING:
         v = math.floor(v) | 1
-    else:  # Quantization.UNBIASED_ROUNDING
+    elif quantization is Quantization.UNBIASED_ROUNDING:
         v = round(v)
+    elif quantization is Quantization.UNBIASED_JAMMING:
+        f = math.floor(v)
+        v = f if v - f == 0 else f | 1
+    else:
+        raise TypeError("Unknown quantization method: {quantization!r}")
 
     v = v / b
     i = 2 ** (integer_bits - 1)
diff --git a/b_asic/resources.py b/b_asic/resources.py
index 51d05523..ef1204ab 100644
--- a/b_asic/resources.py
+++ b/b_asic/resources.py
@@ -651,8 +651,12 @@ class ProcessCollection:
                 )
         _ax.grid(True)  # type: ignore
 
-        _ax.xaxis.set_major_locator(MaxNLocator(integer=True))  # type: ignore
-        _ax.yaxis.set_major_locator(MaxNLocator(integer=True))  # type: ignore
+        _ax.xaxis.set_major_locator(
+            MaxNLocator(integer=True, min_n_ticks=1)
+        )  # type: ignore
+        _ax.yaxis.set_major_locator(
+            MaxNLocator(integer=True, min_n_ticks=1)
+        )  # type: ignore
         _ax.set_xlim(0, self._schedule_time)  # type: ignore
         if row is None:
             _ax.set_ylim(0.25, len(self._collection) + 0.75)  # type: ignore
@@ -1154,7 +1158,7 @@ class ProcessCollection:
             Name used for the VHDL entity.
         word_length : int
             Word length of the memory variable objects.
-        assignment : set
+        assignment : list
             A possible cell assignment to use when generating the memory based storage.
             The cell assignment is a dictionary int to ProcessCollection where the
             integer corresponds to the cell to assign all MemoryVariables in
diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 253c1074..db668d10 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -7,7 +7,7 @@ Contains the schedule class for scheduling operations in an SFG.
 import io
 import sys
 from collections import defaultdict
-from typing import Dict, List, Optional, Sequence, Tuple, cast
+from typing import Dict, List, Optional, Sequence, Tuple, Union, cast
 
 import matplotlib.pyplot as plt
 import numpy as np
@@ -38,9 +38,15 @@ from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import TypeName
 
 # Need RGB from 0 to 1
-_EXECUTION_TIME_COLOR = tuple(c / 255 for c in EXECUTION_TIME_COLOR)
-_LATENCY_COLOR = tuple(c / 255 for c in LATENCY_COLOR)
-_SIGNAL_COLOR = tuple(c / 255 for c in SIGNAL_COLOR)
+_EXECUTION_TIME_COLOR: Union[
+    Tuple[float, float, float], Tuple[float, float, float, float]
+] = tuple(float(c / 255) for c in EXECUTION_TIME_COLOR)
+_LATENCY_COLOR: Union[
+    Tuple[float, float, float], Tuple[float, float, float, float]
+] = tuple(float(c / 255) for c in LATENCY_COLOR)
+_SIGNAL_COLOR: Union[
+    Tuple[float, float, float], Tuple[float, float, float, float]
+] = tuple(float(c / 255) for c in SIGNAL_COLOR)
 
 
 def _laps_default():
@@ -443,11 +449,11 @@ class Schedule:
     def get_possible_time_resolution_decrements(self) -> List[int]:
         """Return a list with possible factors to reduce time resolution."""
         vals = self._get_all_times()
-        maxloop = min(val for val in vals if val)
-        if maxloop <= 1:
+        max_loop = min(val for val in vals if val)
+        if max_loop <= 1:
             return [1]
         ret = [1]
-        for candidate in range(2, maxloop + 1):
+        for candidate in range(2, max_loop + 1):
             if not any(val % candidate for val in vals):
                 ret.append(candidate)
         return ret
@@ -700,7 +706,6 @@ class Schedule:
                             )
                         source_port = inport.signals[0].source
 
-                        source_end_time = None
                         if source_port.operation.graph_id in non_schedulable_ops:
                             source_end_time = 0
                         else:
@@ -793,7 +798,9 @@ class Schedule:
         """
         return ProcessCollection(
             {
-                OperatorProcess(start_time, self._sfg.find_by_id(graph_id))
+                OperatorProcess(
+                    start_time, cast(Operation, self._sfg.find_by_id(graph_id))
+                )
                 for graph_id, start_time in self._start_times.items()
             },
             self.schedule_time,
@@ -987,7 +994,7 @@ class Schedule:
             + (OPERATION_GAP if operation_gap is None else operation_gap)
         )
         ax.axis([-1, self._schedule_time + 1, y_position_max, 0])  # Inverted y-axis
-        ax.xaxis.set_major_locator(MaxNLocator(integer=True))
+        ax.xaxis.set_major_locator(MaxNLocator(integer=True, min_n_ticks=1))
         ax.axvline(
             0,
             linestyle="--",
diff --git a/examples/fivepointwinograddft.py b/examples/fivepointwinograddft.py
index 8093a2e1..2d26c4de 100644
--- a/examples/fivepointwinograddft.py
+++ b/examples/fivepointwinograddft.py
@@ -190,6 +190,7 @@ mem_vars = schedule.get_memory_variables()
 mem_vars.show(title="All memory variables")
 direct, mem_vars = mem_vars.split_on_length()
 mem_vars.show(title="Non-zero time memory variables")
+direct.show(title="Direct interconnects")
 mem_vars_set = mem_vars.split_on_ports(read_ports=1, write_ports=1, total_ports=2)
 
 memories = []
@@ -200,7 +201,6 @@ for i, mem in enumerate(mem_vars_set):
     memory.assign("left_edge")
     memory.show_content(title=f"Assigned {memory.entity_name}")
 
-direct.show(title="Direct interconnects")
 
 arch = Architecture(
     {addsub, butterfly, multiplier, pe_in, pe_out},
diff --git a/test/test_quantization.py b/test/test_quantization.py
index 2923787b..b668a45d 100644
--- a/test/test_quantization.py
+++ b/test/test_quantization.py
@@ -8,10 +8,14 @@ def test_quantization():
     assert quantize(a, 4, quantization=Quantization.ROUNDING) == 0.3125
     assert quantize(a, 4, quantization=Quantization.MAGNITUDE_TRUNCATION) == 0.25
     assert quantize(a, 4, quantization=Quantization.JAMMING) == 0.3125
+    assert quantize(a, 4, quantization=Quantization.UNBIASED_ROUNDING) == 0.3125
+    assert quantize(a, 4, quantization=Quantization.UNBIASED_JAMMING) == 0.3125
     assert quantize(-a, 4, quantization=Quantization.TRUNCATION) == -0.3125
     assert quantize(-a, 4, quantization=Quantization.ROUNDING) == -0.3125
     assert quantize(-a, 4, quantization=Quantization.MAGNITUDE_TRUNCATION) == -0.25
     assert quantize(-a, 4, quantization=Quantization.JAMMING) == -0.3125
+    assert quantize(-a, 4, quantization=Quantization.UNBIASED_ROUNDING) == -0.3125
+    assert quantize(-a, 4, quantization=Quantization.UNBIASED_JAMMING) == -0.3125
     assert quantize(complex(a, -a), 4) == complex(0.25, -0.3125)
     assert quantize(
         complex(a, -a), 4, quantization=Quantization.MAGNITUDE_TRUNCATION
@@ -26,3 +30,8 @@ def test_quantization():
         )
         == 0.9375
     )
+
+    assert quantize(0.3125, 3, quantization=Quantization.ROUNDING) == 0.375
+    assert quantize(0.3125, 3, quantization=Quantization.UNBIASED_ROUNDING) == 0.25
+    assert quantize(0.25, 3, quantization=Quantization.JAMMING) == 0.375
+    assert quantize(0.25, 3, quantization=Quantization.UNBIASED_JAMMING) == 0.25
-- 
GitLab