From b03b510f020f17f3f0fbdf6d5a1405694f4dceef Mon Sep 17 00:00:00 2001 From: Manos Date: Sat, 9 Oct 2021 13:27:16 +0200 Subject: [PATCH] lmdk-expt: Reviewed all graphs for synthetic --- code/expt/avg_dist.py | 121 ++ code/expt/dist_cor.py | 131 ++ code/lib/gdp.py | 1576 +++++++++++++++++ graphics/{ => evaluation}/avg-dist.pdf | Bin 16202 -> 16971 bytes graphics/evaluation/dist-cor-mod.pdf | Bin 0 -> 16040 bytes .../dist-cor-stg.pdf} | Bin 15823 -> 16037 bytes graphics/{ => evaluation}/dist-cor-wk.pdf | Bin 15473 -> 16037 bytes rslt/avg_dist/avg-dist.pdf | Bin 0 -> 16971 bytes rslt/dist_cor/dist-cor-mod.pdf | Bin 0 -> 16040 bytes {graphics => rslt/dist_cor}/dist-cor-stg.pdf | Bin 15825 -> 16037 bytes rslt/dist_cor/dist-cor-wk.pdf | Bin 0 -> 16037 bytes text/evaluation/thething.tex | 21 +- 12 files changed, 1839 insertions(+), 10 deletions(-) create mode 100644 code/expt/avg_dist.py create mode 100644 code/expt/dist_cor.py create mode 100644 code/lib/gdp.py rename graphics/{ => evaluation}/avg-dist.pdf (73%) create mode 100644 graphics/evaluation/dist-cor-mod.pdf rename graphics/{dist-cor-mod.pdf => evaluation/dist-cor-stg.pdf} (69%) rename graphics/{ => evaluation}/dist-cor-wk.pdf (68%) create mode 100644 rslt/avg_dist/avg-dist.pdf create mode 100644 rslt/dist_cor/dist-cor-mod.pdf rename {graphics => rslt/dist_cor}/dist-cor-stg.pdf (68%) create mode 100644 rslt/dist_cor/dist-cor-wk.pdf diff --git a/code/expt/avg_dist.py b/code/expt/avg_dist.py new file mode 100644 index 0000000..941a8de --- /dev/null +++ b/code/expt/avg_dist.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 + +import sys +sys.path.insert(1, '../lib') +import argparse +import gdp +import lmdk_lib +import math +from matplotlib import pyplot as plt +import numpy as np +import os +import time + + +def main(args): + # Number of timestamps + seq = lmdk_lib.get_seq(1, args.time) + # Distribution type + dist_type = np.array(range(0, 4)) + # Number of landmarks + lmdk_n = np.array(range(0, args.time + 1, int(args.time/5))) + + markers = [ + '^', # Symmetric + 'v', # Skewed + 'D', # Bimodal + 's' # Uniform + ] + + # Initialize plot + lmdk_lib.plot_init() + # The x axis + x_i = np.arange(len(lmdk_n)) + plt.xticks(x_i, ((lmdk_n/len(seq))*100).astype(int)) + plt.xlabel('Landmarks (%)') # Set x axis label. + plt.xlim(x_i.min(), x_i.max()) + # The y axis + plt.ylabel('Normalized average distance') # Set y axis label. + plt.yscale('log') + plt.ylim(.001, 1) + # Logging + print('Average distance', end='', flush=True) + for d_i, d in enumerate(dist_type): + avg_dist = np.zeros(len(lmdk_n)) + # Logging + print('.', end='', flush=True) + for i, n in enumerate(lmdk_n): + for r in range(args.reps): + # Generate landmarks + lmdks = lmdk_lib.get_lmdks(seq, n, d) + # Calculate average distance + avg_cur = 0 + for t in seq: + t_prv, t_nxt = gdp.get_limits(t, seq, lmdks) + avg_cur += (abs(t - t_prv) - 1 + abs(t - t_nxt) - 1 )/len(seq) + # Normalized average based on repetitions + avg_dist[i] += avg_cur/args.reps + # Rescaling (min-max normalization) + # https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization) + avg_dist = (avg_dist - avg_dist.min())/(avg_dist.max() - avg_dist.min()) + # Normalize for log scale + if avg_dist[len(avg_dist) - 1] == 0: + avg_dist[len(avg_dist) - 1] = .001 + # Set label + label = lmdk_lib.dist_type_to_str(d_i) + if d_i == 1: + label = 'Skewed' + # Plot line + plt.plot( + x_i, + avg_dist, + label=label, + marker=markers[d_i], + markersize=lmdk_lib.marker_size, + markeredgewidth=0, + linewidth=lmdk_lib.line_width + ) + # Plot legend + lmdk_lib.plot_legend() + # Show plot + # plt.show() + # Save plot + lmdk_lib.save_plot(str('../../rslt/avg_dist/' + 'avg-dist' + '.pdf')) + print(' [OK]', flush=True) + + +''' + Parse arguments. + + Optional: + reps - The number of repetitions. + time - The time limit of the sequence. +''' +def parse_args(): + # Create argument parser. + parser = argparse.ArgumentParser() + + # Mandatory arguments. + + # Optional arguments. + parser.add_argument('-r', '--reps', help='The number of repetitions.', type=int, default=1) + parser.add_argument('-t', '--time', help='The time limit of the sequence.', type=int, default=100) + + # Parse arguments. + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + try: + args = parse_args() + start_time = time.time() + main(args) + end_time = time.time() + print('##############################') + print('Time elapsed: %s' % (time.strftime('%H:%M:%S', time.gmtime(end_time - start_time)))) + print('##############################') + except KeyboardInterrupt: + print('Interrupted by user.') + exit() diff --git a/code/expt/dist_cor.py b/code/expt/dist_cor.py new file mode 100644 index 0000000..039c5db --- /dev/null +++ b/code/expt/dist_cor.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 + +import sys +sys.path.insert(1, '../lib') +import argparse +import gdp +import itertools +import lmdk_bgt +import lmdk_lib +import numpy as np +import os +from matplotlib import pyplot as plt +import time + + +def main(args): + # Privacy goal + epsilon = 1.0 + # Number of timestamps + seq = lmdk_lib.get_seq(1, args.time) + # Correlation degree (higher values means weaker correlations) + cor_deg = np.array([.01, .1, 1.0]) + cor_lbl = ['Strong correlation', 'Moderate correlation', 'Weak correlation'] + # Distribution type + dist_type = np.array(range(0, 4)) + # Number of landmarks + lmdk_n = np.array(range(0, args.time + 1, int(args.time/5))) + # Width of bars + bar_width = 1/(len(dist_type) + 1) + # For each correlation degree + for c_i, c in enumerate(cor_deg): + # Logging + title = cor_lbl[c_i] + print('(%d/%d) %s' %(c_i + 1, len(cor_deg), title), end='', flush=True) + # The transition matrix + p = gdp.gen_trans_mt(2, c) + # Bar offset + x_offset = -(bar_width/2)*(len(dist_type) - 1) + # Initialize plot + lmdk_lib.plot_init() + # The x axis + x_i = np.arange(len(lmdk_n)) + plt.xticks(x_i, ((lmdk_n/len(seq))*100).astype(int)) + plt.xlabel('Landmarks (%)') # Set x axis label. + x_margin = bar_width*(len(dist_type)/2 + 1) + plt.xlim(x_i.min() - x_margin, x_i.max() + x_margin) + # The y axis + plt.ylabel('Privacy loss') # Set y axis label. + plt.yscale('log') + plt.ylim(epsilon/10, 100*len(seq)) + # plt.ylim(0, 10000) + for d_i, d in enumerate(dist_type): + print('.', end='', flush=True) + # Initialization + e = np.zeros(len(lmdk_n)) + a = np.zeros(len(lmdk_n)) + for i, n in enumerate(lmdk_n): + for r in range(args.reps): + # Generate landmarks + lmdks = lmdk_lib.get_lmdks(seq, n, d) + # Uniform budget allocation + e_cur = lmdk_bgt.uniform(seq, lmdks, epsilon) + _, _, a_cur = gdp.tpl_lmdk_mem(e_cur, p, p, seq, lmdks) + # Save privacy loss + e[i] += np.sum(e_cur)/args.reps + a[i] += np.sum(a_cur)/args.reps + # Set label + label = lmdk_lib.dist_type_to_str(d_i) + if d_i == 1: + label = 'Skewed' + # Plot bar for current distribution + plt.bar( + x_i + x_offset, + a, + bar_width, + label=label, + linewidth=lmdk_lib.line_width + ) + # Change offset for next bar + x_offset += bar_width + # Plot line for no correlation + plt.plot( + x_i, + e, + linewidth=lmdk_lib.line_width, + color='#e0e0e0', + ) + # Plot legend + lmdk_lib.plot_legend() + # Show plot + # plt.show() + # Save plot + lmdk_lib.save_plot(str('../../rslt/dist_cor/' + title + '.pdf')) + print(' [OK]', flush=True) + + +''' + Parse arguments. + + Optional: + reps - The number of repetitions. + time - The time limit of the sequence. +''' +def parse_args(): + # Create argument parser. + parser = argparse.ArgumentParser() + + # Mandatory arguments. + + # Optional arguments. + parser.add_argument('-r', '--reps', help='The number of repetitions.', type=int, default=1) + parser.add_argument('-t', '--time', help='The time limit of the sequence.', type=int, default=100) + + # Parse arguments. + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + try: + args = parse_args() + start_time = time.time() + main(args) + end_time = time.time() + print('##############################') + print('Time elapsed: %s' % (time.strftime('%H:%M:%S', time.gmtime(end_time - start_time)))) + print('##############################') + except KeyboardInterrupt: + print('Interrupted by user.') + exit() diff --git a/code/lib/gdp.py b/code/lib/gdp.py new file mode 100644 index 0000000..8467e28 --- /dev/null +++ b/code/lib/gdp.py @@ -0,0 +1,1576 @@ +#!/usr/bin/env python3 + +import argparse +import collections +import csv +import datetime +import math +from matplotlib import pyplot as plt +import numpy as np +import os +import random +from scipy.sparse.linalg import eigs +from scipy.stats import laplace +from scipy.stats import norm +import sympy as sp +import time +import xxhash + + +# Debugging +DEBUG = False # Variable to check. + # When enabled print something. + + +# Memoization +MEM = {} # The cache. +MISS = 0 # Number of additions to the cache. +TOTAL = 0 # Number of cache accesses. + + +''' + Read data from a file. + + Parameters: + path - The relative path to the data file. + Returns: + data - A list of tuples [uid, timestamp, lng, lat, loc]. +''' +def load_data(path): + print('Loading data from', os.path.abspath(path), '... ', end='') + data = [] + try: + with open(path, 'r') as f: + reader = csv.reader(f, delimiter=',') + data = list(reader) + print('OK.') + return data + except IOError: + print('Oops!') + exit() + + +''' + Save output to a file. + + Parameters: + path - The relative path to the output file. + t - The number of timestamps. + e - The privacy budget at each timestamp. + a_b - The backward privacy loss at each timestamp. + a_f - The forward privacy loss at each timestamp. + a - The temporal privacy loss at each timestamp. + Returns: + Nothing. +''' +def save_output(path, t, e, a_b, a_f, a): + # timestamp = time.strftime('%Y%m%d%H%M%S') + print('Saving output to %s... ' %(path), end='', flush=True) + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, 'w') as f: + w = csv.writer(f, delimiter=';') + w.writerow(['t', 'e', 'bpl', 'fpl', 'tpl']) + w.writerows(zip(list(range(1, t + 1)), e, a_b, a_f, a)) + print('OK.', flush=True) + + +''' + Get all the timestamps from the input data. + + Parameters: + data - The input data set. + Returns: + timestamps - An ndarray of all of the timestamps from the input data. +''' +def get_timestamps(data): + print('Getting a list of all timestamps... ', end='', flush=True) + timestamps = np.sort(np.unique(np.array(data)[:, 1])) + if not len(timestamps): + print('No timestamps found.', flush=True) + exit() + # Check timestamps' order. + prev = None + for t in timestamps: + curr = time.mktime(datetime.datetime.strptime(t, '%Y-%m-%d %H:%M').timetuple()) + if prev: + if curr < prev: + print('Wrong order.', flush=True) + exit() + prev = curr + print('OK.', flush=True) + if DEBUG: + print(timestamps, len(timestamps)) + return timestamps + + +''' + Get all the unique locations from the input data. + + Parameters: + data - The input data set. + Returns: + locs - A sorted ndarray of all the unique locations int the input data. +''' +def get_locs(data): + print('Getting a list of all locations... ', end='', flush=True) + locs = np.sort(np.unique(np.array(data)[:, 4].astype(np.int))) + if not len(locs): + print('No locations found.', flush=True) + exit() + print('OK.', flush=True) + if DEBUG: + print(list(map(str, locs)), len(locs)) + return list(map(str, locs)) + + +''' + Get the counts at every location for a specific timestamp. + + Parameters: + data - The input data set. + t - The timestamp of interest. + Returns: + cnts - A dict {loc:cnt} with the counts at every location for a specific timestamp. +''' +def get_cnts(data, t): + print('Getting all counts at %s... ' %(t), end='', flush=True) + locs = get_locs(data) + cnts = dict.fromkeys(locs, 0) + for d in data: + if d[1] == t: + cnts[int(d[4])] += 1 + print('OK.', flush=True) + if DEBUG: + print(cnts) + return cnts + + +''' + Get the counts at every location for every timestamp. + + Parameters: + data - The input data set. + Returns: + cnts - A dict {timestamp:loc} with all the counts at every location for every timestamp. +''' +def get_all_cnts(data): + cnts = {} + for d in data: + key = d[1] + '@' + d[4] + cnts[key] = cnts.get(key, 0) + 1 + if DEBUG: + print(cnts) + return cnts + + +''' + Get a list of unique users in the input data set. + + Parameters: + data - The input data set. + Returns: + users - An ndarray of all unique users. +''' +def get_usrs(data): + users = np.sort(np.unique(np.array(data)[:, 0].astype(np.int))) + if not len(users): + print('No users found.') + exit() + if DEBUG: + print(users, len(users)) + return users + + +''' + Get the data of a particular user from a data set. + + Parameters: + data - The input data set. + id - The user identifier. + Returns: + output - A list of the data of the targeted user. +''' +def get_usr_data(data, id): + output = [] + for d in data: + if (d[0] == str(id)): + output.append(d) + if DEBUG: + print(id, output) + return output + + +''' + Get the data of every user in a data set. + + Parameters: + data - The input data set. + Returns: + output - A dict {usr, [usr_data]} with the data of each user. +''' +def get_usrs_data(data): + output = {} + for d in data: + output[d[0]] = output.get(d[0], []) + [d] + return output + + +''' + Get the trajectory of a user from her data. + + Parameters: + data - The data of the user. + Returns: + traj - A list [(timestamp, loc)] with the locations and corresponding timestamps that the user was at. +''' +def get_usr_traj(data): + traj = [] + for d in data: + traj.append((d[1], d[4])) + if DEBUG: + print(traj) + return traj + + +''' + Get all the possible transitions. + + Parameters: + data - The input data set. + Returns: + trans - A set with all the possible forward transitions in the input. +''' +def get_poss_trans(data): + print('Getting possible transitions... ', end='', flush=True) + trans = set() + for u, u_data in data.items(): + traj = get_usr_traj(u_data) + trans.update(list(zip(traj, traj[1:]))) + if len(trans) == 0: + print('None.', flush=True) + exit() + print('OK.', flush=True) + return trans + + +''' + Get all backward transitions in a data set. + + Parameters: + data - The input data set. + Returns: + trans - A dict {(t, t-1):[transitions]} with all the backward transitions + at every sequential timestamp pair in the input data set. +''' +def get_bwd_trans(data): + print('Getting all backward transitions... ', end='', flush=True) + trans = {} + for u, u_data in data.items(): + traj = get_usr_traj(u_data) + for i, j in zip(traj[1:], traj): + trans[(i[0], j[0])] = trans.get((i[0], j[0]), []) + [(i[1], j[1])] + if len(trans) == 0: + print('None.', flush=True) + exit() + print('OK.', flush=True) + return trans + + +''' + Get all forward transitions in a data set. + + Parameters: + data - The input data set. + Returns: + trans - A dict {(t-1, t):[transitions]} with all the forward transitions + at every sequential timestamp pair in the input data set. +''' +def get_fwd_trans(data): + print('Getting all forward transitions... ', end='', flush=True) + trans = {} + for u, u_data in data.items(): + traj = get_usr_traj(u_data) + for i, j in zip(traj, traj[1:]): + trans[(i[0], j[0])] = trans.get((i[0], j[0]), []) + [(i[1], j[1])] + if len(trans) == 0: + print('None.', flush=True) + exit() + print('OK.', flush=True) + return trans + + +''' + Divide two numbers. If the divisor is 0 return inf. + + Parameters: + a - The dividend. + b - The divisor. + Returns: + The float result of the division. +''' +def safe_div(a, b): + if b == 0: + return math.inf + return float(a/b) + + +''' + Calculate the maximum value of the objective function. + + Parameters: + q - A row from the transition matrix. + d - Another row from the transition matrix. + a - The backward/forward privacy loss of the previous/next + timestamp. + Returns: + The maximum value of the objective function. +''' +def max_val(q, d, a): + if a == math.inf: + return math.nan + return (q*(math.exp(a) - 1) + 1)/(d*(math.exp(a) - 1) + 1) + + +''' + Find two different rows (q and d) of a transition matrix (p) + that maximize the product of the objective function and return + their sums. + + Parameters: + p - The transition matrix representing the backward/forward + correlations. + a - The backward/forward privacy loss of the previous/next + timestamp. + Returns: + sum_q - The sum of the elements of q. + sum_d - The sum of the elements of d. +''' +def find_qd(p, a): + res = 0.0 + sum_q, sum_d = 0.0, 0.0 + for q in p: # A row from the transition matrix. + for d in p: # Another row from the transition matrix. + if not np.array_equal(q, d) and sum(q) and sum(d): + plus = [] # Indexes of the elements of q+ and d+. + for i in range(np.shape(p)[1]): # Iterate each column. + if q[i] > d[i]: + plus.append(i) + s_q, s_d = 0.0, 0.0 + update = True + while update: + update = False + for i in plus: + s_q += q[i] + s_d += d[i] + max_tmp = max_val(s_q, s_d, a) + for i in plus: + if safe_div(q[i], d[i]) <= max_tmp: + plus.remove(i) + update = True + res_tmp = math.log(max_val(s_q, s_d, a)) + if res < res_tmp: + res = res_tmp + sum_q, sum_d = s_q, s_d + return sum_q, sum_d + + +''' + Generate data. + + Parameters: + usrs - The number of users. + timestamps - The number of timestamps. + locs - The numner of locations. + Returns: + data - The generated data. +''' +def gen_data(usrs, timestamps, locs): + print('Generating data... ', end='', flush=True) + # Generate timestamps. + ts = [] + t_start = datetime.datetime.now() + for t in range(timestamps): + t_start += datetime.timedelta(minutes=t) + ts.append(str(t_start.strftime('%Y-%m-%d %H:%M'))) + # Randomly generate unique possible transitions. + trans = set() + for i in range(locs**2): + trans.add((str(random.randint(1, locs)), str(random.randint(1, locs)))) + # Generate the data. + data = [] + for u in range(1, usrs + 1): + # Choose a random starting location. + l_start = random.sample(trans, 1)[0][0] + for t in ts: + # Choose a random next location. + while True: + l_nxt = str(random.randint(1, locs)) + if (l_start, l_nxt) in trans: + data.append([str(u), str(t), str(l_nxt), str(l_nxt), str(l_nxt)]) + break + print('OK.', flush=True) + return data + + +''' + Generate a transition matrix. + + Parameters: + n - The dimension of the matrix. + s - The correlation degree of each row [0, 1]. + The lower its value, the lower the degree of + uniformity of each row. + Returns: + p_ - The transition matrix. +''' +def gen_trans_mt(n, s): + if DEBUG: + print('Generating transition matrix %dx%d with s = %.4f... ' %(n, n, s), end='', flush=True) + p = np.zeros((n, n), float) + np.fill_diagonal(p, 1.0) + p_ = np.zeros((n, n), float) + for j, p_j in enumerate(p[:, ]): + for k, p_jk in enumerate(p_j): + p_[j, k] = round((p[j, k] + s) / (sum(p_j) + len(p_j)*s), 4) + if DEBUG: + print('OK.', flush=True) + if DEBUG: + print(p_) + return p_ + + +''' + Get the transition matrix + + Parameters: + locs - A list of all the locations. + trans - A list of all transitions. + Returns: + p - A 2d dict {{locs}{locs}} containing the + corresponding location transition probabilities. +''' +def get_trans_mt(locs, trans): + if DEBUG: + print('Generating the transition matrix... ', end='', flush=True) + # Initialize the transition matrix. + p = collections.defaultdict(dict) + for i in locs: + for j in locs: + p[i][j] = 0.0 + # Populate the transition matrix. + for i in locs: + for j in locs: + # Count the transitions from i to j. + cnt = collections.Counter(trans)[(i, j)] + # Count the transitions from i to any location. + sum_cnts = len([tr for tr in trans if tr[0] == i]) + res = 0.0 + if cnt != 0 and sum_cnts != 0: + res = cnt/sum_cnts + # Update transition matrix. + p[i][j] = res + if DEBUG: + print('OK.', flush=True) + for i in locs: + print(p[i]) + return p + + +''' + Calculate the measure-theoretic (Kolmogorov-Sinai) entropy + of a transition matrix. + + Parameters: + mt - A 2d dict transition matrix. + Returns: + h - The Kolmogorov-Sinai entropy of the matrix. +''' +def get_entropy(mt): + if DEBUG: + print('Calculating the measure-theoretic entropy... ', end='', flush=True) + h = 0.0 + # Get the 2d array of the transition matrix. + a = get_2darray(mt) + # Check if the transition matrix is empty. + if np.allclose(a, np.zeros((len(a), len(a)), float)): + return h + # Find the stationary distribution (v), written as a row + # vector, that does not change under the application of + # the transition matrix. In other words, the left eigenvector + # associated with eigenvalue (w) 1. It is also called + # Perron-Frobenius eigenvector, since it is a stochastic + # matrix and the largest magnitude of the eigenvalues must + # be 1. We use the transpose of the transition matrix to get + # the left eigenvector. + w, v = eigs(a.T, k=1, which='LM') + # Normalize the eigenvector. The vector is a probability + # distribution, and therefore its sum must be 1. Thus, we use + # its absolute elements' values and its l1-norm to normalize it. + p = np.absolute(v[:,0].real) + p_norm = np.linalg.norm(p, ord=1) + if p_norm: + p = p/p_norm + # Calculate the entropy. + if np.isclose(w.real[0], 1, atol=1e-03): + for i in range(len(a)): + for j in range(len(a)): + # When the transition probability is 0 use the limiting value (0). + if not np.isclose(a[i][j], 0, atol=1e-03) and not np.isclose(p[i], 0, atol=1e-03): + # Binary logarithm measures entropy in bits. + h += -p[i]*a[i][j]*math.log2(a[i][j]) + if DEBUG: + print(h, flush=True) + return h + + +''' + Convert a 2d dict to a 2d array. + + Parameters: + mt - The 2d dict. + Returns: + p - The 2d numpy array. +''' +def get_2darray(mt): + if type(mt) == type(np.array([])): + return mt + p = np.zeros((len(mt), len(mt)), float) + for i, mt_i in enumerate(mt.items()): + p[i] = list(mt_i[1].values()) + return p + + +''' + Get a Laplace probability distribution. + + Parameters: + ts - The points of the distribution. + t - The location of the distribution. + sc - The scale of the distribution. + Returns: + The probability distribution. +''' +def get_laplace_pd(ts, t, sc): + x = np.arange(0, len(ts), 1) + loc = np.where(ts == t) + return laplace.pdf(x, loc=loc, scale=sc)[0] + + +''' + Get a Gaussian probability distribution. + + Parameters: + ts - The points of the distribution. + t - The location of the distribution. + sc - The scale of the distribution. + Returns: + The probability distribution. +''' +def get_norm_pd(ts, t, sc): + x = np.arange(0, len(ts), 1) + loc = np.where(ts == t) + return norm.pdf(x, loc=loc, scale=sc)[0] + + +''' + Get a sample from the time series. + + Parameters: + ts - An ndarray of the timestamps. + t - The current timestamp. + pd - The probability distribution. + ptn - The desired portion [0, 1] of the non-zero elements + of the probability distribution to be sampled. + Returns: + spl - An ndarray of the sampled timestamps. +''' +def get_sample(ts, t, pct, pd): + if DEBUG: + print('Sampling %.2f%% of %s at %s... ' %(pct*100, ts, t), end='', flush=True) + # Check that it is a valid timestamp. + if not t in ts: + print('%s is not in the time series.' %(t)) + exit() + # Remove the current timestamp from the possible sample. + i = np.where(ts == t) + ts = np.delete(ts, i) + pd = np.delete(pd, i) + # Make sure that the probabilities sum to 1. + pd_norm = pd/np.linalg.norm(pd, ord=1) + # Get the sorted sample. + spl = np.sort(np.random.choice(ts, size=int(np.count_nonzero(pd)*pct), replace=False, p=pd_norm)) + if DEBUG: + print(spl, flush=True) + return spl + + +''' + Calculate the backward/forward privacy loss at the current + timestamp. + + Parameters: + p - The transition matrix representing the backward/forward + temporal correlations. + a - The privacy loss of the previous/next timestamp. + e - The privacy budget for data publishing. + Returns: + The backward/forward privacy loss at the current + timestamp. +''' +def priv_l(p, a, e): + sum_q, sum_d = find_qd(p, a) + return math.log(max_val(sum_q, sum_d, a)) + e + + +''' + Calculate the backward/forward privacy loss at the current + timestamp using memoization. + + Parameters: + p - The transition matrix representing the backward/forward + temporal correlations. + a - The privacy loss of the previous/next timestamp. + e - The privacy budget for data publishing. + Returns: + The backward/forward privacy loss at the current + timestamp. +''' +def priv_l_m(p, a, e): + key = xxhash.xxh64(p).hexdigest() + str(a) + str(e) + global MEM, TOTAL, MISS + TOTAL += 1 + result = MEM.get(key) + if not result: + MISS += 1 + sum_q, sum_d = find_qd(p, a) + result = math.log(max_val(sum_q, sum_d, a)) + e + MEM[key] = result + return result + + +''' + Calculate the total backward privacy loss at every timestamp. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + a - The backward privacy loss of every release. + e - The privacy budget for data publishing. + t - The time limit. + Returns: + a - The backward privacy loss at every timestamp + due to the previous data releases. +''' +def bpl(p, a, e, t): + a[0] = e[0] + for i in range(1, t): + a[i] = priv_l(p, a[i - 1], e[i]) + return a + + +''' + Calculate the total backward privacy loss at the current + timestamp with memoization. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + a - The backward privacy loss of the current release + at all previous timestamps. + e - The privacy budget for data publishing. + t - The time limit. + Returns: + a - The backward privacy loss at the current timestamp + due to the previous data releases. +''' +def bpl_m(p, a, e, t): + a[0] = e[0] + for i in range(1, t): + a[i] = priv_l_m(p, a[i - 1], e[i]) + return a + +def bpl_lmdk_mem(p, a, e, t, lmdk): + # t is (near) the landmark + if lmdk == t - 1 or t == lmdk: + return np.array([0]*len(a)) + # There is no landmark before + if lmdk < 1: + lmdk = 1 + a[0] = e[0] + for i in range(lmdk, t): + a[i] = priv_l_m(p, a[i - 1], e[i]) + return a + + +''' + Calculate the total backward privacy loss at the current + timestamp using the static model, i.e., previous releases + are grouped in a window of static size. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group previous releases. + Returns: + a - The backward privacy loss at the current timestamp + due to the previous data releases. +''' +def bpl_s(p, e, i, w): + if i - w > 1: + # print('bpl_s: %d - %d [%d]' %(i, i - w, w)) + return priv_l(np.linalg.matrix_power(p, w), bpl_s(p, e, i - w, w), e[i - 1]) + elif i - w <= 1: + # print('bpl_s: %d - %d [%d]' %(i, 1, i - 1)) + return priv_l(np.linalg.matrix_power(p, i - 1), e[0], e[i - 1]) + elif i == 1: + # print('bpl_s: %d' %(i)) + return e[0] + + +''' + Calculate the total backward privacy loss at the current + timestamp using the static model, i.e., previous releases + are grouped in a window of static size, using memoization. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group previous releases. + Returns: + a - The backward privacy loss at the current timestamp + due to the previous data releases. +''' +def bpl_s_m(p, e, i, w): + if i - w > 1: + return priv_l_m(np.linalg.matrix_power(p, w), bpl_s_m(p, e, i - w, w), e[i - 1]) + elif i - w <= 1: + return priv_l_m(np.linalg.matrix_power(p, i - 1), e[0], e[i - 1]) + elif i == 1: + return e[0] + + +''' + Calculate the total backward privacy loss at the current + timestamp using the linear model, i.e., previous releases + are grouped in a window of a size that increases linearly. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group previous releases. + l - The linearly increasing coefficient that affects the + window size. + Returns: + a - The backward privacy loss at the current timestamp + due to the previous data releases. +''' +def bpl_l(p, e, i, w, l): + if i - w*l > 1: + # print('bpl_l: %d - %d [%d]' %(i, i - w*l, w*l)) + return priv_l(np.linalg.matrix_power(p, w*l), bpl_l(p, e, i - w*l, w, l + 1), e[i - 1]) + elif i - w*l <= 1: + # print('bpl_l: %d - %d [%d]' %(i, 1, i - 1)) + return priv_l(np.linalg.matrix_power(p, i - 1), e[0], e[i - 1]) + elif i == 1: + # print('bpl_l: %d' %(1)) + return e[0] + + +''' + Calculate the total backward privacy loss at the current + timestamp using the linear model, i.e., previous releases + are grouped in a window of a size that increases linearly, + using memoization. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group previous releases. + l - The linearly increasing coefficient that affects the + window size. + Returns: + a - The backward privacy loss at the current timestamp + due to the previous data releases. +''' +def bpl_l_m(p, e, i, w, l): + if i - w*l > 1: + return priv_l_m(np.linalg.matrix_power(p, w*l), bpl_l_m(p, e, i - w*l, w, l + 1), e[i - 1]) + elif i - w*l <= 1: + return priv_l_m(np.linalg.matrix_power(p, i - 1), e[0], e[i - 1]) + elif i == 1: + return e[0] + + +''' + Calculate the total backward privacy loss at the current + timestamp using the exponential model, i.e., previous releases + are grouped in a window of a size that increases exponentially. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group previous releases. + h - The exponentially increasing coefficient that affects + the window size. + Returns: + a - The backward privacy loss at the current timestamp + due to the previous data releases. +''' +def bpl_e(p, e, i, w, h): + if i - w**h > 1: + # print('bpl_e: %d - %d [%d]' %(i, i - w**h, w**h)) + return priv_l(np.linalg.matrix_power(p, w**h), bpl_e(p, e, i - w**h, w, h + 1), e[i - 1]) + elif i - w**h <= 1: + # print('bpl_e: %d - %d [%d]' %(i, 1, i - 1)) + return priv_l(np.linalg.matrix_power(p, i - 1), e[0], e[i - 1]) + elif i == 1: + # print('bpl_e: %d' %(1)) + return e[0] + + +''' + Calculate the total backward privacy loss at the current + timestamp using the exponential model, i.e., previous releases + are grouped in a window of a size that increases exponentially, + using memoization. + + Parameters: + p - The transition matrix representing the backward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group previous releases. + h - The exponentially increasing coefficient that affects + the window size. + Returns: + a - The backward privacy loss at the current timestamp + due to the previous data releases. +''' +def bpl_e_m(p, e, i, w, h): + if i - w**h > 1: + return priv_l_m(np.linalg.matrix_power(p, w**h), bpl_e_m(p, e, i - w**h, w, h + 1), e[i - 1]) + elif i - w**h <= 1: + return priv_l_m(np.linalg.matrix_power(p, i - 1), e[0], e[i - 1]) + elif i == 1: + return e[0] + + +''' + Calculate the total forward privacy loss at the current + timestamp. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + a - The forward privacy loss of the current release + at all next timestamps. + e - The privacy budget for data publishing. + t - The time limit. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl(p, a, e, t): + a[t - 1] = e[t - 1] + for i in range(t - 2, -1, -1): + a[i] = priv_l(p, a[i + 1], e[i]) + return a + + +''' + Calculate the total forward privacy loss at the current + timestamp, using memoization. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + a - The forward privacy loss of the current release + at all next timestamps. + e - The privacy budget for data publishing. + t - The time limit. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl_m(p, a, e, t): + a[t - 1] = e[t - 1] + for i in range(t - 2, -1, -1): + a[i] = priv_l_m(p, a[i + 1], e[i]) + return a + +def fpl_lmdk_mem(p, a, e, t, lmdk): + # t is (near) the landmark + if lmdk == t + 1 or t == lmdk: + return np.array([0]*len(a)) + # There is no landmark after + if lmdk > len(e): + lmdk = len(e) + a[lmdk - 1] = e[lmdk - 1] + for i in range(lmdk - 2, t - 2, -1): + a[i] = priv_l_m(p, a[i + 1], e[i]) + return a + + +''' + Calculate the total forward privacy loss at the current + timestamp using the static model, i.e., next releases + are grouped in a window of static size. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group next releases. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl_s(p, e, i, t, w): + if i + w < t: + # print('fpl_s: %d - %d [%d]' %(i, i + w, w)) + return priv_l(np.linalg.matrix_power(p, w), fpl_s(p, e, i + w, t, w), e[i - 1]) + elif i + w >= t: + # print('fpl_s: %d - %d [%d]' %(i, t, t - i)) + return priv_l(np.linalg.matrix_power(p, t - i), e[t - 1], e[i - 1]) + elif i == t: + # print('fpl_s: %d' %(t)) + return e[t - 1] + + +''' + Calculate the total forward privacy loss at the current + timestamp using the static model, i.e., next releases + are grouped in a window of static size, using memoization. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group next releases. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl_s_m(p, e, i, t, w): + if i + w < t: + return priv_l_m(np.linalg.matrix_power(p, w), fpl_s_m(p, e, i + w, t, w), e[i - 1]) + elif i + w >= t: + return priv_l_m(np.linalg.matrix_power(p, t - i), e[t - 1], e[i - 1]) + elif i == t: + return e[t - 1] + + +''' + Calculate the total forward privacy loss at the current + timestamp using the linear model, i.e., next releases + are grouped in a window of a size that increases linearly. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group next releases. + l - The linearly increasing coefficient that affects the + window size. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl_l(p, e, i, t, w, l): + if i + w*l < t: + # print('fpl_l: %d - %d [%d]' %(i, i + w*l, w*l)) + return priv_l(np.linalg.matrix_power(p, w*l), fpl_l(p, e, i + w*l, t, w, l + 1), e[i - 1]) + elif i + w*l >= t: + # print('fpl_l: %d - %d [%d]' %(i, t, t - i)) + return priv_l(np.linalg.matrix_power(p, t - i), e[t - 1], e[i - 1]) + elif i == t: + # print('fpl_l: %d' %(t)) + return e[t - 1] + + +''' + Calculate the total forward privacy loss at the current + timestamp using the linear model, i.e., next releases + are grouped in a window of a size that increases linearly, + using memoization. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group next releases. + l - The linearly increasing coefficient that affects the + window size. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl_l_m(p, e, i, t, w, l): + if i + w*l < t: + return priv_l_m(np.linalg.matrix_power(p, w*l), fpl_l_m(p, e, i + w*l, t, w, l + 1), e[i - 1]) + elif i + w*l >= t: + return priv_l_m(np.linalg.matrix_power(p, t - i), e[t - 1], e[i - 1]) + elif i == t: + return e[t - 1] + + +''' + Calculate the total forward privacy loss at the current + timestamp using the exponential model, i.e., next releases + are grouped in a window of a size that increases exponentially. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group next releases. + h - The exponentially increasing coefficient that affects + the window size. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl_e(p, e, i, t, w, h): + if i + w**h < t: + # print('fpl_e: %d - %d [%d]' %(i, i + w**h, w**h)) + return priv_l(np.linalg.matrix_power(p, w**h), fpl_e(p, e, i + w**h, t, w, h + 1), e[i - 1]) + elif i + w**h >= t: + # print('fpl_e: %d - %d [%d]' %(i, t, t - i)) + return priv_l(np.linalg.matrix_power(p, t - i), e[t - 1], e[i - 1]) + elif i == t: + # print('fpl_e: %d' %(t)) + return e[t - 1] + + +''' + Calculate the total forward privacy loss at the current + timestamp using the exponential model, i.e., next releases + are grouped in a window of a size that increases exponentially, + using memoization. + + Parameters: + p - The transition matrix representing the forward + temporal correlations. + e - The privacy budget for data publishing. + i - The timestamp of interest. + w - The window size to group next releases. + h - The exponentially increasing coefficient that affects + the window size. + Returns: + a - The forward privacy loss at the current timestamp + due to the next data releases. +''' +def fpl_e_m(p, e, i, t, w, h): + if i + w**h < t: + return priv_l_m(np.linalg.matrix_power(p, w**h), fpl_e_m(p, e, i + w**h, t, w, h + 1), e[i - 1]) + elif i + w**h >= t: + return priv_l_m(np.linalg.matrix_power(p, t - i), e[t - 1], e[i - 1]) + elif i == t: + return e[t - 1] + + +''' + Calculate the total privacy loss at every timestamp. + + Parameters: + bpl - The backward privacy loss. + fpl - The forward privacy loss. + e - The privacy budget for data publishing. + Returns: + The list of total privacy loss at every timestamp. +''' +def tpl(bpl, fpl, e): + return [x + y - z for (x, y, z) in zip(bpl, fpl, e)] + + +''' + Calculate the temporal privacy loss at every timestamp + taking into account landmarks. + + Parameters: + e - The privacy budget for data publishing. + p_b - The transition matrix representing the backward + temporal correlations. + p_f - The transition matrix representing the forward + temporal correlations. + seq - The point sequence. + lmdks - The landmarks. + Returns: + a_b - The backward privacy loss at the current timestamp + due to the previous data releases. + a_f - The forward privacy loss at the current timestamp + due to the next data releases. + a - The total privacy loss at every timestamp + taking into account landmarks. +''' +def tpl_lmdk_mem(e, p_b, p_f, seq, lmdks): + a_b = np.zeros(len(seq)) + a_f = np.zeros(len(seq)) + a = np.zeros(len(seq)) + for t in seq: + t_prv, t_nxt = get_limits(t, seq, lmdks) + a_b[t - 1] = bpl_lmdk_mem(p_b, np.zeros(max(seq)), e, t, t_prv)[t - 1] + a_f[t - 1] = fpl_lmdk_mem(p_f, np.zeros(max(seq)), e, t, t_nxt)[t - 1] + if a_b[t - 1] > 0 and a_f[t - 1] > 0: + a[t - 1] = a_b[t - 1] + a_f[t - 1] - e[t - 1] + elif a_b[t - 1] > 0 or a_f[t - 1] > 0: + a[t - 1] = a_b[t - 1] + a_f[t - 1] + else: + a[t - 1] = e[t - 1] + return a_b, a_f, a + + +''' + Get the limits for the calculation of temporal privacy loss. + + Parameters: + t - The current timestamp. + seq - The point sequence. + lmdks - The landmarks. + Returns: + t_prv - The previous landmark. + t_nxt - The next landmark. +''' +def get_limits(t, seq, lmdks): + # Add landmark limits. + seq_lmdks = np.copy(lmdks) + # if seq[0] not in seq_lmdks: + # seq_lmdks = np.append(seq_lmdks, seq[0]) + # if seq[len(seq) - 1] not in seq_lmdks: + # seq_lmdks = np.append(seq_lmdks, seq[len(seq) - 1]) + # seq_lmdks = np.sort(seq_lmdks) + # Initialize previous and next landmarks. + t_prv = 0 + t_nxt = len(seq) + 1 + # Add current timestamp to landmarks. + seq_lmdks_tmp = np.copy(seq_lmdks) + if t not in seq_lmdks_tmp[:]: + seq_lmdks_tmp = np.append(seq_lmdks, t) + seq_lmdks_tmp = np.sort(seq_lmdks_tmp) + # Find the index of the current timestamp in the landmarks. + idx, = np.where(seq_lmdks_tmp == t) + i = idx[0] + # Find previous landmark. + if i != 0: + t_prv = seq_lmdks_tmp[i - 1] + # Find next landmark. + if i != len(seq_lmdks_tmp) - 1: + t_nxt = seq_lmdks_tmp[i + 1] + return t_prv, t_nxt + + +''' + Plots the privacy loss of the time series. + + Parameters: + title - The title of the plot. + e - The privacy budget for data publishing. + a_b - The backward privacy loss. + a_f - The forward privacy loss. + a - The total privacy loss. + Returns: + Nothing. +''' +def plot_loss(title, e, a_b, a_f, a): + plt.rc('font', family='serif') + plt.rc('font', size=10) + plt.rc('text', usetex=True) + p = np.arange(1.0, len(e) + 1, 1) + plt.plot(p, + e, + label=r'$\varepsilon$', + color='gray', + marker='s') + plt.plot(p, + a_b, + label=r'$\alpha^B$', + color='#e52e4e', # red + marker='<') + plt.plot(p, + a_f, + label=r'$\alpha^F$', + color='#009874', # green + marker='>') + plt.plot(p, + a, + label=r'$\alpha$', + color='#6082b6', # blue + marker='d') + plt.axis([1.0, len(e), + 0.0, 1.5*max(a)]) + plt.legend(loc='best', frameon=True) + plt.grid(axis='y', alpha=1.0) # Add grid on y axis. + plt.xlabel('time') # Set x axis label. + plt.ylabel('privacy loss') # Set y axis label. + plt.title(title) + plt.show() + + +''' + Plots a comparison of the privacy loss of all models. + + Parameters: + title - The title of the plot. + a - The privacy loss of the basic model. + a_s - The privacy loss of the static model. + a_e - The privacy loss of the exponential model. + a_l - The privacy loss of the linear model. + Returns: + Nothing. +''' +def cmp_loss(title, a, a_s, a_e, a_l): + plt.rc('font', family='serif') + plt.rc('font', size=10) + plt.rc('text', usetex=True) + p = np.arange(1.0, len(a) + 1, 1) + plt.plot(p, + a, + label=r'$\alpha$', + color='red', + marker='s') + plt.plot(p, + a_s, + label=r'$\alpha_s$', + color='green', + marker='>') + plt.plot(p, + a_e, + label=r'$\alpha_e$', + color='blue', + marker='d') + plt.plot(p, + a_l, + label=r'$\alpha_l$', + color='yellow', + marker='<') + plt.axis([1.0, len(a), + 0.0, 1.5*max(a)]) + plt.legend(loc='best', frameon=True) + plt.grid(axis='y', alpha=1.0) # Add grid on y axis. + plt.xlabel('time') # Set x axis label. + plt.ylabel('privacy loss') # Set y axis label. + plt.title(title) + plt.show() + + +''' + Parse arguments. + + Mandatory: + model, The model to be used: (b)asic, + (s)tatic, (l)inear, (e)xponential. + + Optional: + -c, --correlation, The correlation degree. + -d, --debug, Enable debugging mode. + -e, --epsilon, The available privacy budget. + -m, --matrix, The size of the transition matrix. + -o, --output, The path to the output directory. + -t, --time, The time limit. + -w, --window, The size of the event protection window. +''' +def parse_args(): + # Create argument parser. + parser = argparse.ArgumentParser() + + # Mandatory arguments. + parser.add_argument('model', help='The model to be used.', choices=['b', 's', 'l', 'e'], type=str) + + # Optional arguments. + parser.add_argument('-c', '--correlation', help='The correlation degree.', type=float, default=0.1) + parser.add_argument('-d', '--debug', help='Enable debugging mode.', action='store_true') + parser.add_argument('-e', '--epsilon', help='The available privacy budget.', type=float, default=1.0) + parser.add_argument('-m', '--matrix', help='The matrix size.', type=int, default=2) + parser.add_argument('-o', '--output', help='The path to the output directory.', type=str, default='') + parser.add_argument('-t', '--time', help='The time limit.', type=int, default=1) + parser.add_argument('-w', '--window', help='The size of the event protection window.', type=int, default=1) + + # Parse arguments. + args = parser.parse_args() + + return args + + +def main(args): + + global DEBUG, MISS, TOTAL + DEBUG = args.debug + MISS, TOTAL = 0, 0 + + e = [args.epsilon]*args.time + + # Generate transition matrices. + p_b = gen_trans_mt(args.matrix, args.correlation) + p_f = gen_trans_mt(args.matrix, args.correlation) + + if DEBUG: + # Run basic for comparison. + a_b = bpl(p_b, [0.0] * args.time, e, args.time) + a_f = fpl(p_f, [0.0] * args.time, e, args.time) + a = tpl(a_b, a_f, e) + + output_path = args.output +\ + '/' + args.model +\ + '_c' + str(args.correlation) +\ + '_e' + str(args.epsilon) +\ + '_m' + str(args.matrix) +\ + '_t' + str(args.time) +\ + '_w' + str(args.window) + + if args.model == 'b': + # Basic + + # start_time = time.process_time() + a_b = bpl_m(p_b, [0.0] * args.time, e, args.time) + a_f = fpl_m(p_f, [0.0] * args.time, e, args.time) + a = tpl(a_b, a_f, e) + # duration1 = time.process_time() - start_time + + if DEBUG: + print('\Basic\n' + 't\tbpl\t\tfpl\t\ttpl') + for i in range(0, args.time): + print('%d\t%f\t%f\t%f' %(i + 1, a_b[i], a_f[i], a[i])) + print('\nSUM\t%f\t%f\t%f' %(sum(a_b), sum(a_f), sum(a))) + print('AVG\t%f\t%f\t%f' %(sum(a_b)/args.time, sum(a_f)/args.time, sum(a)/args.time)) + plot_loss('Basic', e, a_b, a_f, a) + if args.Returns: + save_output(output_path, args.time, e, a_b, a_f, a) + + # start_time = time.process_time() + # a_b_m = bpl_m(p_b, [0.0] * args.time, e, args.time) + # a_f_m = fpl_m(p_f, [0.0] * args.time, e, args.time) + # a_m = tpl(a_b_m, a_f_m, e) + # duration2 = time.process_time() - start_time + + # diff = ((duration2 - duration1)/duration1)*100 + # success = safe_div((TOTAL - MISS)*100, TOTAL) + # print('##############################\n' + # 'basic : %.4fs\n' + # 'w/ mem: %.4fs\n' + # '- succ: %d/%d (%.2f%%)\n' + # 'diff : %.4fs (%.2f%%)\n' + # 'OK : %r' + # %(duration1, + # duration2, + # TOTAL - MISS, TOTAL, success, + # duration2 - duration1, diff, + # np.array_equal(a, a_m))) + # MISS, TOTAL = 0, 0 + elif args.model == 's': + # Static + + # start_time = time.process_time() + a_s_b, a_s_f = [None]*args.time, [None]*args.time + for i in range(1, args.time + 1): + a_s_b[i - 1] = bpl_s_m(p_b, e, i, args.window) + a_s_f[i - 1] = fpl_s_m(p_f, e, i, args.time, args.window) + a_s = tpl(a_s_b, a_s_f, e) + # duration1 = time.process_time() - start_time + + if DEBUG: + print('\nStatic\n' + 't\tbpl\t\t\tfpl\t\t\ttpl') + for i in range(0, args.time): + print('%d\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(i + 1, + a_s_b[i], (a_s_b[i] - a_b[i])/a_b[i]*100, + a_s_f[i], (a_s_f[i] - a_f[i])/a_f[i]*100, + a_s[i], (a_s[i] - a[i])/a[i]*100)) + print('\nSUM\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(sum(a_s_b), ((sum(a_s_b) - sum(a_b))/sum(a_b))*100, + sum(a_s_f), ((sum(a_s_f) - sum(a_f))/sum(a_f))*100, + sum(a_s), ((sum(a_s) - sum(a))/sum(a))*100)) + print('AVG\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(sum(a_s_b)/args.time, ((sum(a_s_b)/args.time - sum(a_b)/args.time)/(sum(a_b)/args.time))*100, + sum(a_s_f)/args.time, ((sum(a_s_f)/args.time - sum(a_f)/args.time)/(sum(a_f)/args.time))*100, + sum(a_s)/args.time, ((sum(a_s)/args.time - sum(a)/args.time)/(sum(a)/args.time))*100)) + plot_loss('Static', e, a_s_b, a_s_f, a_s) + if args.Returns: + save_output(output_path, args.time, e, a_s_b, a_s_f, a_s) + + # start_time = time.process_time() + # a_s_b_m, a_s_f_m = [None]*args.time, [None]*args.time + # for i in range(1, args.time + 1): + # a_s_b_m[i - 1] = bpl_s_m(p_b, e, i, args.window) + # a_s_f_m[i - 1] = fpl_s_m(p_f, e, i, args.time, args.window) + # a_s_m = tpl(a_s_b_m, a_s_f_m, e) + # duration2 = time.process_time() - start_time + + # diff = ((duration2 - duration1)/duration1)*100 + # success = safe_div((TOTAL - MISS)*100, TOTAL) + # print('##############################\n' + # 'static: %.4fs\n' + # 'w/ mem: %.4fs\n' + # '- succ: %d/%d (%.2f%%)\n' + # 'diff : %.4fs (%.2f%%)\n' + # 'OK : %r' + # %(duration1, + # duration2, + # TOTAL - MISS, TOTAL, success, + # duration2 - duration1, diff, + # np.array_equal(a_s, a_s_m))) + # MISS, TOTAL = 0, 0 + elif args.model == 'l': + # Linear + l = 1 + + # start_time = time.process_time() + a_l_b, a_l_f = [None]*args.time, [None]*args.time + for i in range(1, args.time + 1): + a_l_b[i - 1] = bpl_l_m(p_b, e, i, args.window, l) + a_l_f[i - 1] = fpl_l_m(p_f, e, i, args.time, args.window, l) + a_l = tpl(a_l_b, a_l_f, e) + # duration1 = time.process_time() - start_time + + if DEBUG: + print('\nLinear\n' + 't\tbpl\t\t\tfpl\t\t\ttpl') + for i in range(0, args.time): + print('%d\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(i + 1, + a_l_b[i], (a_l_b[i] - a_b[i])/a_b[i]*100, + a_l_f[i], (a_l_f[i] - a_f[i])/a_f[i]*100, + a_l[i], (a_l[i] - a[i])/a[i]*100)) + print('\nSUM\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(sum(a_l_b), ((sum(a_l_b) - sum(a_b))/sum(a_b))*100, + sum(a_l_f), ((sum(a_l_f) - sum(a_f))/sum(a_f))*100, + sum(a_l), ((sum(a_l) - sum(a))/sum(a))*100)) + print('AVG\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(sum(a_l_b)/args.time, ((sum(a_l_b)/args.time - sum(a_b)/args.time)/(sum(a_b)/args.time))*100, + sum(a_l_f)/args.time, ((sum(a_l_f)/args.time - sum(a_f)/args.time)/(sum(a_f)/args.time))*100, + sum(a_l)/args.time, ((sum(a_l)/args.time - sum(a)/args.time)/(sum(a)/args.time))*100)) + plot_loss('Linear', e, a_l_b, a_l_f, a_l) + if args.Returns: + save_output(output_path, args.time, e, a_l_b, a_l_f, a_l) + + # start_time = time.process_time() + # a_l_b_m, a_l_f_m = [None]*args.time, [None]*args.time + # for i in range(1, args.time + 1): + # a_l_b_m[i - 1] = bpl_l_m(p_b, e, i, args.window, l) + # a_l_f_m[i - 1] = fpl_l_m(p_f, e, i, args.time, args.window, l) + # a_l_m = tpl(a_l_b_m, a_l_f_m, e) + # duration2 = time.process_time() - start_time + + # diff = ((duration2 - duration1)/duration1)*100 + # success = safe_div((TOTAL - MISS)*100, TOTAL) + # print('##############################\n' + # 'linear: %.4fs\n' + # 'w/ mem: %.4fs\n' + # '- succ: %d/%d (%.2f%%)\n' + # 'diff : %.4fs (%.2f%%)\n' + # 'OK : %r' + # %(duration1, + # duration2, + # TOTAL - MISS, TOTAL, success, + # duration2 - duration1, diff, + # np.array_equal(a_l, a_l_m))) + # MISS, TOTAL = 0, 0 + elif args.model == 'e': + # Exponential + h = 1 + + # start_time = time.process_time() + a_e_b, a_e_f = [None]*args.time, [None]*args.time + for i in range(1, args.time + 1): + a_e_b[i - 1] = bpl_e_m(p_b, e, i, args.window, h) + a_e_f[i - 1] = fpl_e_m(p_f, e, i, args.time, args.window, h) + a_e = tpl(a_e_b, a_e_f, e) + # duration1 = time.process_time() - start_time + + if DEBUG: + print('\nExponential\n' + 't\tbpl\t\t\tfpl\t\t\ttpl') + for i in range(0, args.time): + print('%d\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(i + 1, + a_e_b[i], (a_e_b[i] - a_b[i])/a_b[i]*100, + a_e_f[i], (a_e_f[i] - a_f[i])/a_f[i]*100, + a_e[i], (a_e[i] - a[i])/a[i]*100)) + print('\nSUM\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(sum(a_e_b), ((sum(a_e_b) - sum(a_b))/sum(a_b))*100, + sum(a_e_f), ((sum(a_e_f) - sum(a_f))/sum(a_f))*100, + sum(a_e), ((sum(a_e) - sum(a))/sum(a))*100)) + print('AVG\t%f (%.2f%%)\t%f (%.2f%%)\t%f (%.2f%%)' + %(sum(a_e_b)/args.time, ((sum(a_e_b)/args.time - sum(a_b)/args.time)/(sum(a_b)/args.time))*100, + sum(a_e_f)/args.time, ((sum(a_e_f)/args.time - sum(a_f)/args.time)/(sum(a_f)/args.time))*100, + sum(a_e)/args.time, ((sum(a_e)/args.time - sum(a)/args.time)/(sum(a)/args.time))*100)) + plot_loss('Exponential', e, a_e_b, a_e_f, a_e) + if args.Returns: + save_output(output_path, args.time, e, a_e_b, a_e_f, a_e) + + # start_time = time.process_time() + # a_e_b_m, a_e_f_m = [None]*args.time, [None]*args.time + # for i in range(1, args.time + 1): + # a_e_b_m[i - 1] = bpl_e_m(p_b, e, i, args.window, h) + # a_e_f_m[i - 1] = fpl_e_m(p_f, e, i, args.time, args.window, h) + # a_e_m = tpl(a_e_b_m, a_e_f_m, e) + # duration2 = time.process_time() - start_time + + # diff = ((duration2 - duration1)/duration1)*100 + # success = safe_div((TOTAL - MISS)*100, TOTAL) + # print('##############################\n' + # 'exp : %.4fs\n' + # 'w/ mem: %.4fs\n' + # '- succ: %d/%d (%.2f%%)\n' + # 'diff : %.4fs (%.2f%%)\n' + # 'OK : %r' + # %(duration1, + # duration2, + # TOTAL - MISS, TOTAL, success, + # duration2 - duration1, diff, + # np.array_equal(a_e, a_e_m))) + # MISS, TOTAL = 0, 0 + + # if DEBUG: + # cmp_loss('Backward', a_b, a_s_b, a_l_b, a_e_b) + # cmp_loss('Forward', a_f, a_s_f, a_l_f, a_e_f) + # cmp_loss('Total', a, a_s, a_l, a_e) + + +if __name__ == '__main__': + try: + args = parse_args() + print('##############################\n' + 'Correlation: %f\n' + 'Debug : %r\n' + 'Epsilon : %f\n' + 'Matrix : %d\n' + 'Model : %s\n' + 'Output : %s\n' + 'Time : %d\n' + 'Window : %d\n' + '##############################' + %(args.correlation, + args.debug, + args.epsilon, + args.matrix, + args.model, + args.output, + args.time, + args.window), flush=True) + start_time = time.process_time() + main(args) + end_time = time.process_time() + print('##############################\n' + 'Time : %.4fs\n' + '##############################\n' + %(end_time - start_time), flush=True) + except KeyboardInterrupt: + print('Interrupted by user.') + exit() diff --git a/graphics/avg-dist.pdf b/graphics/evaluation/avg-dist.pdf similarity index 73% rename from graphics/avg-dist.pdf rename to graphics/evaluation/avg-dist.pdf index 8d7751bf977c71e321150da0674a696f8cdcaecf..6a4c9f0f7f4375e075e27b9eefe17b4ae7ad3bb1 100644 GIT binary patch delta 4223 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 delta 3583 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 PVE`av4Gq`PY1sb*tt5ca diff --git a/graphics/evaluation/dist-cor-mod.pdf b/graphics/evaluation/dist-cor-mod.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4f652011ac806c9ebc7faa6a580895b940d0f26f GIT binary patch literal 16040 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

-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 E10j#-Z2$lO literal 0 HcmV?d00001 diff --git a/graphics/dist-cor-mod.pdf b/graphics/evaluation/dist-cor-stg.pdf similarity index 69% rename from graphics/dist-cor-mod.pdf rename to graphics/evaluation/dist-cor-stg.pdf index 275cee85364c4659d5eaf50a558a10d3243b5eea..8df46a5838cdc07418aa6b60ab54bb3007fc7a90 100644 GIT binary patch delta 4681 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 CZH9*c diff --git a/graphics/dist-cor-wk.pdf b/graphics/evaluation/dist-cor-wk.pdf similarity index 68% rename from graphics/dist-cor-wk.pdf rename to graphics/evaluation/dist-cor-wk.pdf index 0ddc106d7b1f5fac17313c82533485e7d7b54870..e098a935ff3b5599bd8b21b568a2c1a5b19bfde1 100644 GIT binary patch delta 4738 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 EA4JBu9smFU delta 4277 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 diff --git a/rslt/avg_dist/avg-dist.pdf b/rslt/avg_dist/avg-dist.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6a4c9f0f7f4375e075e27b9eefe17b4ae7ad3bb1 GIT binary patch literal 16971 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 literal 0 HcmV?d00001 diff --git a/rslt/dist_cor/dist-cor-mod.pdf b/rslt/dist_cor/dist-cor-mod.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4f652011ac806c9ebc7faa6a580895b940d0f26f GIT binary patch literal 16040 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

-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 E10j#-Z2$lO literal 0 HcmV?d00001 diff --git a/graphics/dist-cor-stg.pdf b/rslt/dist_cor/dist-cor-stg.pdf similarity index 68% rename from graphics/dist-cor-stg.pdf rename to rslt/dist_cor/dist-cor-stg.pdf index 9e90977139dcee4a897115b0397b5b563f3d0944..8df46a5838cdc07418aa6b60ab54bb3007fc7a90 100644 GIT binary patch delta 4783 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 C_p-|X delta 4692 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 literal 0 HcmV?d00001 diff --git a/text/evaluation/thething.tex b/text/evaluation/thething.tex index b68bad5..20aec7e 100644 --- a/text/evaluation/thething.tex +++ b/text/evaluation/thething.tex @@ -51,7 +51,8 @@ In general, we can claim that the Adaptive is the most reliable and best perform Moreover, designing a data-dependent sampling scheme would possibly result in better results for Adaptive. -\paragraph{Temporal distance and correlation} +\subsubsection{Temporal distance and correlation} + Figure~\ref{fig:avg-dist} shows a comparison of the average temporal distance of the events from the previous/next {\thething} or the start/end of the time series for various distributions in synthetic data. More particularly, we count for every event the total number of events between itself and the nearest {\thething} or the series edge. We observe that the uniform and bimodal distributions tend to limit the regular event--{\thething} distance. @@ -61,33 +62,33 @@ On the contrary, distributing the {\thethings} at one part of the sequence, as i \begin{figure}[htp] \centering - \includegraphics[width=.5\linewidth]{avg-dist}% + \includegraphics[width=.5\linewidth]{evaluation/avg-dist}% \caption{Average temporal distance of the events from the {\thethings} for different {\thethings} percentages within a time series in various {\thethings} distributions.} \label{fig:avg-dist} \end{figure} -Figure~\ref{fig:dist-cor} illustrates a comparison among the aforementioned distributions regarding the overall privacy loss under moderate (Figure~\ref{fig:dist-cor-mod}), and strong (Figure~\ref{fig:dist-cor-stg}) correlation degrees. +Figure~\ref{fig:dist-cor} illustrates a comparison among the aforementioned distributions regarding the overall privacy loss under (a)~weak, (b)~moderate, and (c)~strong temporal correlation degrees. The line shows the overall privacy loss---for all cases of {\thethings} distribution---without temporal correlation. -We skip the presentation of the results under a weak correlation degree, since they converge in this case. -In combination with Figure~\ref{fig:avg-dist}, we conclude that a greater average event-{\thething} distance in a distribution can result into greater overall privacy loss under moderate and strong temporal correlation. -This is due to the fact that the backward/forward privacy loss accumulates more over time in wider spaces without {\thethings} (see Section~\ref{subsec:correlations}). +In combination with Figure~\ref{fig:avg-dist}, we conclude that a greater average event--{\thething} distance in a distribution can result into greater overall privacy loss under moderate and strong temporal correlation. +This is due to the fact that the backward/forward privacy loss accumulates more over time in wider spaces without {\thethings} (see Section~\ref{sec:correlation}). Furthermore, the behavior of the privacy loss is as expected regarding the temporal correlation degree. Predictably, a stronger correlation degree generates higher privacy loss while widening the gap between the different distribution cases. On the contrary, a weaker correlation degree makes it harder to differentiate among the {\thethings} distributions. +The privacy loss under a weak correlation degree converge. \begin{figure}[htp] \centering \subcaptionbox{Weak correlation\label{fig:dist-cor-wk}}{% - \includegraphics[width=.5\linewidth]{dist-cor-wk}% + \includegraphics[width=.5\linewidth]{evaluation/dist-cor-wk}% }% \hspace{\fill} \subcaptionbox{Moderate correlation\label{fig:dist-cor-mod}}{% - \includegraphics[width=.5\linewidth]{dist-cor-mod}% + \includegraphics[width=.5\linewidth]{evaluation/dist-cor-mod}% }% \subcaptionbox{Strong correlation\label{fig:dist-cor-stg}}{% - \includegraphics[width=.5\linewidth]{dist-cor-stg}% + \includegraphics[width=.5\linewidth]{evaluation/dist-cor-stg}% }% - \caption{Privacy loss for different {\thethings} percentages and distributions, under weak, moderate, and strong degrees of temporal correlation. + \caption{Privacy loss for different {\thethings} percentages and distributions, under (a)~weak, (b)~moderate, and (c)~strong degrees of temporal correlation. The line shows the overall privacy loss without temporal correlation.} \label{fig:dist-cor} \end{figure}