From bb0d68a4aa2a111441aa5933f1cac4f883b7e842 Mon Sep 17 00:00:00 2001 From: Nick Downing Date: Wed, 16 Jul 2025 00:31:43 +1000 Subject: [PATCH] New approach where all image processing is done in one pass, saving both net and adjacency information, then transistors are reconstructed from the adjacency --- .gitignore | 4 +- Makefile | 83 +++++++---------- conn_matrix.txt | 16 ++++ image_layers.py | 77 ++++++++++++++++ image_nets.py | 238 ++++++++++++++++++++++++++++++++++++++++++++++++ image_stack.py | 70 ++++++++++++++ layer.py | 114 ----------------------- layer_id.py | 28 ------ layers.py | 84 ----------------- layers_net.py | 53 ----------- net_channels.py | 61 +++++++++++++ net_image.py | 99 ++++++++++++++++++++ net_sizes.py | 30 ++++++ nets.py | 72 --------------- 14 files changed, 628 insertions(+), 401 deletions(-) create mode 100644 conn_matrix.txt create mode 100755 image_layers.py create mode 100755 image_nets.py create mode 100755 image_stack.py delete mode 100755 layer.py delete mode 100755 layer_id.py delete mode 100755 layers.py delete mode 100755 layers_net.py create mode 100755 net_channels.py create mode 100755 net_image.py create mode 100755 net_sizes.py delete mode 100755 nets.py diff --git a/.gitignore b/.gitignore index 1ef832f..7b6d975 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /*.png -/*.txt +/channels.txt +/nets.txt +/sizes.txt diff --git a/Makefile b/Makefile index 4028978..6bdc9e3 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,11 @@ all: \ +channels.txt \ +sizes.txt \ net_gnd.png \ net_vcc.png \ -metal_gnd.png \ -metal_vcc.png \ +net_phi0.png \ +net_phi1.png \ +layers.png #buried2.png \ #diff2.png \ #metal2.png \ @@ -10,61 +13,43 @@ metal_vcc.png \ #poly2.png \ #vias2.png -# GND is metal ID 0, corresponding net is found as follows: -# grep ' 1 0$' nets.txt -net_gnd.png: layers.txt nets.txt - ./layers_net.py $^ 17 $@ +channels.txt: nets.txt + ./net_channels.py nets.txt 2,3,4,5 >$@ -# VCC is metal ID 1, corresponding net is found as follows: -# grep ' 1 1$' nets.txt -net_vcc.png: layers.txt nets.txt - ./layers_net.py $^ 21 $@ +sizes.txt: nets.txt + ./net_sizes.py nets.txt >$@ -nets.txt: layers.txt - ./nets.py <$< >$@ +net_gnd.png: nets.txt + ./net_image.py --adjacency nets.txt 0 $@ 0,1,2,4,6,3,7,5 -layers.txt: \ -pads.txt \ -metal.txt \ -vias.txt \ -poly.txt \ -buried.txt \ -drain_source.txt \ -split_diff.txt - ./layers.py pads.txt,metal.txt,vias.txt,poly.txt,buried.txt,drain_source.txt,split_diff.txt 0:1,1:2,2:3,2:6,3:4,3:5,4:6,5:6 >$@ +net_vcc.png: nets.txt + ./net_image.py --adjacency nets.txt 1 $@ 0,1,2,4,6,3,7,5 -metal_gnd.png: metal.txt - ./layer_id.py $< 0 $@ +net_phi0.png: nets.txt + ./net_image.py --adjacency nets.txt 13812 $@ 0,1,2,4,6,3,7,5 -metal_vcc.png: metal.txt - ./layer_id.py $< 1 $@ +net_phi1.png: nets.txt + ./net_image.py --adjacency nets.txt 8126 $@ 0,1,2,4,6,3,7,5 -drain_source.txt: drain_source.png - ./layer.py $< >$@ +nets.txt: \ +metal.png \ +poly.png \ +split_diff.png \ +vias.png \ +pads.png \ +conn_matrix.txt + ./image_nets.py metal.png,poly.png,split_diff.png,vias.png,pads.png conn_matrix.txt $@ -split_diff.txt: split_diff.png - ./layer.py $< >$@ - -buried.txt: buried.png - ./layer.py $< >$@ - -metal.txt: metal.png - ./layer.py $< >$@ - -pads.txt: pads.png - ./layer.py $< >$@ - -poly.txt: poly.png - ./layer.py $< >$@ - -vias.txt: vias.png - ./layer.py $< >$@ - -drain_source.png: split_diff.png poly.png buried.png - ./boolean.py 'split_diff.png&poly.png&~+buried.png' $@ +layers.png: \ +metal.png \ +poly.png \ +split_diff.png \ +vias.png \ +pads.png + ./image_layers.py metal.png,poly.png,split_diff.png,vias.png,pads.png $@ 0,1,2,4,6,3,7,5 split_diff.png: diff.png poly.png buried.png - ./boolean.py 'diff.png&~(-poly.png&~buried.png)' $@ + ./image_stack.py diff.png,poly.png,buried.png $@ 0,1,0,3,0,1,0,2 buried.png: orig/AMD_8085_Buried_orig_7267w.png ./to_mono.py $< $@ @@ -121,4 +106,4 @@ vias2.png: vias1.png ./boolean.py 'vias.png^vias1.png' $@ clean: - rm -f *.png *.txt + rm -f *.png channels.txt sizes.txt nets.txt diff --git a/conn_matrix.txt b/conn_matrix.txt new file mode 100644 index 0000000..a6a4706 --- /dev/null +++ b/conn_matrix.txt @@ -0,0 +1,16 @@ +# 0: empty +# 1: metal -- merge if touches vias or pads +# 2: poly -- merge if touches vias or buried, report if touches channel +# 3: diff -- merge if touches vias or buried, report if touches channel +# 4: buried (diff) -- report if touches channel, cannot touch vias +# 5: channel (diff) -- cannot touch vias +# 6: vias -- cannot touch pads +# 7: pads +1 +0 1 +0 0 1 +0 0 0 1 +0 0 1 1 1 +0 0 2 2 2 1 +0 1 1 1 3 3 1 +0 1 0 0 0 0 3 1 diff --git a/image_layers.py b/image_layers.py new file mode 100755 index 0000000..bfea559 --- /dev/null +++ b/image_layers.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import PIL.Image +import numpy +import sys + +PALETTE = numpy.array( + [ + [0x00, 0x00, 0x00], + [0x00, 0x00, 0xff], + [0x00, 0xff, 0x00], + [0x00, 0xff, 0xff], + [0xff, 0x00, 0x00], + [0xff, 0x00, 0xff], + [0xff, 0xff, 0x00], + [0xff, 0xff, 0xff], + ], + numpy.uint8 +) + +PIL.Image.warnings.simplefilter('ignore', PIL.Image.DecompressionBombWarning) + +if len(sys.argv) < 3: + print( + f'usage: {sys.argv[0]:s} image_in,... image_out [colour,...]' + ) + sys.exit(1) +images_in = sys.argv[1].split(',') +image_out = sys.argv[2] +colours1 = ( + numpy.array([int(i) for i in sys.argv[3].split(',')], numpy.uint8) +if len(sys.argv) >= 4 else + None +) + +images = [] +colours = [1] +for i in range(len(images_in)): + print('image', i) + image_pil = PIL.Image.open(images_in[i]) + image_pil.load() + #print('mode', image_pil.mode) + #print('palette', image_pil.palette) + #print('width', image_pil.width) + #print('height', image_pil.height) + image = numpy.array(image_pil) + #print('shape', image.shape) + #print('dtype', image.dtype) + assert len(image.shape) == 2 + if image.dtype == bool: + n_colours = 2 + image = image.astype(numpy.uint8) + elif image.dtype == numpy.uint8: + n_colours = len(image_pil.palette.tobytes()) // 3 + else: + assert False + images.append(image) + colours.append(colours[-1] + n_colours - 1) +ys, xs = images[0].shape +assert all([i.shape == (ys, xs) for i in images[1:]]) + +image = numpy.zeros((ys, xs), numpy.uint8) +for i in range(len(images)): + mask = images[i] != 0 + image[mask] = images[i][mask] + (colours[i] - 1) + +if colours1 is None: + n_colours = colours[-1] +else: + n_colours = numpy.max(colours1) + 1 + image = colours1[image] +assert n_colours <= PALETTE.shape[0] + +image_pil = PIL.Image.new('P', (xs, ys), None) +image_pil.frombytes(image.tobytes()) +image_pil.putpalette(list(PALETTE[:n_colours, :].reshape((n_colours * 3,)))) +image_pil.save(image_out) diff --git a/image_nets.py b/image_nets.py new file mode 100755 index 0000000..6841568 --- /dev/null +++ b/image_nets.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 + +import PIL.Image +import numpy +import sys + +CONN_NONE = 0 +CONN_MERGE = 1 +CONN_REPORT = 2 +CONN_ABORT = 3 + +PIL.Image.warnings.simplefilter('ignore', PIL.Image.DecompressionBombWarning) + +if len(sys.argv) < 4: + print( + f'usage: {sys.argv[0]:s} image_in,... conn_matrix.txt nets.txt' + ) + sys.exit(1) +images_in = sys.argv[1].split(',') +conn_matrix_txt = sys.argv[2] +nets_txt = sys.argv[3] + +images = [] +colours = [1] +for i in range(len(images_in)): + print('image', i) + + image_pil = PIL.Image.open(images_in[i]) + image_pil.load() + #print('mode', image_pil.mode) + #print('palette', image_pil.palette) + #print('width', image_pil.width) + #print('height', image_pil.height) + + image = numpy.array(image_pil) + #print('shape', image.shape) + #print('dtype', image.dtype) + assert len(image.shape) == 2 + if image.dtype == bool: + n_colours = 2 + image = image.astype(numpy.uint8) + elif image.dtype == numpy.uint8: + n_colours = len(image_pil.palette.tobytes()) // 3 + else: + assert False + + images.append(image) + colours.append(colours[-1] + n_colours - 1) +ys, xs = images[0].shape +assert all([i.shape == (ys, xs) for i in images[1:]]) + +conn_matrix = numpy.identity(colours[-1], numpy.uint8) +with open(conn_matrix_txt) as fin: + colour = 0 + line = fin.readline() + while len(line): + i = line.find('#') + if i != -1: + line = line[:i] + fields = [int(i) for i in line.split()] + if len(fields): + assert colour < colours[-1] + assert len(fields) == colour + 1 + assert fields[-1] == 1 + conn_matrix[:colour, colour] = fields[:-1] + conn_matrix[colour, :colour] = fields[:-1] + colour += 1 + line = fin.readline() + +ptrs = [] +items = [] +for i in range(len(images)): + print('items', i) + + image_padded = numpy.zeros((ys, xs + 1), numpy.uint8) + image_padded[:, :-1] = images[i] + image_padded[image_padded != 0] += colours[i] - 1 + + image_delta = numpy.copy(image_padded) + image_delta[:, 1:] ^= image_delta[:, :-1] + nz_y, nz_x = numpy.nonzero(image_delta) + + for j in range(0, nz_y.shape[0] - 1): + y = nz_y[j] + x0 = nz_x[j] + colour = image_padded[y, x0] + if colour: + x1 = nz_x[j + 1] + while len(ptrs) <= i * ys + y: + ptrs.append(len(items)) + items.append([len(items), colour, y, x0, x1]) +while len(ptrs) <= len(images) * ys: + ptrs.append(len(items)) + +reports = [] +def merge(item0, item1): + net0 = item0 + i = items[net0][0] + while i != net0: + net0 = i + i = items[net0][0] + + net1 = item1 + i = items[net1][0] + while i != net1: + net1 = i + i = items[net1][0] + + net = min(net0, net1) + items[net0][0] = net + items[net1][0] = net + + net0 = item0 + while net0 != net: + i = items[net0][0] + items[net0][0] = net + net0 = i + + net1 = item1 + while net1 != net: + i = items[net1][0] + items[net1][0] = net + net1 = i +def end_to_end(p, q): + if q > p + 1: + i = p + _, colour0, y, x0, x1 = items[i] + i += 1 + while i < q: + _, colour1, _, x2, x3 = items[i] + if x1 == x2: + conn = conn_matrix[colour0, colour1] + if conn == CONN_NONE: + pass + elif conn == CONN_MERGE: + merge(i - 1, i) + elif conn == CONN_REPORT: + reports.append((i - 1, i)) + else: + print('colour0', colour0, 'y', y, 'x0', x0, 'x1', x1) + print('colour1', colour1, 'y', y, 'x2', x2, 'x3', x3) + assert False + i += 1 + colour0 = colour1 + x0 = x2 + x1 = x3 +def touch(p, q, r, s): + if q > p and s > r: + i = p + _, colour0, y0, x0, x1 = items[i] + j = r + _, colour1, y1, x2, x3 = items[j] + while True: + if x2 >= x1: + i += 1 + if i >= q: + break + _, colour0, _, x0, x1 = items[i] + elif x0 >= x3: + j += 1 + if j >= s: + break + _, colour1, _, x2, x3 = items[j] + else: + conn = conn_matrix[colour0, colour1] + if conn == CONN_NONE: + pass + elif conn == CONN_MERGE: + merge(i, j) + elif conn == CONN_REPORT: + reports.append((i, j)) + else: + print('colour0', colour0, 'y0', y0, 'x0', x0, 'x1', x1) + print('colour1', colour1, 'y1', y1, 'x2', x2, 'x3', x3) + assert False + + if x1 < x3: + i += 1 + if i >= q: + break + _, colour0, _, x0, x1 = items[i] + else: + j += 1 + if j >= s: + break + _, colour1, _, x2, x3 = items[j] + +for i in range(len(images)): + print('touch', i) + for j in range(ys): + end_to_end( + ptrs[i * ys + j], + ptrs[i * ys + j + 1] + ) + for j in range(ys - 1): + touch( + ptrs[i * ys + j], + ptrs[i * ys + j + 1], + ptrs[i * ys + j + 1], + ptrs[i * ys + j + 2] + ) +for i in range(len(images)): + for j in range(i + 1, len(images)): + if numpy.any( + conn_matrix[colours[i]:colours[i + 1], colours[j]:colours[j + 1]] + ): + print('touch', i, j) + for k in range(ys): + touch( + ptrs[i * ys + k], + ptrs[i * ys + k + 1], + ptrs[j * ys + k], + ptrs[j * ys + k + 1] + ) + +print('output') +with open(nets_txt, 'w') as fout: + print(colours[-1], ys, xs, file = fout) + print(len(items), file = fout) + for i in range(len(items)): + net, colour, y, x0, x1 = items[i] + + j = items[net][0] + while j != net: + net = j + j = items[net][0] + + j = i + while j != net: + k = items[j][0] + items[j][0] = net + j = k + + print(net, colour, y, x0, x1, file = fout) + + print(len(reports), file = fout) + for item0, item1 in reports: + print(item0, item1, file = fout) diff --git a/image_stack.py b/image_stack.py new file mode 100755 index 0000000..626b3dc --- /dev/null +++ b/image_stack.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import PIL.Image +import numpy +import sys + +PALETTE = numpy.array( + [ + [0x00, 0x00, 0x00], + [0x00, 0x00, 0xff], + [0x00, 0xff, 0x00], + [0x00, 0xff, 0xff], + [0xff, 0x00, 0x00], + [0xff, 0x00, 0xff], + [0xff, 0xff, 0x00], + [0xff, 0xff, 0xff], + ], + numpy.uint8 +) + +PIL.Image.warnings.simplefilter('ignore', PIL.Image.DecompressionBombWarning) + +if len(sys.argv) < 3: + print( + f'usage: {sys.argv[0]:s} image_in,... image_out [colour,...]' + ) + sys.exit(1) +images_in = sys.argv[1].split(',') +image_out = sys.argv[2] +colours = ( + numpy.array([int(i) for i in sys.argv[3].split(',')], numpy.uint8) +if len(sys.argv) >= 4 else + None +) + +images = [] +for image_in in images_in: + image_pil = PIL.Image.open(image_in) + image_pil.load() + #print('mode', image_pil.mode) + #print('palette', image_pil.palette) + #print('width', image_pil.width) + #print('height', image_pil.height) + image = numpy.array(image_pil) + #print('shape', image.shape) + #print('dtype', image.dtype) + assert len(image.shape) == 2 and image.dtype == bool + images.append(image) +ys, xs = images[0].shape +assert all([i.shape == (ys, xs) for i in images[1:]]) + +n = len(images) +assert n <= 8 +image = numpy.bitwise_or.reduce( + numpy.stack(images, 2).astype(numpy.uint8) << + numpy.arange(n, dtype = numpy.uint8)[numpy.newaxis, numpy.newaxis, :], + 2 +) + +if colours is None: + n_colours = 1 << n +else: + n_colours = numpy.max(colours) + 1 + image = colours[image] +assert n_colours <= PALETTE.shape[0] + +image_pil = PIL.Image.new('P', (xs, ys), None) +image_pil.frombytes(image.tobytes()) +image_pil.putpalette(list(PALETTE[:n_colours, :].reshape((n_colours * 3,)))) +image_pil.save(image_out) diff --git a/layer.py b/layer.py deleted file mode 100755 index 9c8d33e..0000000 --- a/layer.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python3 - -import PIL.Image -import numpy -import sys - -PIL.Image.warnings.simplefilter('ignore', PIL.Image.DecompressionBombWarning) - -if len(sys.argv) < 2: - print( - f'usage: {sys.argv[0]:s} image_in' - ) - sys.exit(1) -image_in = sys.argv[1] - -image = PIL.Image.open(image_in) -image.load() -#print('mode', image.mode) -#print('palette', image.palette) -#print('width', image.width) -#print('height', image.height) -image = numpy.array(image) -#print('shape', image.shape) -#print('dtype', image.dtype) -assert len(image.shape) == 2 and image.dtype == bool -ys, xs = image.shape - -image[:, 1:] ^= image[:, :-1] -nz_y, nz_x = numpy.nonzero(image) - -ptrs = [] -items = [] -for i in range(0, nz_y.shape[0], 2): - y = nz_y[i] - while len(ptrs) <= y: - ptrs.append(len(items)) - items.append([len(items), y, nz_x[i], nz_x[i + 1]]) -while len(ptrs) <= ys: - ptrs.append(len(items)) - -for i in range(ys - 1): - p = ptrs[i] - q = ptrs[i + 1] - r = ptrs[i + 2] - if q > p and r > q: - j = p - jid, _, jx0, jx1 = items[j] - k = q - kid, _, kx0, kx1 = items[k] - while True: - if kx0 >= jx1: - j += 1 - if j >= q: - break - jid, _, jx0, jx1 = items[j] - elif jx0 >= kx1: - k += 1 - if k >= r: - break - kid, _, kx0, kx1 = items[k] - else: - l = items[jid][0] - while l != jid: - jid = l - l = items[jid][0] - - l = items[kid][0] - while l != kid: - kid = l - l = items[kid][0] - - id = min(jid, kid) - items[jid][0] = id - items[kid][0] = id - - jid = j - while jid != id: - l = items[jid][0] - items[jid][0] = id - jid = l - - kid = k - while kid != id: - l = items[kid][0] - items[kid][0] = id - kid = l - - if jx1 < kx1: - j += 1 - if j >= q: - break - jid, _, jx0, jx1 = items[j] - else: - k += 1 - if k >= r: - break - kid, _, kx0, kx1 = items[k] - -print(ys, xs) -for i in range(len(items)): - id, y, x0, x1 = items[i] - - l = items[id][0] - while l != id: - id = l - l = items[id][0] - - l = i - while l != id: - m = items[l][0] - items[l][0] = id - l = m - - print(id, y, x0, x1) diff --git a/layer_id.py b/layer_id.py deleted file mode 100755 index 0a73c0b..0000000 --- a/layer_id.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -import PIL.Image -import numpy -import sys - -if len(sys.argv) < 4: - print( - f'usage: {sys.argv[0]:s} layer.txt id image_out' - ) - sys.exit(1) -layer_txt = sys.argv[1] -id = int(sys.argv[2]) -image_out = sys.argv[3] - -with open(layer_txt) as fin: - line = fin.readline() - assert len(line) - ys, xs = [int(i) for i in line.split()] - image = numpy.zeros((ys, xs), bool) - - line = fin.readline() - while len(line): - id1, y, x0, x1 = [int(i) for i in line.split()] - if id1 == id: - image[y, x0:x1] = True - line = fin.readline() -PIL.Image.fromarray(image).save(image_out) diff --git a/layers.py b/layers.py deleted file mode 100755 index 363708b..0000000 --- a/layers.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python3 - -import sys - -if len(sys.argv) < 3: - print( - f'usage: {sys.argv[0]:s} layer0.txt,layer1.txt,... l0:l1,l0:l2,...' - ) - sys.exit(1) -layers_in = sys.argv[1].split(',') -layer_pairs = [] -for i in sys.argv[2].split(','): - l0, l1 = [int(j) for j in i.split(':')] - layer_pairs.append((l0, l1)) - -layers = [] -for layer_in in layers_in: - with open(layer_in) as fin: - line = fin.readline() - assert len(line) - ys, xs = [int(i) for i in line.split()] - - ptrs = [] - items = [] - line = fin.readline() - while len(line): - id, y, x0, x1 = [int(i) for i in line.split()] - while len(ptrs) <= y: - ptrs.append(len(items)) - items.append((id, y, x0, x1)) - line = fin.readline() - while len(ptrs) <= ys: - ptrs.append(len(items)) - layers.append(((ys, xs), ptrs, items)) -(ys, xs) = layers[0][0] -assert all([i[0] == (ys, xs) for i in layers]) - -print(len(layers), ys, xs) -for _, _, items in layers: - print(len(items)) - for id, y, x0, x1 in items: - print(id, y, x0, x1) - -for l0, l1 in layer_pairs: - _, ptrs0, items0 = layers[l0] - _, ptrs1, items1 = layers[l1] - - found = set() - for i in range(ys): - p = ptrs0[i] - q = ptrs0[i + 1] - r = ptrs1[i] - s = ptrs1[i + 1] - if q > p and s > r: - j = p - jid, _, jx0, jx1 = items0[j] - k = r - kid, _, kx0, kx1 = items1[k] - while True: - if kx0 >= jx1: - j += 1 - if j >= q: - break - jid, _, jx0, jx1 = items0[j] - elif jx0 >= kx1: - k += 1 - if k >= s: - break - kid, _, kx0, kx1 = items1[k] - else: - key = (jid, kid) - if key not in found: - found.add(key) - print(l0, l1, jid, kid) - if jx1 < kx1: - j += 1 - if j >= q: - break - jid, _, jx0, jx1 = items0[j] - else: - k += 1 - if k >= s: - break - kid, _, kx0, kx1 = items1[k] diff --git a/layers_net.py b/layers_net.py deleted file mode 100755 index b3fe8ca..0000000 --- a/layers_net.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 - -import PIL.Image -import numpy -import sys - -if len(sys.argv) < 5: - print( - f'usage: {sys.argv[0]:s} layers.txt nets.txt net image_out' - ) - sys.exit(1) -layers_txt = sys.argv[1] -nets_txt = sys.argv[2] -net = int(sys.argv[3]) -image_out = sys.argv[4] - -with open(layers_txt) as fin: - line = fin.readline() - assert len(line) - n_layers, ys, xs = [int(i) for i in line.split()] - - items = [] - layers = [] - for i in range(n_layers): - line = fin.readline() - assert len(line) - n_items = int(line.rstrip()) - ids = {} - for j in range(n_items): - line = fin.readline() - assert len(line) - id, y, x0, x1 = [int(i) for i in line.split()] - if id not in ids: - ids[id] = [] - ids[id].append((y, x0, x1)) - layers.append(ids) - -image = numpy.zeros((ys, xs, 3), numpy.uint8) -with open(nets_txt) as fin: - line = fin.readline() - while len(line): - net1, layer, id = [int(i) for i in line.split()] - if net1 == net: - c = layer + 1 - c = numpy.array( - [((c >> 2) & 1) * 0xff, ((c >> 1) & 1) * 0xff, (c & 1) * 0xff], - numpy.uint8 - ) - for y, x0, x1 in layers[layer][id]: - image[y, x0:x1, :] = c[numpy.newaxis, :] - line = fin.readline() - -PIL.Image.fromarray(image).save(image_out) diff --git a/net_channels.py b/net_channels.py new file mode 100755 index 0000000..1336d66 --- /dev/null +++ b/net_channels.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +import numpy +import sys + +if len(sys.argv) < 3: + print( + f'usage: {sys.argv[0]:s} nets.txt poly_colour,diff_colour,buried_colour,channel_colour' + ) + sys.exit(1) +nets_txt = sys.argv[1] +poly_colour, diff_colour, buried_colour, channel_colour = \ + [int(i) for i in sys.argv[2].split(',')] +diff_colours = {diff_colour, buried_colour} + +with open(nets_txt) as fin: + line = fin.readline() + assert len(line) + + line = fin.readline() + assert len(line) + n_items = int(line.rstrip()) + + items = [] + channel_nets = {} + for i in range(n_items): + line = fin.readline() + assert len(line) + net, colour, y, x0, x1 = [int(i) for i in line.split()] + items.append((net, colour, y, x0, x1)) + if colour == channel_colour and net not in channel_nets: + channel_nets[net] = [] + + line = fin.readline() + assert len(line) + n_reports = int(line.rstrip()) + + for i in range(n_reports): + line = fin.readline() + assert len(line) + item0, item1 = [int(i) for i in line.split()] + net0 = items[item0][0] + net1 = items[item1][0] + if net0 in channel_nets: + channel_nets[net0].append(item1) + if net1 in channel_nets: + channel_nets[net1].append(item0) + +for channel_net, adjacent_items in sorted(channel_nets.items()): + #adjacent_nets = set([items[i][0] for i in adjacent_items]) + #adjacent_colours = set([items[i][1] for i in adjacent_items]) + #print('channel_net', channel_net, 'adjacent_nets', adjacent_nets, 'adjacent_colours', adjacent_colours) + + poly_nets = set( + [items[i][0] for i in adjacent_items if items[i][1] == poly_colour] + ) + diff_nets = set( + [items[i][0] for i in adjacent_items if items[i][1] in diff_colours] + ) + if len(poly_nets) != 1 or len(diff_nets) != 2: + print('channel_net', channel_net, 'poly_nets', poly_nets, 'diff_nets', diff_nets) diff --git a/net_image.py b/net_image.py new file mode 100755 index 0000000..4b0a0c6 --- /dev/null +++ b/net_image.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +import PIL.Image +import numpy +import sys + +PALETTE = numpy.array( + [ + [0x00, 0x00, 0x00], + [0x00, 0x00, 0xff], + [0x00, 0xff, 0x00], + [0x00, 0xff, 0xff], + [0xff, 0x00, 0x00], + [0xff, 0x00, 0xff], + [0xff, 0xff, 0x00], + [0xff, 0xff, 0xff], + ], + numpy.uint8 +) + +PIL.Image.warnings.simplefilter('ignore', PIL.Image.DecompressionBombWarning) + +adjacency = False +if len(sys.argv) >= 2 and sys.argv[1] == '--adjacency': + adjacency = True + del sys.argv[1] +if len(sys.argv) < 4: + print( + f'usage: {sys.argv[0]:s} [--adjacency] nets.txt net image_out [colour,...]' + ) + sys.exit(1) +nets_txt = sys.argv[1] +net = int(sys.argv[2]) +image_out = sys.argv[3] +colours = ( + numpy.array([int(i) for i in sys.argv[4].split(',')], numpy.uint8) +if len(sys.argv) >= 5 else + None +) + +with open(nets_txt) as fin: + line = fin.readline() + assert len(line) + n_colours, ys, xs = [int(i) for i in line.split()] + image = numpy.zeros((ys, xs), numpy.uint8) + + line = fin.readline() + assert len(line) + n_items = int(line.rstrip()) + + items = [] + for i in range(n_items): + line = fin.readline() + assert len(line) + net1, colour, y, x0, x1 = [int(i) for i in line.split()] + items.append((net1, colour, y, x0, x1)) + if net1 == net: + image[y, x0:x1] = colour + + if adjacency: + line = fin.readline() + assert len(line) + n_reports = int(line.rstrip()) + + adjacent_nets = set() + adjacent_colours = set() + for i in range(n_reports): + line = fin.readline() + assert len(line) + item0, item1 = [int(i) for i in line.split()] + if items[item0][0] == net: + if items[item1][0] == net: + continue + elif items[item1][0] == net: + item0, item1 = item1, item0 + else: + continue + + _, _, _, x0, x1 = items[item0] + net1, colour, y, x2, x3 = items[item1] + adjacent_nets.add(net1) + adjacent_colours.add(colour) + if x2 < x0 - 1: + x2 = x0 - 1 + if x3 > x1 + 1: + x3 = x1 + 1 + image[y, x2:x3] = colour + print('adjacent_nets', adjacent_nets) + print('adjacent_colours', adjacent_colours) +if colours is not None: + assert n_colours <= len(colours) + image = colours[image] + n_colours = numpy.max(colours) + 1 +assert n_colours <= PALETTE.shape[0] + +image_pil = PIL.Image.new('P', (xs, ys), None) +image_pil.frombytes(image.tobytes()) +image_pil.putpalette(list(PALETTE[:n_colours, :].reshape((n_colours * 3,)))) +image_pil.save(image_out) diff --git a/net_sizes.py b/net_sizes.py new file mode 100755 index 0000000..c9c4516 --- /dev/null +++ b/net_sizes.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import numpy +import sys + +if len(sys.argv) < 2: + print( + f'usage: {sys.argv[0]:s} nets.txt' + ) + sys.exit(1) +nets_txt = sys.argv[1] + +net_sizes = {} +with open(nets_txt) as fin: + line = fin.readline() + assert len(line) + + line = fin.readline() + assert len(line) + n_items = int(line.rstrip()) + + for i in range(n_items): + line = fin.readline() + assert len(line) + net, colour, y, x0, x1 = [int(i) for i in line.split()] + if net not in net_sizes: + net_sizes[net] = 0 + net_sizes[net] += x1 - x0 +for v, k in sorted([(v, k) for k, v in net_sizes.items()]): + print(k, v) diff --git a/nets.py b/nets.py deleted file mode 100755 index 3491e5e..0000000 --- a/nets.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 - -import numpy -import sys - -line = sys.stdin.readline() -assert len(line) -n_layers, ys, xs = [int(i) for i in line.split()] - -items = [] -layers = [] -for i in range(n_layers): - line = sys.stdin.readline() - assert len(line) - n_items = int(line.rstrip()) - ids = {} - for j in range(n_items): - line = sys.stdin.readline() - assert len(line) - id, _, _, _ = [int(i) for i in line.split()] - if id not in ids: - ids[id] = len(items) - items.append([len(items), i, id]) - layers.append(ids) - -line = sys.stdin.readline() -while len(line): - l0, l1, id0, id1 = [int(i) for i in line.split()] - # skip drain_source layer which separates nets by transistors - if l0 != 5 and l1 != 5: - net0 = layers[l0][id0] - n = items[net0][0] - while n != net0: - net0 = n - n = items[net0][0] - - net1 = layers[l1][id1] - n = items[net1][0] - while n != net1: - net1 = n - n = items[net1][0] - - net = min(net0, net1) - - net0 = layers[l0][id0] - while net0 != net: - n = items[net0][0] - items[net0][0] = net - net0 = n - - net1 = layers[l1][id1] - while net1 != net: - n = items[net1][0] - items[net1][0] = net - net1 = n - line = sys.stdin.readline() - -for i in range(len(items)): - net, layer, id = items[i] - - n = items[net][0] - while n != net: - net = n - n = items[net][0] - - n = i - while n != net: - o = items[n][0] - items[n][0] = net - n = o - - print(net, layer, id) -- 2.34.1