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)
Пример #4
0
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)
Пример #7
0
def get_initial_st(g):
    sampler = st_sampler.STSampler(g)
    return sampler.sample()