Research source · python

verify_persistent_selector.py

site/public/research-artifacts/replay-fanout/verify_persistent_selector.py

104 lines. Source is displayed for inspection; it is not executed by this page.

File fingerprint

SHA-256: 4409860c017433b6a8de3f7bbb88b705375a3146c39aad045bf63334de05ab0a

#!/usr/bin/env python3
"""Literal immutable-row interpreter versus independent language oracle."""
from itertools import product
import json


def follow(heap, root, path):
    for port in path:
        if root is None:
            return None
        root = heap[root][1][port]
    return root


def step(heap, mode, char, mutant=False):
    old = len(heap) - 1
    if mode == 'DATA' and char in '01':
        row = ('B' + char, (len(heap), follow(heap, old, (0,))))
        new_mode, accept = 'DATA', False
    elif (mode, char) == ('DATA', '#') or (mode, char) == ('QUERY', '0'):
        path = (0,) if mode == 'DATA' or mutant else (0, 1)
        head = follow(heap, old, path)
        row = ('W', (head, None))
        new_mode = 'QUERY'
        accept = head is not None and heap[head][0] == 'B1'
    else:
        row = ('W', (None, None))
        new_mode, accept = 'DEAD', False
    return heap + (row,), new_mode, accept


def oracle(word):
    if word.count('#') != 1:
        return False
    data, query = word.split('#')
    return (bool(data) and all(c in '01' for c in data)
            and all(c == '0' for c in query) and len(query) < len(data)
            and data[len(data) - len(query) - 1] == '1')


def run(word, mutant=False):
    heap, mode, accept = (('W', (None, None)),), 'DATA', False
    for char in word:
        heap, mode, accept = step(heap, mode, char, mutant)
    return heap, mode, accept


def chain(heap):
    head = follow(heap, len(heap)-1, (0,))
    result = []
    while head is not None:
        assert heap[head][0] in ('B0', 'B1')
        result.append(heap[head][0][1])
        head = heap[head][1][1]
    return ''.join(result)


def main():
    counts = dict(all_words=0, immutable_steps=0, chain_invariants=0,
                  selector_queries=0, residual_profiles=0, mutant_failures=0)
    witness = None
    def visit(word, heap, mode, accept):
        nonlocal witness
        counts['all_words'] += 1
        assert accept == oracle(word), word
        assert len(heap) == len(word) + 1
        if mode == 'DATA':
            assert chain(heap) == word[::-1]
            counts['chain_invariants'] += 1
        elif mode == 'QUERY':
            data, query = word.split('#')
            assert chain(heap) == data[::-1][len(query):]
            counts['chain_invariants'] += 1
        if run(word, mutant=True)[2] != oracle(word):
            counts['mutant_failures'] += 1
            if witness is None or (len(word), word) < (len(witness), witness):
                witness = word
        if len(word) == 10:
            return
        for char in '01#':
            new_heap, new_mode, new_accept = step(heap, mode, char)
            assert new_heap[:-1] == heap
            counts['immutable_steps'] += 1
            visit(word+char, new_heap, new_mode, new_accept)
    visit('', (('W', (None, None)),), 'DATA', False)
    for n in range(1, 11):
        profiles = set()
        for bits in product('01', repeat=n):
            data = ''.join(bits)
            answers = tuple(run(data + '#' + '0'*j)[2] for j in range(n))
            assert answers == tuple(bit == '1' for bit in data[::-1])
            profiles.add(answers)
            counts['selector_queries'] += n
        assert len(profiles) == 2**n
        counts['residual_profiles'] += len(profiles)
    assert witness is not None
    return dict(ok=True, counts=counts, alphabet='01#', max_word_length=10,
                max_data_length=10, degree=2, distance=2,
                nodes_per_symbol=1, mutation='replace pop path 01 by stay path 0',
                shortest_mutation_witness=witness)


if __name__ == '__main__':
    print(json.dumps(main(), indent=2, sort_keys=True))