diff --git a/database/Makefile b/database/Makefile deleted file mode 100644 index 99fab407..00000000 --- a/database/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -.NOTPARALLEL: - -SUBDIRS := $(patsubst %/,%, $(wildcard */)) - -.PHONY: $(SUBDIRS) - -$(MAKECMDGOALS): $(SUBDIRS) - -$(SUBDIRS): - $(MAKE) -C $@ -f ../Makefile.database $(MAKECMDGOALS) diff --git a/database/Makefile.database b/database/Makefile.database deleted file mode 100644 index 2e407968..00000000 --- a/database/Makefile.database +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: all clean - -all: tilegrid.json - -# Small dance to say that there is a single recipe that is run once to generate -# multiple files. -tileconn.json tilegrid.json: fuzzers -.INTERMEDIATE: fuzzers -fuzzers: SHELL:=/bin/bash -fuzzers: settings.sh - source settings.sh && $(MAKE) -C ../../fuzzers all - -clean: - rm -f *.db tileconn.json tilegrid.json *.yaml - rm -rf html diff --git a/experiments/timfuz/timfuz_checksub.py b/experiments/timfuz/checksub.py similarity index 100% rename from experiments/timfuz/timfuz_checksub.py rename to experiments/timfuz/checksub.py diff --git a/experiments/timfuz/timfuz_corner_csv.py b/experiments/timfuz/corner_csv.py similarity index 100% rename from experiments/timfuz/timfuz_corner_csv.py rename to experiments/timfuz/corner_csv.py diff --git a/experiments/timfuz/timfuz_perf.py b/experiments/timfuz/perf_test.py similarity index 100% rename from experiments/timfuz/timfuz_perf.py rename to experiments/timfuz/perf_test.py diff --git a/experiments/timfuz/solve_leastsq.py b/experiments/timfuz/solve_leastsq.py new file mode 100644 index 00000000..b00c58ad --- /dev/null +++ b/experiments/timfuz/solve_leastsq.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 + +# https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.linprog.html +from scipy.optimize import linprog +from timfuz import Benchmark, Ar_di2np, Ar_ds2t, A_di2ds, A_ds2di, simplify_rows, loadc_Ads_b, index_names, A_ds2np, load_sub, run_sub_json, A_ub_np2d, print_eqns, print_eqns_np +from timfuz_massage import massage_equations +import numpy as np +import glob +import json +import math +from collections import OrderedDict +from fractions import Fraction +import sys +import datetime +import os +import time +import timfuz_solve +import numpy +import scipy.optimize as optimize +from scipy.optimize import least_squares + +def run_corner(Anp, b, names, verbose=False, opts={}, meta={}, outfn=None): + # Given timing scores for above delays (-ps) + assert type(Anp[0]) is np.ndarray, type(Anp[0]) + assert type(b) is np.ndarray, type(b) + + #check_feasible(Anp, b) + + ''' + Be mindful of signs + Have something like + timing1/timing 2 are constants + delay1 + delay2 + delay4 >= timing1 + delay2 + delay3 >= timing2 + + But need it in compliant form: + -delay1 + -delay2 + -delay4 <= -timing1 + -delay2 + -delay3 <= -timing2 + ''' + rows = len(Anp) + cols = len(Anp[0]) + + print('Unique delay elements: %d' % len(names)) + print('Input paths') + print(' # timing scores: %d' % len(b)) + print(' Rows: %d' % rows) + + ''' + You must have at least as many things to optimize as variables + That is, the system must be plausibly constrained for it to attempt a solve + If not, you'll get a message like + TypeError: Improper input: N=3 must not exceed M=2 + ''' + if rows < cols: + raise Exception("rows must be >= cols") + + def func(params, xdata, ydata): + return (ydata - np.dot(xdata, params)) + + print('') + # Now find smallest values for delay constants + # Due to input bounds (ex: column limit), some delay elements may get eliminated entirely + print('Running leastsq w/ %d r, %d c (%d name)' % (rows, cols, len(names))) + x0 = np.array([0.0 for _x in range(cols)]) + x, cov_x, infodict, mesg, ier = optimize.leastsq(func, x0, args=(Anp, b), full_output=True) + print('x', x) + print('cov_x', cov_x) + print('infodictx', infodict) + print('mesg', mesg) + print('ier', ier) + print(' Solution found: %s' % (ier in (1, 2, 3, 4))) + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description= + 'Solve timing solution' + ) + + parser.add_argument('--verbose', action='store_true', help='') + parser.add_argument('--massage', action='store_true', help='') + parser.add_argument('--sub-json', help='Group substitutions to make fully ranked') + parser.add_argument('--corner', default="slow_max", help='') + parser.add_argument('--out', default=None, help='output timing delay .json') + parser.add_argument( + 'fns_in', + nargs='*', + help='timing3.csv input files') + args = parser.parse_args() + # Store options in dict to ease passing through functions + bench = Benchmark() + + fns_in = args.fns_in + if not fns_in: + fns_in = glob.glob('specimen_*/timing3.csv') + + sub_json = None + if args.sub_json: + sub_json = load_sub(args.sub_json) + + try: + timfuz_solve.run(run_corner=run_corner, sub_json=sub_json, + fns_in=fns_in, corner=args.corner, massage=args.massage, outfn=args.out, verbose=args.verbose) + finally: + print('Exiting after %s' % bench) + +# optimize.curve_fit wrapper +def test1(): + # Generate artificial data = straight line with a=0 and b=1 + # plus some noise. + xdata = np.array([0.0,1.0,2.0,3.0,4.0,5.0]) + ydata = np.array([0.1,0.9,2.2,2.8,3.9,5.1]) + # Initial guess. + x0 = np.array([0.0, 0.0, 0.0]) + sigma = np.array([1.0,1.0,1.0,1.0,1.0,1.0]) + + def func(x, a, b, c): + return a + b*x + c*x*x + + print(optimize.curve_fit(func, xdata, ydata, x0, sigma)) + +# optimize.leastsq +def test2(): + + # The function whose square is to be minimised. + # params ... list of parameters tuned to minimise function. + # Further arguments: + # xdata ... design matrix for a linear model. + # ydata ... observed data. + def func(params, xdata, ydata): + return (ydata - np.dot(xdata, params)) + + x0 = np.array([0.0, 0.0]) + + ''' + a = 10 + a + b = 100 + ''' + xdata = np.array([[1, 0], + [1, 1]]) + ydata = np.array([10, 100]) + + ''' + x [ 10. 90.] + cov_x [[ 1. -1.] + [-1. 2.]] + infodictx {'ipvt': array([1, 2], dtype=int32), 'qtf': array([ 1.69649118e-10, 1.38802454e-10]), 'nfev': 7, 'fjac': array([[ 1.41421356, 0.70710678], + [ 0.70710678, 0.70710678]]), 'fvec': array([ 0., 0.])} + mesg The relative error between two consecutive iterates is at most 0.000000 + ier 2 + Solution found: True + ''' + x, cov_x, infodict, mesg, ier = optimize.leastsq(func, x0, args=(xdata, ydata), full_output=True) + print('x', x) + print('cov_x', cov_x) + print('infodictx', infodict) + print('mesg', mesg) + print('ier', ier) + print(' Solution found: %s' % (ier in (1, 2, 3, 4))) + +# non-square +def test3(): + def func(params, xdata, ydata): + return (ydata - np.dot(xdata, params)) + + x0 = np.array([0.0, 0.0, 0.0]) + + ''' + a = 10 + a + b + c = 100 + ''' + xdata = np.array([[1, 0, 0], + [1, 1, 1], + [0, 0, 0]]) + ydata = np.array([10, 100, 0]) + + x, cov_x, infodict, mesg, ier = optimize.leastsq(func, x0, args=(xdata, ydata), full_output=True) + print('x', x) + print('cov_x', cov_x) + print('infodictx', infodict) + print('mesg', mesg) + print('ier', ier) + print(' Solution found: %s' % (ier in (1, 2, 3, 4))) + +def test4(): + def func(params): + print('') + print('iter') + print(params) + print(xdata) + print(ydata) + return (ydata - np.dot(xdata, params)) + + x0 = np.array([0.0, 0.0, 0.0]) + + ''' + You must have at least as many things to optimize as variables + That is, the system must be plausibly constrained for it to attempt a solve + If not, you'll get a message like + TypeError: Improper input: N=3 must not exceed M=2 + ''' + xdata = np.array([[1, 0, 0], + [1, 1, 1], + [1, 0, 1], + [0, 1, 1], + ]) + ydata = np.array([10, 100, 120, 140]) + + x, cov_x, infodict, mesg, ier = optimize.leastsq(func, x0, full_output=True) + print('x', x) + print('cov_x', cov_x) + print('infodictx', infodict) + print('mesg', mesg) + print('ier', ier) + print(' Solution found: %s' % (ier in (1, 2, 3, 4))) + +def test5(): + from scipy.optimize import least_squares + + def fun_rosenbrock(x): + return np.array([10 * (x[1] - x[0]**2), (1 - x[0])]) + x0_rosenbrock = np.array([2, 2]) + res = least_squares(fun_rosenbrock, x0_rosenbrock) + ''' + active_mask: array([ 0., 0.]) + cost: 9.8669242910846867e-30 + fun: array([ 4.44089210e-15, 1.11022302e-16]) + grad: array([ -8.89288649e-14, 4.44089210e-14]) + jac: array([[-20.00000015, 10. ], + [ -1. , 0. ]]) + message: '`gtol` termination condition is satisfied.' + nfev: 3 + njev: 3 + optimality: 8.8928864934219529e-14 + status: 1 + success: True + x: array([ 1., 1.]) + ''' + print(res) + +def test6(): + from scipy.optimize import least_squares + + def func(params): + return (ydata - np.dot(xdata, params)) + + x0 = np.array([0.0, 0.0, 0.0]) + + ''' + a = 10 + a + b + c = 100 + ''' + xdata = np.array([[1, 0, 0], + [1, 1, 1], + [0, 0, 0]]) + ydata = np.array([10, 100, 0]) + + res = least_squares(func, x0) + ''' + ''' + print(res) + +if __name__ == '__main__': + #main() + #test1() + #test2() + #test3() + #test4() + #test5() + test6() + diff --git a/experiments/timfuz/solve_linprog.py b/experiments/timfuz/solve_linprog.py new file mode 100644 index 00000000..2eef5e75 --- /dev/null +++ b/experiments/timfuz/solve_linprog.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 + +# https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.linprog.html +from scipy.optimize import linprog +from timfuz import Benchmark, Ar_di2np, Ar_ds2t, A_di2ds, A_ds2di, simplify_rows, loadc_Ads_b, index_names, A_ds2np, load_sub, run_sub_json, A_ub_np2d, print_eqns, print_eqns_np +from timfuz_massage import massage_equations +import numpy as np +import glob +import json +import math +from collections import OrderedDict +from fractions import Fraction +import sys +import datetime +import os +import time +import timfuz_solve + +def run_corner(Anp, b, names, verbose=False, opts={}, meta={}, outfn=None): + # Given timing scores for above delays (-ps) + assert type(Anp[0]) is np.ndarray, type(Anp[0]) + assert type(b) is np.ndarray, type(b) + + #check_feasible(Anp, b) + + ''' + Be mindful of signs + Have something like + timing1/timing 2 are constants + delay1 + delay2 + delay4 >= timing1 + delay2 + delay3 >= timing2 + + But need it in compliant form: + -delay1 + -delay2 + -delay4 <= -timing1 + -delay2 + -delay3 <= -timing2 + ''' + rows = len(Anp) + cols = len(Anp[0]) + print('Scaling to solution form...') + b_ub = -1.0 * b + #A_ub = -1.0 * Anp + A_ub = [-1.0 * x for x in Anp] + + if verbose: + print('') + print('A_ub b_ub') + print_eqns_np(A_ub, b_ub, verbose=verbose) + print('') + + print('Creating misc constants...') + # Minimization function scalars + # Treat all logic elements as equally important + c = [1 for _i in range(len(names))] + # Delays cannot be negative + # (this is also the default constraint) + #bounds = [(0, None) for _i in range(len(names))] + # Also you can provide one to apply to all + bounds = (0, None) + + # Seems to take about rows + 3 iterations + # Give some margin + #maxiter = int(1.1 * rows + 100) + #maxiter = max(1000, int(1000 * rows + 1000)) + # Most of the time I want it to just keep going unless I ^C it + maxiter = 1000000 + + if verbose >= 2: + print('b_ub', b) + print('Unique delay elements: %d' % len(names)) + print(' # delay minimization weights: %d' % len(c)) + print(' # delay constraints: %d' % len(bounds)) + print('Input paths') + print(' # timing scores: %d' % len(b)) + print(' Rows: %d' % rows) + + tlast = [time.time()] + iters = [0] + printn = [0] + def callback(xk, **kwargs): + iters[0] = kwargs['nit'] + if time.time() - tlast[0] > 1.0: + sys.stdout.write('I:%d ' % kwargs['nit']) + tlast[0] = time.time() + printn[0] += 1 + if printn[0] % 10 == 0: + sys.stdout.write('\n') + sys.stdout.flush() + + print('') + # Now find smallest values for delay constants + # Due to input bounds (ex: column limit), some delay elements may get eliminated entirely + print('Running linprog w/ %d r, %d c (%d name)' % (rows, cols, len(names))) + res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, callback=callback, + options={"disp": True, 'maxiter': maxiter, 'bland': True, 'tol': 1e-6,}) + nonzeros = 0 + print('Ran %d iters' % iters[0]) + if res.success: + print('Result sample (%d elements)' % (len(res.x))) + plim = 3 + for xi, (name, x) in enumerate(zip(names, res.x)): + nonzero = x >= 0.001 + if nonzero: + nonzeros += 1 + #if nonzero and (verbose >= 1 or xi > 30): + if nonzero and (verbose or ((nonzeros < 100 or nonzeros % 20 == 0) and nonzeros <= plim)): + print(' % 4u % -80s % 10.1f' % (xi, name, x)) + print('Delay on %d / %d' % (nonzeros, len(res.x))) + if not os.path.exists('res'): + os.mkdir('res') + fn_out = 'res/%s' % datetime.datetime.utcnow().isoformat().split('.')[0] + print('Writing %s' % fn_out) + np.save(fn_out, (3, c, A_ub, b_ub, bounds, names, res, meta)) + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description= + 'Solve timing solution' + ) + + parser.add_argument('--verbose', action='store_true', help='') + parser.add_argument('--massage', action='store_true', help='') + parser.add_argument('--sub-json', help='Group substitutions to make fully ranked') + parser.add_argument('--corner', default="slow_max", help='') + parser.add_argument('--out', default=None, help='output timing delay .json') + parser.add_argument( + 'fns_in', + nargs='*', + help='timing3.csv input files') + args = parser.parse_args() + # Store options in dict to ease passing through functions + bench = Benchmark() + + fns_in = args.fns_in + if not fns_in: + fns_in = glob.glob('specimen_*/timing3.csv') + + sub_json = None + if args.sub_json: + sub_json = load_sub(args.sub_json) + + try: + timfuz_solve.run(run_corner=run_corner, sub_json=sub_json, + fns_in=fns_in, corner=args.corner, massage=args.massage, outfn=args.out, verbose=args.verbose) + finally: + print('Exiting after %s' % bench) + +if __name__ == '__main__': + main() diff --git a/experiments/timfuz/timfuz_sub2csv.py b/experiments/timfuz/sub2csv.py similarity index 100% rename from experiments/timfuz/timfuz_sub2csv.py rename to experiments/timfuz/sub2csv.py diff --git a/experiments/timfuz/timfuz.py b/experiments/timfuz/timfuz.py index 01727a4b..d2bcd300 100644 --- a/experiments/timfuz/timfuz.py +++ b/experiments/timfuz/timfuz.py @@ -718,6 +718,9 @@ def load_sub(fn): return j def row_sub_syms(row, sub_json, verbose=False): + zero = Fraction(0) + zero = 0 + if 0 and verbose: print("") print(row.items()) @@ -751,8 +754,9 @@ def row_sub_syms(row, sub_json, verbose=False): if verbose: print('pivot %i %s' % (n, pivot)) for subk, subv in sorted(sub_json['subs'][group].items()): - oldn = row.get(subk, Fraction(0)) - rown = oldn - n * subv + oldn = row.get(subk, zero) + rown = -n * subv + rown += type(rown)(oldn) if verbose: print(" %s: %d => %d" % (subk, oldn, rown)) if rown == 0: @@ -768,8 +772,9 @@ def row_sub_syms(row, sub_json, verbose=False): # after all constants are applied, the row should end up positive? # numeric precision issues previously limited this # Ex: AssertionError: ('PIP_BSW_2ELSING0', -2.220446049250313e-16) - for k, v in sorted(row.items()): - assert v > 0, (k, v) + if 0: + for k, v in sorted(row.items()): + assert v > 0, (k, v) def run_sub_json(Ads, sub_json, verbose=False): nrows = 0 @@ -805,7 +810,7 @@ def run_sub_json(Ads, sub_json, verbose=False): print('') print("Sub: %u / %u rows changed" % (nsubs, nrows)) - print("Sub: %u => %u cols" % (ncols_old, ncols_new)) + print("Sub: %u => %u non-zero row cols" % (ncols_old, ncols_new)) def print_eqns(Ads, b, verbose=0, lim=3, label=''): rows = len(b) diff --git a/experiments/timfuz/timfuz_massage.py b/experiments/timfuz/timfuz_massage.py index 3c7b78b8..046886ce 100644 --- a/experiments/timfuz/timfuz_massage.py +++ b/experiments/timfuz/timfuz_massage.py @@ -322,6 +322,7 @@ def derive_eq_by_col(Ads, b_ub, verbose=0): print('Derive col: %d => %d rows' % (len(b_ub), len(b_ret))) return Ads_ret, b_ret +# keep derriving until solution is (probably) stable def massage_equations_old(Ads, b, verbose=False, derive_lim=3): ''' Equation pipeline @@ -392,7 +393,8 @@ def massage_equations_old(Ads, b, verbose=False, derive_lim=3): debug("final (sorted)") return Ads, b -def massage_equations_old2(Ads, b, verbose=False): +# iteratively increasing column limit until all columns are added +def massage_equations_inc_col_lim(Ads, b, verbose=False): ''' Equation pipeline Some operations may generate new equations @@ -463,7 +465,9 @@ def massage_equations_old2(Ads, b, verbose=False): print('Massage final: %d => %d rows' % (dstart, dend)) return Ads, b -def massage_equations(Ads, b, verbose=False): +# only derive based on nearby equations +# theory is they will be the best to diff +def massage_equations_near(Ads, b, verbose=False): ''' Equation pipeline Some operations may generate new equations @@ -525,3 +529,5 @@ def massage_equations(Ads, b, verbose=False): print('') print('Massage final: %d => %d rows' % (dstart, dend)) return Ads, b + +massage_equations = massage_equations_inc_col_lim diff --git a/experiments/timfuz/timfuz_solve.py b/experiments/timfuz/timfuz_solve.py index 356476e5..a2e6526a 100644 --- a/experiments/timfuz/timfuz_solve.py +++ b/experiments/timfuz/timfuz_solve.py @@ -32,9 +32,12 @@ def check_feasible(A_ub, b_ub): progress = max(1, rows / 100) - # Chose a high arbitrary value for x - # Delays should be in order of ns, so a 10 ns delay should be way above what anything should be - xs = [10e3 for _i in range(cols)] + ''' + Delays should be in order of ns, so a 10 ns delay should be way above what anything should be + Series can have several hundred delay elements + Max delay in ballpark + ''' + xs = [1e9 for _i in range(cols)] # FIXME: use the correct np function to do this for me # Verify bounds @@ -65,102 +68,14 @@ def check_feasible(A_ub, b_ub): raise Exception("Bad ") print(' done') -def run_corner(Anp, b, names, verbose=False, opts={}, meta={}): - # Given timing scores for above delays (-ps) - assert type(Anp[0]) is np.ndarray, type(Anp[0]) - assert type(b) is np.ndarray, type(b) +def instances(Ads): + ret = 0 + for row_ds in Ads: + ret += sum(row_ds.values()) + return ret - #check_feasible(Anp, b) - - ''' - Be mindful of signs - Have something like - timing1/timing 2 are constants - delay1 + delay2 + delay4 >= timing1 - delay2 + delay3 >= timing2 - - But need it in compliant form: - -delay1 + -delay2 + -delay4 <= -timing1 - -delay2 + -delay3 <= -timing2 - ''' - rows = len(Anp) - cols = len(Anp[0]) - print('Scaling to solution form...') - b_ub = -1.0 * b - #A_ub = -1.0 * Anp - A_ub = [-1.0 * x for x in Anp] - - if verbose: - print('') - print('A_ub b_ub') - print_eqns_np(A_ub, b_ub, verbose=verbose) - print('') - - print('Creating misc constants...') - # Minimization function scalars - # Treat all logic elements as equally important - c = [1 for _i in range(len(names))] - # Delays cannot be negative - # (this is also the default constraint) - #bounds = [(0, None) for _i in range(len(names))] - # Also you can provide one to apply to all - bounds = (0, None) - - # Seems to take about rows + 3 iterations - # Give some margin - #maxiter = int(1.1 * rows + 100) - #maxiter = max(1000, int(1000 * rows + 1000)) - # Most of the time I want it to just keep going unless I ^C it - maxiter = 1000000 - - if verbose >= 2: - print('b_ub', b) - print('Unique delay elements: %d' % len(names)) - print(' # delay minimization weights: %d' % len(c)) - print(' # delay constraints: %d' % len(bounds)) - print('Input paths') - print(' # timing scores: %d' % len(b)) - print(' Rows: %d' % rows) - - tlast = [time.time()] - iters = [0] - printn = [0] - def callback(xk, **kwargs): - iters[0] = kwargs['nit'] - if time.time() - tlast[0] > 1.0: - sys.stdout.write('I:%d ' % kwargs['nit']) - tlast[0] = time.time() - printn[0] += 1 - if printn[0] % 10 == 0: - sys.stdout.write('\n') - sys.stdout.flush() - - print('') - # Now find smallest values for delay constants - # Due to input bounds (ex: column limit), some delay elements may get eliminated entirely - print('Running linprog w/ %d r, %d c (%d name)' % (rows, cols, len(names))) - res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, callback=callback, - options={"disp": True, 'maxiter': maxiter, 'bland': True, 'tol': 1e-6,}) - nonzeros = 0 - print('Ran %d iters' % iters[0]) - if res.success: - print('Result sample (%d elements)' % (len(res.x))) - plim = 3 - for xi, (name, x) in enumerate(zip(names, res.x)): - nonzero = x >= 0.001 - if nonzero: - nonzeros += 1 - #if nonzero and (verbose >= 1 or xi > 30): - if nonzero and (verbose or ((nonzeros < 100 or nonzeros % 20 == 0) and nonzeros <= plim)): - print(' % 4u % -80s % 10.1f' % (xi, name, x)) - print('Delay on %d / %d' % (nonzeros, len(res.x))) - if not os.path.exists('res'): - os.mkdir('res') - fn_out = 'res/%s' % datetime.datetime.utcnow().isoformat().split('.')[0] - print('Writing %s' % fn_out) - np.save(fn_out, (3, c, A_ub, b_ub, bounds, names, res, meta)) - -def run(fns_in, corner, sub_json=None, dedup=True, massage=False, verbose=False): +def run(fns_in, corner, run_corner, sub_json=None, dedup=True, massage=False, outfn=None, verbose=False, **kwargs): + print('Loading data') Ads, b = loadc_Ads_b(fns_in, corner, ico=True) # Remove duplicate rows @@ -168,15 +83,19 @@ def run(fns_in, corner, sub_json=None, dedup=True, massage=False, verbose=False) # maybe better to just add them into the matrix directly if dedup: oldn = len(Ads) + iold = instances(Ads) Ads, b = simplify_rows(Ads, b) print('Simplify %u => %u rows' % (oldn, len(Ads))) - + print('Simplify %u => %u instances' % (iold, instances(Ads))) + if sub_json: print('Sub: %u rows' % len(Ads)) + iold = instances(Ads) names_old = index_names(Ads) run_sub_json(Ads, sub_json, verbose=verbose) names = index_names(Ads) print("Sub: %u => %u names" % (len(names_old), len(names))) + print('Sub: %u => %u instances' % (iold, instances(Ads))) else: names = index_names(Ads) @@ -187,46 +106,20 @@ def run(fns_in, corner, sub_json=None, dedup=True, massage=False, verbose=False) #print #col_dist(A_ubd, 'final', names) + ''' + Given: + a >= 10 + a + b >= 100 + A valid solution is: + a = 100 + However, a better solution is something like + a = 10 + b = 90 + This creates derived constraints to provide more realistic results + ''' if massage: Ads, b = massage_equations(Ads, b) print('Converting to numpy...') names, Anp = A_ds2np(Ads) - run_corner(Anp, np.asarray(b), names, verbose=verbose) - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Solve timing solution' - ) - - parser.add_argument('--verbose', action='store_true', help='') - parser.add_argument('--massage', action='store_true', help='') - parser.add_argument('--sub-json', help='Group substitutions to make fully ranked') - parser.add_argument('--corner', default="slow_max", help='') - parser.add_argument( - 'fns_in', - nargs='*', - help='timing3.csv input files') - args = parser.parse_args() - # Store options in dict to ease passing through functions - bench = Benchmark() - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing3.csv') - - sub_json = None - if args.sub_json: - sub_json = load_sub(args.sub_json) - - try: - run(sub_json=sub_json, - fns_in=fns_in, verbose=args.verbose, corner=args.corner, massage=args.massage) - finally: - print('Exiting after %s' % bench) - -if __name__ == '__main__': - main() + run_corner(Anp, np.asarray(b), names, outfn=outfn, verbose=verbose, **kwargs)