# The following are snap functions for finding a best approximated integer or rational number for a real number: import numpy as np from sympy import Rational def bestApproximation(x,imax): # The input is a numpy parameter vector p. # The output is an integer specifying which parameter to change, # and a float specifying the new value. def float2contfrac(x,nmax): x = float(x) c = [np.floor(x)]; y = x - np.floor(x) k = 0 while np.abs(y)!=0 and k 0: p = np.abs(q[:,0] / q[:,1] - abs(x)).astype(float) * (1 + np.abs(q[:,0])) * q[:,1] p = pval(p) i = np.argmin(p) return (xsign * q[i,0] / float(q[i,1]), xsign* q[i,0], q[i,1], p[i]) else: return (None, 0, 0, 1) def integerSnap(p, top=1): p = np.array(p) metric = np.abs(p - np.round(p.astype(np.double))) chosen = np.argsort(metric)[:top] return dict(list(zip(chosen, np.round(p.astype(np.double))[chosen]))) def zeroSnap(p, top=1): p = np.array(p) metric = np.abs(p) chosen = np.argsort(metric)[:top] return dict(list(zip(chosen, np.zeros(len(chosen))))) def rationalSnap(p, top=1): """Snap to nearest rational number using continued fraction.""" p = np.array(p) snaps = np.array(list(bestApproximation(x,10) for x in p)) chosen = np.argsort(snaps[:, 3])[:top] d = dict(list(zip(chosen, snaps[chosen, 1:3]))) d = {k: f"{val[0]}/{val[1]}" for k,val in d.items()} return d