mirror of https://github.com/openXC7/prjxray.git
timfuz: handle zeros more concretely
Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
parent
c2c996c706
commit
06d47dcb5e
|
|
@ -6,36 +6,48 @@ from timfuz import Benchmark, loadc_Ads_bs, load_sub, Ads2bounds, corners2csv, c
|
|||
def gen_flat(fns_in, sub_json, corner=None):
|
||||
Ads, bs = loadc_Ads_bs(fns_in, ico=True)
|
||||
bounds = Ads2bounds(Ads, bs)
|
||||
zeros = set()
|
||||
# Elements with zero delay assigned due to sub group
|
||||
group_zeros = set()
|
||||
# Elements with a concrete delay
|
||||
nonzeros = set()
|
||||
|
||||
if corner:
|
||||
zero_row = [None, None, None, None]
|
||||
zero_row[corner_s2i[corner]] = 0
|
||||
else:
|
||||
zero_row = None
|
||||
|
||||
for bound_name, bound_bs in bounds.items():
|
||||
sub = sub_json['subs'].get(bound_name, None)
|
||||
if sub:
|
||||
if bound_name in sub_json['zero_names']:
|
||||
if zero_row:
|
||||
yield bound_name, 0
|
||||
elif sub:
|
||||
print('sub', sub)
|
||||
# put entire delay into pivot
|
||||
pivot = sub_json['pivots'][bound_name]
|
||||
assert pivot not in zeros
|
||||
assert pivot not in group_zeros
|
||||
nonzeros.add(pivot)
|
||||
non_pivot = set(sub.keys() - set([pivot]))
|
||||
#for name in non_pivot:
|
||||
# assert name not in nonzeros, (pivot, name, nonzeros)
|
||||
zeros.update(non_pivot)
|
||||
group_zeros.update(non_pivot)
|
||||
yield pivot, bound_bs
|
||||
else:
|
||||
nonzeros.add(bound_name)
|
||||
yield bound_name, bound_bs
|
||||
# non-pivots can appear multiple times, but they should always be zero
|
||||
# however, due to substitution limitations, just warn
|
||||
violations = zeros.intersection(nonzeros)
|
||||
violations = group_zeros.intersection(nonzeros)
|
||||
if len(violations):
|
||||
print('WARNING: %s non-0 non-pivot' % (len(violations)))
|
||||
|
||||
# XXX: how to best handle these?
|
||||
# should they be fixed 0?
|
||||
if corner:
|
||||
zero_row = [None, None, None, None]
|
||||
zero_row[corner_s2i[corner]] = 0
|
||||
for zero in zeros - violations:
|
||||
if zero_row:
|
||||
print('zero_row', len(group_zeros), len(violations))
|
||||
for zero in group_zeros - violations:
|
||||
print('zero', zero)
|
||||
yield zero, zero_row
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,20 @@ import sympy
|
|||
from collections import OrderedDict
|
||||
from fractions import Fraction
|
||||
|
||||
def rm_zero_cols(Ads, verbose=True):
|
||||
removed = OrderedSet()
|
||||
|
||||
print('Removing ZERO elements')
|
||||
for row_ds in Ads:
|
||||
for k in set(row_ds.keys()):
|
||||
if k in removed:
|
||||
del row_ds[k]
|
||||
elif k.find('ZERO') >= 0:
|
||||
del row_ds[k]
|
||||
removed.add(k)
|
||||
if verbose:
|
||||
print(' Removing %s' % k)
|
||||
return removed
|
||||
|
||||
def fracr_quick(r):
|
||||
return [Fraction(numerator=int(x), denominator=1) for x in r]
|
||||
|
|
@ -20,14 +34,13 @@ def fracm_quick(m):
|
|||
print('fracm_quick type: %s' % t)
|
||||
return [fracr_quick(r) for r in m]
|
||||
|
||||
|
||||
class State(object):
|
||||
def __init__(self, Ads, drop_names=[]):
|
||||
def __init__(self, Ads, zero_names=[]):
|
||||
self.Ads = Ads
|
||||
self.names = index_names(self.Ads)
|
||||
|
||||
# known zero delay elements
|
||||
self.drop_names = OrderedSet(drop_names)
|
||||
self.zero_names = OrderedSet(zero_names)
|
||||
# active names in rows
|
||||
# includes sub variables, excludes variables that have been substituted out
|
||||
self.base_names = OrderedSet(self.names)
|
||||
|
|
@ -46,30 +59,34 @@ class State(object):
|
|||
" Largest: %u" % max([len(x) for x in self.subs.values()]))
|
||||
print(" Rows: %u" % len(self.Ads))
|
||||
print(
|
||||
" Cols (in): %u" % (len(self.base_names) + len(self.drop_names)))
|
||||
" Cols (in): %u" % (len(self.base_names) + len(self.zero_names)))
|
||||
print(" Cols (preprocessed): %u" % len(self.base_names))
|
||||
print(" Drop names: %u" % len(self.drop_names))
|
||||
print(" ZERO names: %u" % len(self.zero_names))
|
||||
print(" Cols (out): %u" % len(self.names))
|
||||
print(" Solvable vars: %u" % len(self.names & self.base_names))
|
||||
assert len(self.names) >= len(self.subs)
|
||||
|
||||
@staticmethod
|
||||
def load(fn_ins, simplify=False, corner=None):
|
||||
def load(fn_ins, simplify=False, corner=None, rm_zero=False):
|
||||
zero_names = OrderedSet()
|
||||
|
||||
Ads, b = loadc_Ads_b(fn_ins, corner=corner, ico=True)
|
||||
if rm_zero:
|
||||
zero_names = rm_zero_cols(Ads)
|
||||
if simplify:
|
||||
print('Simplifying corner %s' % (corner, ))
|
||||
Ads, b = simplify_rows(Ads, b, remove_zd=False, corner=corner)
|
||||
return State(Ads)
|
||||
return State(Ads, zero_names=zero_names)
|
||||
|
||||
|
||||
def write_state(state, fout):
|
||||
j = {
|
||||
'names':
|
||||
OrderedDict([(x, None) for x in state.names]),
|
||||
'drop_names':
|
||||
list(state.drop_names),
|
||||
'zero_names':
|
||||
sorted(list(state.zero_names)),
|
||||
'base_names':
|
||||
list(state.base_names),
|
||||
sorted(list(state.base_names)),
|
||||
'subs':
|
||||
OrderedDict([(name, values) for name, values in state.subs.items()]),
|
||||
'pivots':
|
||||
|
|
@ -172,11 +189,11 @@ def state_rref(state, verbose=False):
|
|||
return state
|
||||
|
||||
|
||||
def run(fnout, fn_ins, simplify=False, corner=None, verbose=0):
|
||||
def run(fnout, fn_ins, simplify=False, corner=None, rm_zero=False, verbose=0):
|
||||
print('Loading data')
|
||||
|
||||
assert len(fn_ins) > 0
|
||||
state = State.load(fn_ins, simplify=simplify, corner=corner)
|
||||
state = State.load(fn_ins, simplify=simplify, corner=corner, rm_zero=rm_zero)
|
||||
state_rref(state, verbose=verbose)
|
||||
state.print_stats()
|
||||
if fnout:
|
||||
|
|
@ -195,6 +212,7 @@ def main():
|
|||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--simplify', action='store_true', help='')
|
||||
parser.add_argument('--corner', default="slow_max", help='')
|
||||
parser.add_argument('--rm-zero', action='store_true', help='Remove ZERO elements')
|
||||
parser.add_argument(
|
||||
'--speed-json',
|
||||
default='build_speed/speed.json',
|
||||
|
|
@ -214,6 +232,7 @@ def main():
|
|||
fn_ins=fns_in,
|
||||
simplify=args.simplify,
|
||||
corner=args.corner,
|
||||
rm_zero=args.rm_zero,
|
||||
verbose=args.verbose)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
|
|
|||
|
|
@ -30,47 +30,6 @@ def mkestimate(Anp, b):
|
|||
return x0
|
||||
|
||||
|
||||
def save(outfn, xvals, names, corner):
|
||||
# ballpark minimum actual observed delay is around 7 (carry chain)
|
||||
# anything less than one is probably a solver artifact
|
||||
delta = 0.5
|
||||
corneri = corner_s2i[corner]
|
||||
|
||||
# Round conservatively
|
||||
roundf = {
|
||||
'fast_max': math.ceil,
|
||||
'fast_min': math.floor,
|
||||
'slow_max': math.ceil,
|
||||
'slow_min': math.floor,
|
||||
}[corner]
|
||||
|
||||
print('Writing results')
|
||||
skips = 0
|
||||
keeps = 0
|
||||
with open(outfn, 'w') as fout:
|
||||
# write as one variable per line
|
||||
# this natively forms a bound if fed into linprog solver
|
||||
fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n')
|
||||
for xval, name in zip(xvals, names):
|
||||
row_ico = 1
|
||||
|
||||
# also review ceil vs floor choice for min vs max
|
||||
# lets be more conservative for now
|
||||
if xval < delta:
|
||||
#print('Skipping %s: %0.6f' % (name, xval))
|
||||
skips += 1
|
||||
continue
|
||||
keeps += 1
|
||||
#xvali = round(xval)
|
||||
|
||||
items = [str(row_ico), acorner2csv(roundf(xval), corneri)]
|
||||
items.append('%u %s' % (1, name))
|
||||
fout.write(','.join(items) + '\n')
|
||||
print(
|
||||
'Wrote: skip %u => %u / %u valid delays' % (skips, keeps, len(names)))
|
||||
assert keeps, 'Failed to estimate delay'
|
||||
|
||||
|
||||
def run_corner(
|
||||
Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None):
|
||||
# Given timing scores for above delays (-ps)
|
||||
|
|
@ -140,7 +99,7 @@ def run_corner(
|
|||
print('Done')
|
||||
|
||||
if outfn:
|
||||
save(outfn, res.x, names, corner)
|
||||
timfuz_solve.solve_save(outfn, res.x, names, corner, verbose=verbose)
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
|||
|
|
@ -12,50 +12,12 @@ import time
|
|||
import timfuz_solve
|
||||
|
||||
|
||||
def save(outfn, xvals, names, corner):
|
||||
# ballpark minimum actual observed delay is around 7 (carry chain)
|
||||
# anything less than one is probably a solver artifact
|
||||
delta = 0.5
|
||||
corneri = corner_s2i[corner]
|
||||
|
||||
roundf = {
|
||||
'fast_max': math.ceil,
|
||||
'fast_min': math.floor,
|
||||
'slow_max': math.ceil,
|
||||
'slow_min': math.floor,
|
||||
}[corner]
|
||||
|
||||
print('Writing results')
|
||||
zeros = 0
|
||||
with open(outfn, 'w') as fout:
|
||||
# write as one variable per line
|
||||
# this natively forms a bound if fed into linprog solver
|
||||
fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n')
|
||||
for xval, name in zip(xvals, names):
|
||||
row_ico = 1
|
||||
|
||||
# FIXME: only report for the given corner?
|
||||
# also review ceil vs floor choice for min vs max
|
||||
# lets be more conservative for now
|
||||
if xval < delta:
|
||||
print('WARNING: near 0 delay on %s: %0.6f' % (name, xval))
|
||||
zeros += 1
|
||||
#continue
|
||||
items = [str(row_ico), acorner2csv(roundf(xval), corneri)]
|
||||
items.append('%u %s' % (1, name))
|
||||
fout.write(','.join(items) + '\n')
|
||||
nonzeros = len(names) - zeros
|
||||
print(
|
||||
'Wrote: %u / %u constrained delays, %u zeros' %
|
||||
(nonzeros, len(names), zeros))
|
||||
|
||||
|
||||
def run_corner(
|
||||
Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None):
|
||||
if len(Anp) == 0:
|
||||
print('WARNING: zero equations')
|
||||
if outfn:
|
||||
save(outfn, [], [], corner)
|
||||
timfuz_solve.solve_save(outfn, [], [], corner)
|
||||
return
|
||||
maxcorner = {
|
||||
'slow_max': True,
|
||||
|
|
@ -180,7 +142,7 @@ def run_corner(
|
|||
print('Delay on %d / %d' % (nonzeros, len(res.x)))
|
||||
|
||||
if outfn:
|
||||
save(outfn, res.x, names, corner)
|
||||
timfuz_solve.solve_save(outfn, res.x, names, corner, verbose=verbose)
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ corner_s2i = OrderedDict(
|
|||
|
||||
|
||||
def allow_zero_eqns():
|
||||
'''If true, allow a system of equations with no equations'''
|
||||
return os.getenv('ALLOW_ZERO_EQN', 'N') == 'Y'
|
||||
|
||||
|
||||
|
|
@ -732,7 +733,7 @@ def row_sub_vars(row, sub_json, strict=False, verbose=False):
|
|||
print(row.items())
|
||||
|
||||
delvars = 0
|
||||
for k in sub_json['drop_names']:
|
||||
for k in sub_json['zero_names']:
|
||||
try:
|
||||
del row[k]
|
||||
delvars += 1
|
||||
|
|
@ -908,3 +909,7 @@ def tilej_stats(tilej):
|
|||
print(
|
||||
' %s: %u / %u solved, %u / %u covered' %
|
||||
(etype, solved, net, covered, net))
|
||||
|
||||
def load_bounds(bounds_csv, corner, ico=True):
|
||||
Ads, b = loadc_Ads_b([bounds_csv], corner, ico=ico)
|
||||
return Ads2bounds(Ads, b)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from timfuz import simplify_rows, loadc_Ads_b, index_names, A_ds2np, run_sub_json, print_eqns, Ads2bounds, instances, SimplifiedToZero, allow_zero_eqns
|
||||
from timfuz import simplify_rows, loadc_Ads_b, index_names, A_ds2np, run_sub_json, print_eqns, Ads2bounds, instances, SimplifiedToZero, allow_zero_eqns, corner_s2i, acorner2csv
|
||||
from timfuz_massage import massage_equations
|
||||
import numpy as np
|
||||
import sys
|
||||
import math
|
||||
|
||||
|
||||
def check_feasible(A_ub, b_ub):
|
||||
|
|
@ -93,6 +94,44 @@ def filter_bounds(Ads, b, bounds, corner):
|
|||
return ret_Ads, ret_b
|
||||
|
||||
|
||||
def solve_save(outfn, xvals, names, corner, save_zero=True, verbose=False):
|
||||
# ballpark minimum actual observed delay is around 7 (carry chain)
|
||||
# anything less than one is probably a solver artifact
|
||||
delta = 0.5
|
||||
corneri = corner_s2i[corner]
|
||||
|
||||
roundf = {
|
||||
'fast_max': math.ceil,
|
||||
'fast_min': math.floor,
|
||||
'slow_max': math.ceil,
|
||||
'slow_min': math.floor,
|
||||
}[corner]
|
||||
|
||||
print('Writing results')
|
||||
zeros = 0
|
||||
with open(outfn, 'w') as fout:
|
||||
# write as one variable per line
|
||||
# this natively forms a bound if fed into linprog solver
|
||||
fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n')
|
||||
for xval, name in zip(xvals, names):
|
||||
row_ico = 1
|
||||
|
||||
if xval < delta:
|
||||
if verbose:
|
||||
print('WARNING: near 0 delay on %s: %0.6f' % (name, xval))
|
||||
zeros += 1
|
||||
if not save_zero:
|
||||
continue
|
||||
items = [str(row_ico), acorner2csv(roundf(xval), corneri)]
|
||||
items.append('%u %s' % (1, name))
|
||||
fout.write(','.join(items) + '\n')
|
||||
nonzeros = len(names) - zeros
|
||||
print(
|
||||
'Wrote: %u / %u constrained delays, %u zeros' %
|
||||
(nonzeros, len(names), zeros))
|
||||
assert nonzeros, 'Failed to estimate delay'
|
||||
|
||||
|
||||
def run(
|
||||
fns_in,
|
||||
corner,
|
||||
|
|
|
|||
Loading…
Reference in New Issue