|
|
|
@ -14,12 +14,12 @@ from __future__ import annotations |
|
|
|
|
|
|
|
|
|
|
|
from collections import deque, defaultdict |
|
|
|
from collections import deque, defaultdict |
|
|
|
import re |
|
|
|
import re |
|
|
|
from typing import Union |
|
|
|
from typing import Union, Any |
|
|
|
|
|
|
|
|
|
|
|
import numpy as np |
|
|
|
import numpy as np |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GrowingList(list): |
|
|
|
class GrowingList[T](list[T]): |
|
|
|
def __setitem__(self, index, value): |
|
|
|
def __setitem__(self, index, value): |
|
|
|
if value is None: self.has_nones = True |
|
|
|
if value is None: self.has_nones = True |
|
|
|
if index == len(self): return super().append(value) |
|
|
|
if index == len(self): return super().append(value) |
|
|
|
@ -28,9 +28,13 @@ class GrowingList(list): |
|
|
|
self.has_nones = True |
|
|
|
self.has_nones = True |
|
|
|
super().__setitem__(index, value) |
|
|
|
super().__setitem__(index, value) |
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, index): |
|
|
|
# Override __getitem__ to return None when reading beyond the list |
|
|
|
if isinstance(index, slice): return super().__getitem__(index) |
|
|
|
# instead of throwing an exception. Type checker complains about the None return |
|
|
|
return super().__getitem__(index) if index < len(self) else None |
|
|
|
# type, though. Probably not needed anyways. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#def __getitem__(self, index) -> list[T] | T | None: |
|
|
|
|
|
|
|
# if isinstance(index, slice): return super().__getitem__(index) |
|
|
|
|
|
|
|
# return super().__getitem__(index) if index < len(self) else None |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def free_idx(self): |
|
|
|
def free_idx(self): |
|
|
|
@ -155,7 +159,7 @@ class Line: |
|
|
|
Use the explicit case only if connections to specific pins are required. |
|
|
|
Use the explicit case only if connections to specific pins are required. |
|
|
|
It may overwrite any previous line references in the connection list of the nodes. |
|
|
|
It may overwrite any previous line references in the connection list of the nodes. |
|
|
|
""" |
|
|
|
""" |
|
|
|
def __init__(self, circuit: Circuit, driver: Union[Node, tuple[Node, int]], reader: Union[Node, tuple[Node, int]]): |
|
|
|
def __init__(self, circuit: Circuit, driver: Node | tuple[Node, None|int], reader: Node | tuple[Node, None|int]): |
|
|
|
self.circuit = circuit |
|
|
|
self.circuit = circuit |
|
|
|
"""The :class:`Circuit` object the line is part of. |
|
|
|
"""The :class:`Circuit` object the line is part of. |
|
|
|
""" |
|
|
|
""" |
|
|
|
@ -168,20 +172,20 @@ class Line: |
|
|
|
accessing it by :code:`my_data[l.index]` or simply by :code:`my_data[l]`. |
|
|
|
accessing it by :code:`my_data[l.index]` or simply by :code:`my_data[l]`. |
|
|
|
""" |
|
|
|
""" |
|
|
|
if not isinstance(driver, tuple): driver = (driver, driver.outs.free_idx) |
|
|
|
if not isinstance(driver, tuple): driver = (driver, driver.outs.free_idx) |
|
|
|
self.driver = driver[0] |
|
|
|
self.driver: Node = driver[0] |
|
|
|
"""The :class:`Node` object that drives this line. |
|
|
|
"""The :class:`Node` object that drives this line. |
|
|
|
""" |
|
|
|
""" |
|
|
|
self.driver_pin = driver[1] |
|
|
|
self.driver_pin = driver[1] if driver[1] is not None else self.driver.outs.free_idx |
|
|
|
"""The output pin position of the driver node this line is connected to. |
|
|
|
"""The output pin position of the driver node this line is connected to. |
|
|
|
|
|
|
|
|
|
|
|
This is the position in the list :py:attr:`Node.outs` of the driving node this line referenced from: |
|
|
|
This is the position in the list :py:attr:`Node.outs` of the driving node this line referenced from: |
|
|
|
:code:`self.driver.outs[self.driver_pin] == self`. |
|
|
|
:code:`self.driver.outs[self.driver_pin] == self`. |
|
|
|
""" |
|
|
|
""" |
|
|
|
if not isinstance(reader, tuple): reader = (reader, reader.ins.free_idx) |
|
|
|
if not isinstance(reader, tuple): reader = (reader, reader.ins.free_idx) |
|
|
|
self.reader = reader[0] |
|
|
|
self.reader: Node = reader[0] |
|
|
|
"""The :class:`Node` object that reads this line. |
|
|
|
"""The :class:`Node` object that reads this line. |
|
|
|
""" |
|
|
|
""" |
|
|
|
self.reader_pin = reader[1] |
|
|
|
self.reader_pin = reader[1] if reader[1] is not None else self.reader.ins.free_idx |
|
|
|
"""The input pin position of the reader node this line is connected to. |
|
|
|
"""The input pin position of the reader node this line is connected to. |
|
|
|
|
|
|
|
|
|
|
|
This is the position in the list :py:attr:`Node.ins` of the reader node this line referenced from: |
|
|
|
This is the position in the list :py:attr:`Node.ins` of the reader node this line referenced from: |
|
|
|
@ -203,8 +207,6 @@ class Line: |
|
|
|
for i, l in enumerate(self.driver.outs): l.driver_pin = i |
|
|
|
for i, l in enumerate(self.driver.outs): l.driver_pin = i |
|
|
|
if self.reader is not None: self.reader.ins[self.reader_pin] = None |
|
|
|
if self.reader is not None: self.reader.ins[self.reader_pin] = None |
|
|
|
if self.circuit is not None: del self.circuit.lines[self.index] |
|
|
|
if self.circuit is not None: del self.circuit.lines[self.index] |
|
|
|
self.driver = None |
|
|
|
|
|
|
|
self.reader = None |
|
|
|
|
|
|
|
self.circuit = None |
|
|
|
self.circuit = None |
|
|
|
|
|
|
|
|
|
|
|
def __index__(self): |
|
|
|
def __index__(self): |
|
|
|
@ -309,7 +311,7 @@ class Circuit: |
|
|
|
""" |
|
|
|
""" |
|
|
|
return self._locs(prefix, self.s_nodes) |
|
|
|
return self._locs(prefix, self.s_nodes) |
|
|
|
|
|
|
|
|
|
|
|
def _locs(self, prefix, nodes): |
|
|
|
def _locs(self, prefix, nodes:list[Node]) -> Node|list[Any]: # can return list[list[...]] |
|
|
|
d_top = dict() |
|
|
|
d_top = dict() |
|
|
|
for i, n in enumerate(nodes): |
|
|
|
for i, n in enumerate(nodes): |
|
|
|
if m := re.match(fr'({re.escape(prefix)}.*?)((?:[\d_\[\]])*$)', n.name): |
|
|
|
if m := re.match(fr'({re.escape(prefix)}.*?)((?:[\d_\[\]])*$)', n.name): |
|
|
|
@ -324,7 +326,7 @@ class Circuit: |
|
|
|
def sorted_values(d): return [sorted_values(v) for k, v in sorted(d.items())] if isinstance(d, dict) else d |
|
|
|
def sorted_values(d): return [sorted_values(v) for k, v in sorted(d.items())] if isinstance(d, dict) else d |
|
|
|
l = sorted_values(d_top) |
|
|
|
l = sorted_values(d_top) |
|
|
|
while isinstance(l, list) and len(l) == 1: l = l[0] |
|
|
|
while isinstance(l, list) and len(l) == 1: l = l[0] |
|
|
|
return None if isinstance(l, list) and len(l) == 0 else l |
|
|
|
return l #None if isinstance(l, list) and len(l) == 0 else l |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def stats(self): |
|
|
|
def stats(self): |
|
|
|
|