get things working with a LazyLibrary hack while we think about cycles
This commit is contained in:
parent
22735125d5
commit
6eb4af3203
@ -142,7 +142,7 @@ def waveguide(
|
|||||||
left=Port((-extent, 0), rotation=0, ptype='pcwg'),
|
left=Port((-extent, 0), rotation=0, ptype='pcwg'),
|
||||||
right=Port((extent, 0), rotation=pi, ptype='pcwg'),
|
right=Port((extent, 0), rotation=pi, ptype='pcwg'),
|
||||||
)
|
)
|
||||||
pat2dev(pat)
|
dev2pat(pat)
|
||||||
print(pat)
|
print(pat)
|
||||||
return pat
|
return pat
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ def bend(
|
|||||||
extent * numpy.sqrt(3) / 2),
|
extent * numpy.sqrt(3) / 2),
|
||||||
rotation=pi * 4 / 3, ptype='pcwg'),
|
rotation=pi * 4 / 3, ptype='pcwg'),
|
||||||
)
|
)
|
||||||
pat2dev(pat)
|
dev2pat(pat)
|
||||||
return pat
|
return pat
|
||||||
|
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ def y_splitter(
|
|||||||
'bot': Port((extent / 2, -extent * numpy.sqrt(3) / 2), rotation=pi * 2 / 3, ptype='pcwg'),
|
'bot': Port((extent / 2, -extent * numpy.sqrt(3) / 2), rotation=pi * 2 / 3, ptype='pcwg'),
|
||||||
}
|
}
|
||||||
|
|
||||||
pat2dev(pat)
|
dev2pat(pat)
|
||||||
return pat
|
return pat
|
||||||
|
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ def main(interactive: bool = True) -> None:
|
|||||||
# We can also add text labels for our circuit's ports.
|
# We can also add text labels for our circuit's ports.
|
||||||
# They will appear at the uppermost hierarchy level, while the individual
|
# They will appear at the uppermost hierarchy level, while the individual
|
||||||
# device ports will appear further down, in their respective cells.
|
# device ports will appear further down, in their respective cells.
|
||||||
pat2dev(circ.pattern)
|
dev2pat(circ.pattern)
|
||||||
|
|
||||||
# Add the pattern into our library
|
# Add the pattern into our library
|
||||||
lib['my_circuit'] = circ.pattern
|
lib['my_circuit'] = circ.pattern
|
||||||
@ -319,7 +319,7 @@ def main(interactive: bool = True) -> None:
|
|||||||
# Check if we forgot to include any patterns... ooops!
|
# Check if we forgot to include any patterns... ooops!
|
||||||
if dangling := lib.dangling_refs():
|
if dangling := lib.dangling_refs():
|
||||||
print('Warning: The following patterns are referenced, but not present in the'
|
print('Warning: The following patterns are referenced, but not present in the'
|
||||||
f'library! {dangling}')
|
f' library! {dangling}')
|
||||||
print('We\'ll solve this by merging in shape_lib, which contains those shapes...')
|
print('We\'ll solve this by merging in shape_lib, which contains those shapes...')
|
||||||
|
|
||||||
lib.add(shape_lib)
|
lib.add(shape_lib)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
from typing import Dict
|
from typing import Dict, TypeVar
|
||||||
#from typing import Union, Optional, MutableMapping, TYPE_CHECKING
|
#from typing import Union, Optional, MutableMapping, TYPE_CHECKING
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from numpy.typing import ArrayLike
|
||||||
|
|
||||||
#from .pattern import Pattern
|
#from .pattern import Pattern
|
||||||
|
from .ref import Ref
|
||||||
from .ports import PortList, Port
|
from .ports import PortList, Port
|
||||||
|
|
||||||
#if TYPE_CHECKING:
|
#if TYPE_CHECKING:
|
||||||
|
@ -207,7 +207,7 @@ class Builder(PortList):
|
|||||||
names.
|
names.
|
||||||
"""
|
"""
|
||||||
if library is None:
|
if library is None:
|
||||||
if hasattr(source, 'library') and isinstance(source, MutableLibrary):
|
if hasattr(source, 'library') and isinstance(source.library, MutableLibrary):
|
||||||
library = source.library
|
library = source.library
|
||||||
else:
|
else:
|
||||||
raise BuildError('No library provided (and not present in `source.library`')
|
raise BuildError('No library provided (and not present in `source.library`')
|
||||||
|
@ -53,7 +53,9 @@ def dev2pat(pattern: Pattern, layer: layer_t) -> Pattern:
|
|||||||
def pat2dev(
|
def pat2dev(
|
||||||
layers: Sequence[layer_t],
|
layers: Sequence[layer_t],
|
||||||
library: Mapping[str, Pattern],
|
library: Mapping[str, Pattern],
|
||||||
pattern: Pattern,
|
pattern: Pattern, # Pattern is good since we don't want to do library[name] to avoid infinite recursion.
|
||||||
|
# LazyLibrary protects against library[ref.target] causing a circular lookup.
|
||||||
|
# For others, maybe check for cycles up front? TODO
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
max_depth: int = 999_999,
|
max_depth: int = 999_999,
|
||||||
skip_subcells: bool = True,
|
skip_subcells: bool = True,
|
||||||
@ -94,20 +96,24 @@ def pat2dev(
|
|||||||
if (skip_subcells and pattern.ports) or max_depth == 0:
|
if (skip_subcells and pattern.ports) or max_depth == 0:
|
||||||
return pattern
|
return pattern
|
||||||
|
|
||||||
# Load ports for all subpatterns
|
# Load ports for all subpatterns, and use any we find
|
||||||
for target in set(rr.target for rr in pat.refs):
|
found_ports = False
|
||||||
|
for target in set(rr.target for rr in pattern.refs):
|
||||||
pp = pat2dev(
|
pp = pat2dev(
|
||||||
layers=layers,
|
layers=layers,
|
||||||
library=library,
|
library=library,
|
||||||
pattern=library[target],
|
pattern=library[target],
|
||||||
name=target,
|
name=target,
|
||||||
max_depth=max_depth-1,
|
max_depth=max_depth - 1,
|
||||||
skip_subcells=skip_subcells,
|
skip_subcells=skip_subcells,
|
||||||
blacklist=blacklist + {name},
|
blacklist=blacklist + {name},
|
||||||
)
|
)
|
||||||
found_ports |= bool(pp.ports)
|
found_ports |= bool(pp.ports)
|
||||||
|
|
||||||
for ref in pat.refs:
|
if not found_ports:
|
||||||
|
return pattern
|
||||||
|
|
||||||
|
for ref in pattern.refs:
|
||||||
aa = library.abstract(ref.target)
|
aa = library.abstract(ref.target)
|
||||||
if not aa.ports:
|
if not aa.ports:
|
||||||
continue
|
continue
|
||||||
|
@ -713,11 +713,13 @@ class LazyLibrary(MutableLibrary):
|
|||||||
"""
|
"""
|
||||||
dict: Dict[str, Callable[[], 'Pattern']]
|
dict: Dict[str, Callable[[], 'Pattern']]
|
||||||
cache: Dict[str, 'Pattern']
|
cache: Dict[str, 'Pattern']
|
||||||
|
_lookups_in_progress: Set[str]
|
||||||
enable_cache: bool = True
|
enable_cache: bool = True
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.dict = {}
|
self.dict = {}
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
|
self._lookups_in_progress = set()
|
||||||
|
|
||||||
def __setitem__(self, key: str, value: Callable[[], 'Pattern']) -> None:
|
def __setitem__(self, key: str, value: Callable[[], 'Pattern']) -> None:
|
||||||
self.dict[key] = value
|
self.dict[key] = value
|
||||||
@ -735,8 +737,17 @@ class LazyLibrary(MutableLibrary):
|
|||||||
logger.debug(f'found {key} in cache')
|
logger.debug(f'found {key} in cache')
|
||||||
return self.cache[key]
|
return self.cache[key]
|
||||||
|
|
||||||
|
if key in self._lookups_in_progress:
|
||||||
|
raise LibraryError(
|
||||||
|
f'Detected multiple simultaneous lookups of "{key}".\n'
|
||||||
|
'This may be caused by an invalid (cyclical) reference, or buggy code.\n'
|
||||||
|
'If you are lazy-loading a file, try a non-lazy load and check for refernce cycles.' # TODO give advice on finding cycles
|
||||||
|
)
|
||||||
|
|
||||||
|
self._lookups_in_progress.add(key)
|
||||||
func = self.dict[key]
|
func = self.dict[key]
|
||||||
pat = func()
|
pat = func()
|
||||||
|
self._lookups_in_progress.remove(key)
|
||||||
self.cache[key] = pat
|
self.cache[key] = pat
|
||||||
return pat
|
return pat
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user