timfuz: make rref deterministic

Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
John McMaster 2018-09-19 11:53:57 -07:00
parent 7c0828e6c2
commit ee3ef206ad
4 changed files with 103 additions and 28 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from timfuz import Benchmark, Ar_di2np, loadc_Ads_b, index_names, A_ds2np, simplify_rows
from timfuz import Benchmark, Ar_di2np, loadc_Ads_b, index_names, A_ds2np, simplify_rows, OrderedSet
import numpy as np
import glob
import math
@ -27,14 +27,15 @@ class State(object):
self.names = index_names(self.Ads)
# known zero delay elements
self.drop_names = set(drop_names)
self.drop_names = OrderedSet(drop_names)
# active names in rows
# includes sub variables, excludes variables that have been substituted out
self.base_names = set(self.names)
self.base_names = OrderedSet(self.names)
#self.names = OrderedSet(self.base_names)
self.names = set(self.base_names)
# List of variable substitutions
# k => dict of v:n entries that it came from
self.subs = {}
self.subs = OrderedDict()
self.verbose = True
def print_stats(self):
@ -63,11 +64,16 @@ class State(object):
def write_state(state, fout):
j = {
'names': dict([(x, None) for x in state.names]),
'drop_names': list(state.drop_names),
'base_names': list(state.base_names),
'subs': dict([(name, values) for name, values in state.subs.items()]),
'pivots': state.pivots,
'names':
OrderedDict([(x, None) for x in state.names]),
'drop_names':
list(state.drop_names),
'base_names':
list(state.base_names),
'subs':
OrderedDict([(name, values) for name, values in state.subs.items()]),
'pivots':
state.pivots,
}
json.dump(j, fout, sort_keys=True, indent=4, separators=(',', ': '))
@ -89,7 +95,7 @@ def Anp2matrix(Anp):
def row_np2ds(rownp, names):
ret = {}
ret = OrderedDict()
assert len(rownp) == len(names), (len(rownp), len(names))
for namei, name in enumerate(names):
v = rownp[namei]
@ -102,7 +108,7 @@ def row_sym2dsf(rowsym, names):
'''Convert a sympy row into a dictionary of keys to (numerator, denominator) tuples'''
from sympy import fraction
ret = {}
ret = OrderedDict()
assert len(rowsym) == len(names), (len(rowsym), len(names))
for namei, name in enumerate(names):
v = rowsym[namei]
@ -145,7 +151,7 @@ def state_rref(state, verbose=False):
print('rref')
sympy.pprint(rref)
state.pivots = {}
state.pivots = OrderedDict()
def row_solved(rowsym, row_pivot):
for ci, c in enumerate(rowsym):
@ -177,7 +183,7 @@ def state_rref(state, verbose=False):
state.names.add(group_name)
# Remove substituted variables
# Note: variables may appear multiple times
state.names.difference_update(set(rowdsf.keys()))
state.names.difference_update(OrderedSet(rowdsf.keys()))
pivot_name = names[row_pivot]
state.pivots[group_name] = pivot_name
if verbose:

View File

@ -192,7 +192,8 @@ def main():
parser.add_argument('--verbose', action='store_true', help='')
parser.add_argument('--massage', action='store_true', help='')
parser.add_argument('--bounds-csv', help='Previous solve result starting point')
parser.add_argument(
'--bounds-csv', help='Previous solve result starting point')
parser.add_argument(
'--sub-json', help='Group substitutions to make fully ranked')
parser.add_argument('--corner', required=True, default="slow_max", help='')

View File

@ -7,7 +7,6 @@ import json
def run_types(tilej, verbose=False):
def process(etype):
# dict[model] = set((tile, wire/pip))
zeros = {}
@ -19,7 +18,9 @@ def run_types(tilej, verbose=False):
zeros.setdefault(emodel, set()).add((tilek, ename))
# Print out delay model instances
print('%s ZERO types: %u, %s' % (etype, len(zeros), zeros.keys()))
print('%s ZERO instances: %u' % (etype, sum([len(x) for x in zeros.values()])))
print(
'%s ZERO instances: %u' %
(etype, sum([len(x) for x in zeros.values()])))
for model in sorted(zeros.keys()):
modelv = zeros[model]
print('Model: %s' % model)
@ -30,8 +31,8 @@ def run_types(tilej, verbose=False):
print('')
process('pips')
def run_prefix(tilej, verbose=False):
def run_prefix(tilej, verbose=False):
def process(etype):
prefixes = set()
print('Processing %s' % etype)
@ -48,6 +49,7 @@ def run_prefix(tilej, verbose=False):
print('')
process('pips')
def run(fnin, verbose=False):
tilej = json.load((open(fnin, 'r')))
run_types(tilej)
@ -55,11 +57,16 @@ def run(fnin, verbose=False):
print('')
run_prefix(tilej)
def main():
import argparse
parser = argparse.ArgumentParser(description='Solve timing solution')
parser.add_argument('fnin', default="../timgrid/build/timgrid-s.json", nargs='?', help='input timgrid JSON')
parser.add_argument(
'fnin',
default="../timgrid/build/timgrid-s.json",
nargs='?',
help='input timgrid JSON')
args = parser.parse_args()
run(args.fnin, verbose=False)

View File

@ -13,10 +13,76 @@ import sys
import random
import glob
from fractions import Fraction
import collections
from benchmark import Benchmark
NAME_ZERO = set(
# Equations are filtered out until nothing is left
class SimplifiedToZero(Exception):
pass
# http://code.activestate.com/recipes/576694/
class OrderedSet(collections.MutableSet):
def __init__(self, iterable=None):
self.end = end = []
end += [None, end, end] # sentinel node for doubly linked list
self.map = {} # key --> [key, prev, next]
if iterable is not None:
self |= iterable
def __len__(self):
return len(self.map)
def __contains__(self, key):
return key in self.map
def add(self, key):
if key not in self.map:
end = self.end
curr = end[1]
curr[2] = end[1] = self.map[key] = [key, curr, end]
def discard(self, key):
if key in self.map:
key, prev, next = self.map.pop(key)
prev[2] = next
next[1] = prev
def __iter__(self):
end = self.end
curr = end[2]
while curr is not end:
yield curr[0]
curr = curr[2]
def __reversed__(self):
end = self.end
curr = end[1]
while curr is not end:
yield curr[0]
curr = curr[1]
def pop(self, last=True):
if not self:
raise KeyError('set is empty')
key = self.end[1][0] if last else self.end[2][0]
self.discard(key)
return key
def __repr__(self):
if not self:
return '%s()' % (self.__class__.__name__, )
return '%s(%r)' % (self.__class__.__name__, list(self))
def __eq__(self, other):
if isinstance(other, OrderedSet):
return len(self) == len(other) and list(self) == list(other)
return set(self) == set(other)
NAME_ZERO = OrderedSet(
[
"BSW_CLK_ZERO",
"BSW_ZERO",
@ -40,11 +106,6 @@ corner_s2i = OrderedDict(
])
# Equations are filtered out until nothing is left
class SimplifiedToZero(Exception):
pass
def allow_zero_eqns():
return os.getenv('ALLOW_ZERO_EQN', 'N') == 'Y'
@ -148,7 +209,7 @@ def check_feasible(A_ub, b_ub):
def Ab_ub_dt2d(eqns):
'''Convert dict using the rows as keys into a list of dicts + b_ub list (ie return A_ub, b_ub)'''
#return [dict(rowt) for rowt in eqns]
rows = [(dict(rowt), b) for rowt, b in eqns.items()]
rows = [(OrderedDict(rowt), b) for rowt, b in eqns.items()]
A_ubd, b_ub = zip(*rows)
return list(A_ubd), list(b_ub)
@ -411,7 +472,7 @@ def derive_eq_by_col(A_ubd, b_ub, verbose=0):
b_ub[row_refi] /= v
knowns[k] = b_ub[row_refi]
print(' done')
#knowns_set = set(knowns.keys())
#knowns_set = OrderedSet(knowns.keys())
print('%d constrained' % len(knowns))
'''
Now see what we can do
@ -648,7 +709,7 @@ def loadc_Ads_raw(fns):
def index_names(Ads):
names = set()
names = OrderedSet()
for row_ds in Ads:
for k1 in row_ds.keys():
names.add(k1)
@ -740,7 +801,7 @@ def run_sub_json(Ads, sub_json, strict=False, verbose=False):
ncols_new = 0
print('Subbing %u rows' % len(Ads))
prints = set()
prints = OrderedSet()
for rowi, row in enumerate(Ads):
if 0 and verbose: