Compare commits
1
Commits
449bf9a031
...
bda89dc1b0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bda89dc1b0 |
No files matched your search
@@ -0,0 +1,64 @@
|
||||
"""A parser and dumper for Atalanta's plain-text test pattern format (*.test).
|
||||
|
||||
A *.test file contains one test pattern per line in the form ``<index>: <bits>``,
|
||||
where ``<bits>`` is a string of ``'0'`` and ``'1'`` characters giving the values of
|
||||
the primary inputs (in circuit order). Lines starting with ``'*'`` are comments.
|
||||
|
||||
This parser also accepts files without ``<index>:`` and patterns elements in 8-valued
|
||||
logic such as ``'R'``, ``'F'``, ``'X'``.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
import numpy as np
|
||||
|
||||
from . import readtext, logic
|
||||
from .circuit import Circuit
|
||||
|
||||
_pattern_re = re.compile(r'^\s*(?:\d+:\s*)?([01HLRFX-]+)\s*$')
|
||||
|
||||
|
||||
class TestFile:
|
||||
"""Intermediate representation of a *.test pattern file.
|
||||
|
||||
:param text: The contents of a *.test file.
|
||||
"""
|
||||
|
||||
def __init__(self, text: str):
|
||||
patterns = []
|
||||
for line in text.splitlines():
|
||||
if (m := _pattern_re.match(line)) is not None:
|
||||
patterns.append(logic.mvarray(m.group(1)))
|
||||
|
||||
self.patterns = np.stack(patterns, axis=-1) if patterns \
|
||||
else np.zeros((0, 0), dtype=np.uint8)
|
||||
"""The parsed patterns as a mvarray (see :py:mod:`~kyupy.logic`).
|
||||
|
||||
The second-to-last axis goes along primary inputs, the last axis goes along patterns.
|
||||
"""
|
||||
|
||||
def tests(self, circuit: Circuit):
|
||||
"""Assembles and returns the test pattern set for the given circuit.
|
||||
|
||||
:param circuit: The circuit to assemble the patterns for. The patterns will follow the
|
||||
:py:attr:`~kyupy.circuit.Circuit.io_nodes` ordering of the circuit.
|
||||
:return: A logic array (see :py:mod:`~kyupy.logic`). The values for primary inputs are
|
||||
filled, all other values are left unassigned.
|
||||
"""
|
||||
pi_locs = [i for i, n in enumerate(circuit.io_nodes) if len(n.ins) == 0]
|
||||
tests = np.full((len(circuit.io_nodes), self.patterns.shape[-1]), logic.UNASSIGNED, dtype=np.uint8)
|
||||
tests[pi_locs] = self.patterns
|
||||
return tests
|
||||
|
||||
|
||||
def parse(text) -> TestFile:
|
||||
"""Parses the given ``text`` and returns a :class:`TestFile` object."""
|
||||
return TestFile(text)
|
||||
|
||||
|
||||
def load(file) -> TestFile:
|
||||
"""Parses the contents of ``file`` and returns a :class:`TestFile` object.
|
||||
|
||||
Files with `.gz`-suffix are decompressed on-the-fly.
|
||||
"""
|
||||
return parse(readtext(file))
|
||||
@@ -0,0 +1,29 @@
|
||||
import numpy as np
|
||||
|
||||
from kyupy import atalanta, logic
|
||||
|
||||
|
||||
def test_parse():
|
||||
text = '\n'.join([
|
||||
'* Test pattern file',
|
||||
'1: 0011',
|
||||
'2: 1100',
|
||||
'1010',
|
||||
])
|
||||
tf = atalanta.parse(text)
|
||||
|
||||
# second-to-last axis = inputs, last axis = patterns
|
||||
assert tf.patterns.shape == (4, 3)
|
||||
assert tf.patterns.dtype == np.uint8
|
||||
assert set(np.unique(tf.patterns)) <= {logic.ZERO, logic.ONE}
|
||||
|
||||
# patterns are stored along the last axis
|
||||
assert list(tf.patterns[:, 0]) == [logic.ZERO, logic.ZERO, logic.ONE, logic.ONE]
|
||||
assert list(tf.patterns[:, 1]) == [logic.ONE, logic.ONE, logic.ZERO, logic.ZERO]
|
||||
assert list(tf.patterns[:, 2]) == [logic.ONE, logic.ZERO, logic.ONE, logic.ZERO]
|
||||
|
||||
|
||||
def test_empty():
|
||||
tf = atalanta.parse('* only comments\n* nothing else\n')
|
||||
assert tf.patterns.shape == (0, 0)
|
||||
assert tf.patterns.dtype == np.uint8
|
||||
Reference in new issue
Block a user