def approx_count(g, M1, M2): if (random_graphs.num_edges(g) == len(g) - 1): return 1 # pick first edge of g #u = next(iter(g.keys())) #v = g[u][0] # possible because g connected # get random edge u, v = random_graphs.get_random_edge(g) # draw M1 samples to decide which case sampler = st_sampler.STSampler(g) has_e = 0 for i in range(M1): sample = sampler.sample() if v in sample[u]: has_e += 1 print(f'has_e = {has_e}') # decide if proportion of has_e > 0.5 if (2 * has_e > M1): both_nbrs = set(g[v]).intersection(set( g[u])) # a vertex is a double if it is in this set # contract g random_graphs.contract(g, (u, v)) # we need to do some extra estimation, because st of the contracted g can be expanded in many ways sampler = st_sampler.STSampler(g) counter = collections.Counter() # counts freq of doubles for i in range(M2): sample = sampler.sample() num_doubles = len(set( sample[u]).intersection(both_nbrs)) # u is now the node (u+v) counter[num_doubles] += 1 exp = get_expansion_factor(counter) print(f'exp factor = {exp}') nst = mtt.MTT(g) rec = approx_count(g, M1, M2) est = rec error = abs(est - nst) / nst * 100 print(f'actual = {nst}, estimated = {est}, error = {error}') return rec * exp * M1 / has_e else: # delete e and recurse g[u].remove(v) g[v].remove(u) nst = mtt.MTT(g) rec = approx_count(g, M1, M2) est = rec error = abs(est - nst) / nst * 100 print(f'actual = {nst}, estimated = {est}, error = {error}') return rec * M1 / (M1 - has_e)
def approx_count_iter(g, M1, M2): est = 1 # accumulates the multiplers here while (random_graphs.num_edges(g) > len(g) - 1): # while we dont have a spanning tree u, v = random_graphs.get_random_edge(g) # draw M1 samples to decide which how to reduce the graph sampler = st_sampler.STSampler(g) has_e = 0 for i in range(M1): sample = sampler.sample() if v in sample[u]: has_e += 1 print(f'has_e / M1 = {has_e}/{M1}') # decide which of the 2 reductions to use if (2 * has_e > M1): # has_e > 0.5 both_nbrs = set(g[v]).intersection(set( g[u])) # a vertex is a double if it is in this set random_graphs.contract(g, (u, v)) #we need to do some extra estimation, because st of the contracted g can be expanded in many ways sampler = st_sampler.STSampler(g) counter = collections.Counter() # counts freq of doubles for i in range(M2): sample = sampler.sample() num_doubles = len(set(sample[u]).intersection( both_nbrs)) # u is now the node (u+v) counter[num_doubles] += 1 exp = get_expansion_factor(counter) print('num_bad =', len(both_nbrs)) print(counter) print(f'exp_factor = {exp.numerator / exp.denominator}') if (exp > 1): print('*' * 50) # some debug info est *= Fraction(M1, has_e) * exp else: # delete e and recurse g[u].remove(v) g[v].remove(u) est *= Fraction(M1, M1 - has_e) return round(est)
def unit_test_1(): n = 10 p = 0.3 seed = 1 g = random_graphs.get_random_connected_graph(n, p) # todo: add seed num_samples = 100 sampler = st_sampler.STSampler( {}) # empty sampler, it will be initialized within fn later use_log = False nst = approx_count_st_testing_ver(g, sampler, num_samples, use_log) print(nst)
def approx_term_1(g, u, v, num_samples): min_denom = 5 sampler = st_sampler.STSampler(g) denominator = 0 for _ in range(num_samples): sample = sampler.sample() if u not in sample[v]: denominator += 1 while denominator < min_denom: # while denom is too small, take more samples sample = sampler.sample() if u not in sample[v]: denominator += 1 num_samples += 1 return Fraction(num_samples, denominator)
def unit_test_2(): n = 30 p = 0.3 seed = 1 g = random_graphs.get_random_connected_graph(n, p) # todo: add seed sampler = st_sampler.STSampler( {}) # empty sampler, it will be initialized within fn later num_edges_each_time_fn_1 = lambda x, y: 1 # one edge each time num_samples_fn_1 = lambda x, y: 200 # 100 samples each time num_edges_each_time_fn_2 = lambda x, y: 3 # 3 edges each time num_samples_fn_2 = lambda x, y: 100 + 30 * y # 100 samples as base, and for every edge, add 10 samples use_log = False nst = approx_count_st_generic(g, sampler, num_samples_fn_2, num_edges_each_time_fn_2, use_log) actual = mtt.MTT(g) print('error =', abs(nst - actual) / actual)
def unit_test(): n = 8 d = 0.3 g = random_graphs.get_random_connected_graph(n, d) sampler = st_sampler.STSampler(g) test_for_uniform_dist(g, sampler)
def get_initial_st(g): sampler = st_sampler.STSampler(g) return sampler.sample()