Source code for verf.StaticGraph

from typing import List

import networkx
from networkx import Graph
from z3 import Bool

from core.benchmarks.Benchmark import VerilogBenchmark
from core.expressions.BooleanExpression import LITERAL
from core.hardware.Crossbar import MemristorCrossbar
from verf.GraphBasedEquivalenceChecker import GraphBasedEquivalenceChecker
from utils.Z3Converter import Z3Converter


[docs] class StaticGraph(GraphBasedEquivalenceChecker): def __init__(self, crossbar: MemristorCrossbar, specification: VerilogBenchmark): super().__init__(crossbar, specification)
[docs] def get_simple_paths(self, output_variable: str) -> List[List[str]]: return self.simple_paths[output_variable]
[docs] def to_formula(self, output_variable: str, input_function: str = "1") -> Bool: assert isinstance(self.boolean_function, MemristorCrossbar) # Construct a bipartite graph where the rows and columns are nodes, and the intersections are edges. graph = Graph() edge_node_mapping = dict() for layer in range(self.boolean_function.layers): for r in range(self.boolean_function.rows): for c in range(self.boolean_function.columns): memristor = self.boolean_function.get_memristor(r, c, layer) if memristor.literal != LITERAL('False', False): if layer % 2 == 0: graph.add_edge("L_{}_{}".format(layer, r), "L_{}_{}".format(layer + 1, c), literal=memristor.literal) edge_node_mapping[("L{}_{}".format(layer, r), "C{}".format(layer + 1, c))] = str(memristor.literal) else: graph.add_edge("L_{}_{}".format(layer, c), "L_{}_{}".format(layer + 1, r), literal=memristor.literal) edge_node_mapping[("L{}_{}".format(layer, c), "C{}".format(layer + 1, r))] = str(memristor.literal) # for r in range(self.crossbar.rows): # for c in range(self.crossbar.columns): # memristor = self.crossbar.get_memristor(r, c) # if memristor.literal != LITERAL('False', False): # graph.add_edge("R{}".format(r), "C{}".format(c)) # edge_node_mapping[("R{}".format(r), "C{}".format(c))] = str(memristor.literal) input_layer, input_nanowire = self.boolean_function.get_input_nanowire(input_function) output_layer, output_nanowire = self.boolean_function.get_output_nanowire(output_variable) # Start a breadth-first search on a dynamic graph start_node = "L_{}_{}".format(output_layer, output_nanowire) end_node = "L_{}_{}".format(input_layer, input_nanowire) # start_node = "R{}".format(self.crossbar.output_nanowires[output_variable]) # end_node = "R{}".format(self.crossbar.input_nanowires[input_nanowire]) # Verify whether the required input nanowire and output nanowire are in the graph if start_node not in graph.nodes or end_node not in graph.nodes: return False paths = list(networkx.all_simple_edge_paths(graph, end_node, start_node)) simple_paths = [] for path in paths: simple_path = [] for (u, v) in path: if (u, v) in edge_node_mapping: simple_path.append(edge_node_mapping[(u, v)]) else: simple_path.append(edge_node_mapping[(v, u)]) simple_paths.append(simple_path) self.simple_paths[output_variable] = simple_paths formula = Z3Converter.simple_paths_to_z3(simple_paths) self.formulae[output_variable] = formula return formula