From a88d19e2dae7aff36d41905abb8b4de0c81782e8 Mon Sep 17 00:00:00 2001 From: Yuqing Date: Tue, 28 Nov 2023 12:53:28 -0800 Subject: [PATCH 1/3] fix issues in fdp converter --- autodp/converter.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/autodp/converter.py b/autodp/converter.py index bd740f6..8ff2f64 100644 --- a/autodp/converter.py +++ b/autodp/converter.py @@ -163,6 +163,7 @@ def fun(x): # the input the RDP's \alpha return np.log(1 / delta) / (x - 1) + rdp(x) results = minimize_scalar(fun, method='Brent', bracket=(1,2))#, bounds=[1, alpha_max]) + #results = minimize_scalar(fun, method='BBounded', bounds=[1, alpha_max]) if results.success: return results.fun else: @@ -736,13 +737,16 @@ def normal_equation_loglogx(loglogx): bound1 = np.log(-tmp - tmp**2 / 2 - tmp**3 / 6) else: bound1 = np.log(1-np.exp(fun1(np.log(1-delta)))) - #results = minimize_scalar(normal_equation, bracket=[-1,-2]) - results = minimize_scalar(normal_equation, method="Bounded", bounds=[bound1,0], - options={'xatol': 1e-10, 'maxiter': 500, 'disp': 0}) + results = minimize_scalar(normal_equation, bracket=[-0.5,-2]) + #results = minimize_scalar(normal_equation, method="Bounded", bounds=[bound1,0], + # options={'xatol': 1e-10, 'maxiter': 500, 'disp': 0}) if results.success: - if abs(results.fun) > 1e-4 and abs(results.x)>1e-10: + + if abs(results.fun) > 1e-3 and abs(results.x)>1e-10: # This means that we hit xatol (x is close to 0, but # the function value is not close to 0) In this case let's do an even larger search. + + print(f'err is {results.fun}, {results.x}') raise RuntimeError("'find_logx' fails to find the tangent line.") else: return results.x From 082b00ab56d56e8575190dc3bee3a279a6c490e9 Mon Sep 17 00:00:00 2001 From: Yuqing Date: Tue, 28 Nov 2023 12:57:48 -0800 Subject: [PATCH 2/3] fix issues in fdp converter again --- autodp/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autodp/converter.py b/autodp/converter.py index 8ff2f64..c133f30 100644 --- a/autodp/converter.py +++ b/autodp/converter.py @@ -737,7 +737,7 @@ def normal_equation_loglogx(loglogx): bound1 = np.log(-tmp - tmp**2 / 2 - tmp**3 / 6) else: bound1 = np.log(1-np.exp(fun1(np.log(1-delta)))) - results = minimize_scalar(normal_equation, bracket=[-0.5,-2]) + results = minimize_scalar(normal_equation, bracket=[-1,-2]) #results = minimize_scalar(normal_equation, method="Bounded", bounds=[bound1,0], # options={'xatol': 1e-10, 'maxiter': 500, 'disp': 0}) if results.success: From 586959456a171ebf2c9155342e699de1413f5365 Mon Sep 17 00:00:00 2001 From: Yuqing Date: Tue, 5 Dec 2023 11:51:16 -0800 Subject: [PATCH 3/3] rebase to the old cdf to approxdp converter --- autodp/converter.py | 57 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/autodp/converter.py b/autodp/converter.py index c133f30..f465bdd 100644 --- a/autodp/converter.py +++ b/autodp/converter.py @@ -737,11 +737,11 @@ def normal_equation_loglogx(loglogx): bound1 = np.log(-tmp - tmp**2 / 2 - tmp**3 / 6) else: bound1 = np.log(1-np.exp(fun1(np.log(1-delta)))) - results = minimize_scalar(normal_equation, bracket=[-1,-2]) - #results = minimize_scalar(normal_equation, method="Bounded", bounds=[bound1,0], - # options={'xatol': 1e-10, 'maxiter': 500, 'disp': 0}) - if results.success: + #results = minimize_scalar(normal_equation, bracket=[-1,-2]) + results = minimize_scalar(normal_equation, method="Bounded", bounds=[bound1, 0], + options={'xatol': 1e-10, 'maxiter': 500, 'disp': 0}) + if results.success: if abs(results.fun) > 1e-3 and abs(results.x)>1e-10: # This means that we hit xatol (x is close to 0, but # the function value is not close to 0) In this case let's do an even larger search. @@ -815,9 +815,48 @@ def approxdp(delta): +# The following version is used in the original paper. +def cdf_to_approxdp(cdf_p,cdf_q, quadrature=True): + """ + given cdf function, output (epsilon, delta) + when take_log is true, the cdf is for log(p/q) + when take_log is false, the cdf is for p/q + """ -def cdf_to_approxdp(cdf_p,cdf_q, quadrature=True): + def trade_off(threshold): + left = 0 + right = 100# the range of e^epsilon + mid = (left+right)*1.0/2 + while left1e-3): + #cur_value = cdf(np.log(mid)) + mid * cdf(-np.log(mid)) + cur_value = cdf_p(np.log(mid)) + mid * cdf_q(-np.log(mid)) + #print('cur delta before', 1-cur_value, 'cdf',cdf_p(np.log(mid))) + if np.abs(1-cur_value - threshold) < 1e-5: + return mid + if (right - left <= 1e-2): + return mid + print('current delta', 1-cur_value) + if 1-cur_value > threshold: + left = mid + else: + right = mid + + mid = (right + left)*1./2 + print('current search epsilon', np.log(mid)) + #print('left', left, 'right', right) + + + print('no solution found', 'current delta',1-cur_value, 'required delta',threshold) + + def approxdp(delta): + return np.log(trade_off(delta)) + + return approxdp + + +# TODO: fix the following numerical instable version. +def not_stable_cdf_to_approxdp(cdf_p,cdf_q, quadrature=True): """ Solve eps(delta) query by searching a pair of cdf such that delta(eps) = 1 - cdf_p(eps) - e^eps*cdf_q(-eps) @@ -827,6 +866,7 @@ def cdf_to_approxdp(cdf_p,cdf_q, quadrature=True): quadrature: if False, using a FFT-based numerical tool to convert characteristic functions back to cdf. """ + #print(f'***test cdf here {cdf_p(2)} {cdf_p(10)}') if quadrature == False: # Future work: convert characteristic functions to cdf using FFT. return cdf_to_approxdp_fft(cdf_p,cdf_q, l=1e5) @@ -839,7 +879,7 @@ def trade_off(x): print('Binary search epsilon',log_e, 'current delta', 1-result) return result # tol denotes the relative difference in delta term - exp_eps = numerical_inverse(trade_off, [0,1], tol=1e-2) + exp_eps = numerical_inverse(trade_off, [0,1], tol=1e-5) def approxdp(delta): t = exp_eps(1 - delta) return np.log(t) @@ -1097,8 +1137,9 @@ def normal_equation(x): return abs(fun(x)) #results = minimize_scalar(normal_equation, bounds=bounds, bracket=[1, 2], tol=1e-10) - results = minimize_scalar(normal_equation, bounds=bounds, bracket=[1,2], tol=tol) - + #results = minimize_scalar(normal_equation, bounds=bounds, bracket=[1,2], tol=tol) + results = minimize_scalar(normal_equation, method="Bounded", bounds=bounds, + options={'xatol': 1e-10, 'maxiter': 500, 'disp': 0}) #results = root_scalar(fun, options={'disp': False}) if results.success: