diff --git a/code/lib/lmdk_bgt.py b/code/lib/lmdk_bgt.py index 5fe6ba7..1b21c3a 100644 --- a/code/lib/lmdk_bgt.py +++ b/code/lib/lmdk_bgt.py @@ -398,6 +398,61 @@ def adaptive_cont(seq, lmdks, epsilon, inc_rt, dec_rt): return rls_data, bgts, skipped +def adaptive_cons(seq, lmdks, epsilon, inc_rt, dec_rt): + ''' + Adaptive budget allocation. + + Parameters: + seq - The point sequence. + lmdks - The landmarks. + epsilon - The available privacy budget. + inc_rt - Sampling rate increase rate. + dec_rt - Sampling rate decrease rate. + Returns: + rls_data - The perturbed data. + bgts - The privacy budget allocation. + skipped - The number of skipped releases. + ''' + # Uniform budget allocation + bgts = uniform(seq, lmdks, epsilon) + # Released + rls_data = [None]*len(seq) + # The sampling rate + samp_rt = 1 + # Track landmarks + lmdk_cur = 0 + # Track skipped releases + skipped = 0 + for i, p in enumerate(seq): + # Check if current point is a landmark + is_landmark = any((lmdks[:]==p).all(1)) + if is_landmark: + lmdk_cur += 1 + if lmdk_lib.should_sample(samp_rt) or i == 0: + # Add noise to original data + o = lmdk_lib.add_laplace_noise(p[1], 1, bgts[i]) + rls_data[i] = [p[0], o] + # Adjust sampling rate + if i > 0: + if abs(rls_data[i - 1][1] - o) < 1/bgts[i]: + # Decrease + samp_rt -= samp_rt*dec_rt + else: + # Increase + samp_rt += (1 - samp_rt)*inc_rt + else: + skipped += 1 + # Skip current release and approximate with previous + rls_data[i] = rls_data[i - 1] + if is_landmark: + # Allocate the current budget to the following releases uniformly + for j in range(i + 1, len(seq)): + bgts[j] += bgts[i]/(len(lmdks) - lmdk_cur + 1) + # No budget was spent + bgts[i] = 0 + return rls_data, bgts, skipped + + def skip(seq, lmdks, epsilon): ''' Skip landmarks. @@ -459,6 +514,36 @@ def skip_cont(seq, lmdks, epsilon): return rls_data, bgts +def skip_cons(seq, lmdks, epsilon): + ''' + Skip landmarks. + + Parameters: + seq - The point sequence. + lmdks - The landmarks. + epsilon - The available privacy budget. + Returns: + rls_data - The perturbed data. + bgts - The privacy budget allocation. + ''' + # Event-level budget allocation + bgts = np.array(len(seq)*[epsilon]) + # Released + rls_data = [None]*len(seq) + for i, p in enumerate(seq): + # Check if current point is a landmark + is_landmark = any((lmdks[:]==p).all(1)) + # Add noise + o = [p[0], lmdk_lib.add_laplace_noise(p[1], 1, bgts[i])] + if is_landmark: + if i > 0: + # Approximate with previous + o = rls_data[i - 1] + bgts[i] = 0 + rls_data[i] = o + return rls_data, bgts + + def sample(seq, lmdks, epsilon): ''' Publish randomly. @@ -642,6 +727,18 @@ def uniform_cont(seq, lmdks, epsilon): return rls_data, bgts +def uniform_cons(seq, lmdks, epsilon): + # Released + rls_data = [None]*len(seq) + # Budgets + bgts = uniform(seq, lmdks, epsilon) + for i, p in enumerate(seq): + is_landmark = any((lmdks[:]==p).all(1)) + # [timestamp, perturbed consumption] + rls_data[i] = [p[0], lmdk_lib.add_laplace_noise(p[1], 1, bgts[i])] + return rls_data, bgts + + def utility_analysis(seq, lmdks, o, epsilon): ''' Analyze the utility. @@ -688,3 +785,10 @@ def mae_cont(o): if p[0] != p[1]: mae += 1/len(o) return mae + + +def mae_cons(seq, o): + mae = 0 + for i, p in enumerate(seq): + mae += abs(p[1] - o[i][1])/len(seq) + return mae