示例#1
0
def create_complex_mech(sigma1, sigma2, eps, coeffs):
    gm1 = ExactGaussianMechanism(sigma1, name='GM1')
    gm2 = ExactGaussianMechanism(sigma2, name='GM2')
    SVT = PureDP_Mechanism(eps=eps, name='SVT')

    # run gm1 for 3 rounds
    # run gm2 for 5 times
    # run SVT for once
    # compose them with the transformation: compose.
    compose = Composition()
    composed_mech = compose([gm1, gm2, SVT], coeffs)
    return composed_mech
示例#2
0
def testcase_single_para():

    test_case = []
    # each test_case = {'noise_para','delta','eps'} range sigma from 1 to 100
    sigma_list = [
        int(1.6**i) for i in range(int(math.floor(math.log(100, 1.6))) + 1)
    ]
    for sigma in sigma_list:
        for delta in [1e-3, 1e-4, 1e-5, 1e-6]:
            gm = ExactGaussianMechanism(sigma, name='GM')
            cur_test = {
                'sigma': sigma,
                'delta': delta,
                'eps': gm.get_approxDP(delta)
            }
            test_case.append(cur_test)
    return test_case
示例#3
0
def testcase_multi_para():
    """
	create test cases when there are multi parameters (e.g., #coeff and sigma in Composed Gaussian mechanism)
	"""

    test_case = []
    # each test_case = {'noise_para','delta','coeff','eps'} range sigma from 1 to 100, coeff is the number of composition
    sigma_list = [
        int(1.6**i) for i in range(int(math.floor(math.log(100, 1.6))) + 1)
    ]
    for sigma in sigma_list:
        for coeff in [1, 10, 100, 1000]:
            for delta in [1e-3, 1e-4, 1e-5, 1e-6]:
                gm = ExactGaussianMechanism(sigma, name='GM')
                compose = Composition()
                composed_mech = compose([gm], [coeff])
                cur_test = {
                    'sigma': sigma,
                    'delta': delta,
                    'coeff': coeff,
                    'eps': composed_mech.get_approxDP(delta)
                }
                test_case.append(cur_test)
    return test_case
示例#4
0
sigma1 = 5

gm1 = GaussianMechanism(sigma1, phi_off=False, name='phi_GM1')

compose = ComposeAFA()
composed_mech = compose([gm1], [10])
delta1 = 1e-6
eps1 = composed_mech.get_approxDP(delta1)

# RDP-based accountant.
gm2 = GaussianMechanism(sigma1, name='rdp_GM2')
compose_rdp = Composition()
composed_mech_rdp = compose_rdp([gm2], [10])

#Exact Gaussian mechanism.
gm3 = ExactGaussianMechanism(sigma1, name='exact_GM3')
compose_exact = ComposeGaussian()
composed_mech_exact = compose_exact([gm3], [10])

# Get name of the composed object, a structured description of the mechanism generated automatically
print('Mechanism name is \"', composed_mech.name, '\"')
print('Parameters are: ', composed_mech.params)
print('epsilon(delta) = ', eps1, ', at delta = ', delta1)
print('Results from rdp_based accountant, epsilon(delta) = ',
      composed_mech_rdp.get_approxDP(delta1), ', at delta = ', delta1)
print('Results from AFA, epsilon(delta) = ', eps1, ', at delta = ', delta1)
print('Results from exact Gaussian accountant, epsilon(delta) = ',
      composed_mech_exact.get_approxDP(delta1), ', at delta = ', delta1)

## Example 2:  Composition of a heterogeneous sequence of mechanisms [Gaussian mechanism, randomized response ...].
"""
示例#5
0
from autodp.mechanism_zoo import ExactGaussianMechanism
from autodp.transformer_zoo import Composition, ComposeGaussian
import matplotlib.pyplot as plt

sigma1 = 5.0
sigma2 = 8.0

gm1 = ExactGaussianMechanism(sigma1, name='GM1')
gm2 = ExactGaussianMechanism(sigma2, name='GM2')

# run gm1 for 3 rounds
# run gm2 for 5 times

# compose them with the transformation: compose and
rdp_compose = Composition()
rdp_composed_mech = rdp_compose([gm1, gm2], [3, 5])

compose = ComposeGaussian()
composed_mech = compose([gm1, gm2], [3, 5])

# Query for eps given delta
delta1 = 1e-6
eps1 = composed_mech.get_approxDP(delta1)
eps1b = rdp_composed_mech.get_approxDP(delta1)

delta2 = 1e-4
eps2 = composed_mech.get_approxDP(delta2)
eps2b = rdp_composed_mech.get_approxDP(delta2)

# Get name of the composed object, a structured description of the mechanism generated automatically
print('Mechanism name is \"', composed_mech.name, '\"')
示例#6
0
def exp5_subsample_fixed_eps():
    """
    Evaluate poisson subsample Gaussian mechanism
    sample probability = 0.02, fix delta to 1e-5 and compare epsilon over composition
    x axis is # composition
    y axis is epsilon(delta)

    Evaluate four methods
    BBGHS_RDP :eps_rdp
    Our phi-function lower bound: eps_phi_left
    Our phi-function upper bound:  eps_phi_right
    Double quadrature:eps_quadrature
    """

    delta = 1e-5

    import pickle
    prob = 0.02
    klist = [100 * i for i in range(2, 16)]

    doc = {}
    exp4_path = 'exp5.pkl'
    if os.path.exists(exp4_path):
        with open(exp4_path, 'rb') as f:
            doc = pickle.load(f)
            klist = klist[:]
            eps_phi_left = doc['phi_left']
            eps_phi_right = doc['phi_right']
            eps_rdp = doc['rdp']
            eps_quarture = doc['quarture']
    else:

        for sigma in [2]:
            eps_rdp = []
            eps_phi_left = []
            eps_phi_right = []
            eps_quarture = []
            for coeff in klist:
                gm1 = ExactGaussianMechanism(sigma, name='GM1')
                compose = Composition()
                poisson_sample = AmplificationBySampling(PoissonSampling=True)
                composed_mech = compose(
                    [poisson_sample(gm1, prob, improved_bound_flag=True)],
                    [coeff])
                #phi_subsample_left = SubSampleGaussian(sigma, prob,coeff, CDF_off=False, lower_bound = True)
                #phi_subsample_right = SubSampleGaussian(sigma, prob,coeff, CDF_off=False, upper_bound = True)
                phi_quarture = SubSampleGaussian(sigma,
                                                 prob,
                                                 coeff,
                                                 CDF_off=False)
                eps_rdp.append(composed_mech.approxDP(delta))
                eps_quarture.append(phi_quarture.get_approxDP(delta))
                #eps_phi_left.append(phi_subsample_left.approxDP(delta))
                #eps_phi_right.append(phi_subsample_right.approxDP(delta))
                print('eps using double quarture', eps_quarture)
                #print('eps using phi lower bound', eps_phi_left)
                #print('eps using phi right bound', eps_phi_right)
                print('eps using the optimal rdp conversion', eps_rdp)
            cur_result = {}
            cur_result['rdp'] = eps_rdp
            cur_result['phi_left'] = eps_phi_left
            cur_result['phi_right'] = eps_phi_right
            cur_result['quarture'] = eps_quarture

            with open(exp4_path, 'wb') as f:
                pickle.dump(cur_result, f)

    for sigma in [2]:
        naive_rdp = []
        eps_optimal_rdp = []

        for coeff in klist:
            gm1 = ExactGaussianMechanism(sigma, name='GM1')
            compose = Composition()
            poisson_sample = AmplificationBySampling(PoissonSampling=True)
            composed_mech = compose(
                [poisson_sample(gm1, prob, improved_bound_flag=True)], [coeff])
            eps_optimal_rdp.append(composed_mech.approxDP(delta))

    print('RDP optimal conversion', eps_optimal_rdp)
    print('quarture result', eps_quarture)

    # copy the results from fourier paper and our previous experimental results
    eps_quarture = [
        0.5732509555915974, 0.7058115513738935, 0.8194825434078763,
        0.9209338664859984, 1.0136435019043732, 1.099702697374365,
        1.1804867199047775, 1.2569025991868228, 1.3296691895163435,
        1.3993259169003278, 1.4662601850161303, 1.5308113615711694,
        1.5932321716160407, 1.6637669337344212
    ]
    eps_phi_left = [
        0.5553297955867375, 0.6832218356617155, 0.7928056642133938,
        0.8906191704210357, 0.9799696230766813, 1.0628838022920961,
        1.1406664339350132, 1.2142613396519286, 1.2843523223848659,
        1.3513924639580124, 1.4158316082377795, 1.4779534607841263,
        1.5380153993392631, 1.5962516845946515
    ]
    eps_phi_right = [
        0.5866220805156243, 0.7223973520962709, 0.8387942691051304,
        0.9426878979377773, 1.0376345860832061, 1.1257547173351041,
        1.2084450581608812, 1.2867150182217082, 1.3612194904959256,
        1.4325246778969292, 1.5010566850456206, 1.567135674028485,
        1.6310457295344567, 1.6929980332709857
    ]
    fft_lower = [
        0.5738987073827246, 0.7070330939276875, 0.8213662927173179,
        0.92358900507979, 1.0171625920742302, 1.1041565229625558,
        1.1859259173798518, 1.2634158671679698, 1.3373168083154394,
        1.4081514706603082, 1.4763269642671626, 1.54216775460533,
        1.605937390055278, 1.667853467197358
    ]
    fft_higher = [
        0.5738987073827246, 0.7070330939276875, 0.8213662927173179,
        0.92358900507979, 1.0171625920742302, 1.1041565229625558,
        1.1859259173798518, 1.2634158671679698, 1.3373168083154394,
        1.4081514706603082, 1.4763269642671626, 1.54216775460533,
        1.605937390055278, 1.667853467197358
    ]
    import matplotlib.pyplot as plt
    #epsusingphi[1.7183697391746319e-06, 1.735096619083328e-06, 2.090003729609751e-06]
    #epsusingrdp[1.1702248059464182e-09, 4.4203574134371593e-10, 3.824438543631459e-10]
    props = fm.FontProperties(family='Gill Sans',
                              fname='/Library/Fonts/GillSans.ttc')
    f, ax = plt.subplots()
    plt.figure(num=0, figsize=(12, 8), dpi=80, facecolor='w', edgecolor='k')
    #plt.plot(klist,naive_rdp, 'g.-.', linewidth=2)
    plt.plot(klist, eps_rdp, 'm.-.', linewidth=2)
    #plt.plot(klist, eps_optimal_rdp, 'y.-', linewidth=2)
    plt.plot(klist, eps_phi_left, 'cx-', linewidth=2)
    plt.plot(klist, eps_phi_right, 'rx-', linewidth=2)
    plt.plot(klist, eps_quarture, 'y.-', linewidth=2)
    plt.plot(klist, fft_lower, 'gs--', linewidth=1)
    plt.plot(klist, fft_higher, 'rs--', linewidth=1)

    #plt.plot(klist, doc['20']['rdp'], '--k', linewidth=2)
    #plt.plot(klist, doc['20']['eps'], '--r^', linewidth=2)
    plt.legend([
        r'BBGHS_RDP', 'our AFA lower bound', 'our AFA higher bound',
        'Double quadrature', 'FA lower bound', 'FA higher bound'
    ],
               loc='best',
               fontsize=17)
    plt.grid(True)
    plt.xticks(fontsize=22)
    plt.yticks(fontsize=22)
    plt.xlabel(r'Number of Compositions $k$', fontsize=22)
    plt.ylabel(r'$\epsilon$', fontsize=22)
    ax.set_title('Title', fontproperties=props)
    #plt.show()
    plt.savefig('exp4_eps.pdf', bbox_inches='tight')
示例#7
0
def exp4_subsample_fixed_eps():
    """
    Evaluate poisson subsample Gaussian mechanism
    sample probability = 0.02, fix epsilon to 1.0 and compare delta over composition
    x axis is # composition
    y axis is delta(epsilon)

    Evaluate four methods
    BBGHS_RDP :eps_rdp
    Our phi-function lower bound: eps_phi_left
    Our phi-function upper bound:  eps_phi_right
    Double quadrature:eps_quadrature
    """

    eps = 1.0

    import pickle
    prob = 0.02
    klist = [100 * i for i in range(2, 16)]
    exp4_path = 'gamma_0.02_sigma_12.pkl'
    if os.path.exists(exp4_path):
        with open(exp4_path, 'rb') as f:
            doc = pickle.load(f)
            klist = klist[:]
            eps_phi_left = doc['phi_left']
            eps_phi_right = doc['phi_right']
            eps_rdp = doc['rdp']
            eps_quarture = doc['quarture']
    else:

        for sigma in [2]:
            eps_rdp = []
            eps_phi_left = []
            eps_phi_right = []
            eps_quarture = []
            for coeff in klist:
                gm1 = ExactGaussianMechanism(sigma, name='GM1')
                compose = Composition()
                poisson_sample = AmplificationBySampling(PoissonSampling=True)
                composed_mech = compose(
                    [poisson_sample(gm1, prob, improved_bound_flag=True)],
                    [coeff])
                #uncomment the code below to run upper and lower bounds, which is much slower
                #phi_subsample_left = SubSampleGaussian(sigma, prob,coeff, CDF_off=False, lower_bound = True)
                #phi_subsample_right = SubSampleGaussian(sigma, prob,coeff, CDF_off=False, upper_bound = True)
                phi_quarture = SubSampleGaussian(sigma,
                                                 prob,
                                                 coeff,
                                                 CDF_off=False)
                eps_rdp.append(composed_mech.approx_delta(eps))
                eps_quarture.append(phi_quarture.get_approx_delta(eps))
                #eps_phi_left.append(phi_subsample_left.approx_delta(eps))
                #eps_phi_right.append(phi_subsample_right.approx_delta(eps))
                print('eps using double quarture', eps_quarture)
                print('eps using phi lower bound', eps_phi_left)
                print('eps using phi right bound', eps_phi_right)
                print('eps using rdp', eps_rdp)
            cur_result = {}
            cur_result['rdp'] = eps_rdp

            #eps_phi = [8.126706321817492e-11, 1.680813696457811e-08, 3.7171456678093376e-07, 2.8469414374309687e-06, 1.2134517188197369e-05, 3.612046366420398e-05, 8.487142126792672e-05, 0.00016916885963894502]
            # previous experimental records for the sigma = 2.0, eps =1.0
            cur_result['phi_left'] = [
                1.9705163375286992e-11, 6.54413434131078e-09,
                1.8172415920878554e-07, 1.5912195465344071e-06,
                7.408024600416465e-06, 2.3476597821679127e-05,
                5.780615396550352e-05, 0.0001194871003954497,
                0.00021761168363315566, 0.00036048564689211086,
                0.0005551755399635068, 0.0008073269983187659,
                0.0011211655514957834, 0.0014996039591825359
            ]
            cur_result['phi_right'] = [
                1.4208450705963226e-10, 2.7065873453364222e-08,
                5.615768975610223e-07, 4.101636149422114e-06,
                1.6856443667586166e-05, 4.875023579764651e-05,
                0.00011190249522187185, 0.00021878046437442066,
                0.00038078926980138466, 0.0006074760381444841,
                0.0009062357815770332, 0.0012823422696145335,
                0.0017391548126395213, 0.0022783994671059515
            ]
            #cur_result['phi_left'] = eps_phi_left
            #cur_result['phi_right'] = eps_phi_right
            cur_result['quarture'] = eps_quarture

            with open(exp4_path, 'wb') as f:
                pickle.dump(cur_result, f)
    # copy the results from Fourier accountant paper
    fft_lower = [
        7.887405682751439e-11, 1.621056159906838e-08, 3.547744440606434e-07,
        2.6891898301208684e-06, 1.1344617219024322e-05, 3.342412117224878e-05,
        7.773514229351955e-05, 0.00015336724020791973, 0.00026855202090630444,
        0.00042999375546865035, 0.0006426099200177218, 0.0009095489321732455,
        0.00123236372576394, 0.0016112544734264512
    ]
    fft_higher = [
        8.195861133559092e-11, 1.7175792871794577e-08, 3.8343699421628997e-07,
        2.9650469214763064e-06, 1.2761325748530785e-05, 3.836009767606709e-05,
        9.10255425945141e-05, 0.0001832372011979862, 0.00032737944462639086,
        0.0005348503868262945, 0.0008155844687884689, 0.0011778834943758018,
        0.001628443617837156, 0.002172490405255
    ]
    for sigma in [2]:

        eps_optimal_rdp = []

        for coeff in klist:
            gm1 = ExactGaussianMechanism(sigma, name='GM1')
            compose = Composition()
            poisson_sample = AmplificationBySampling(PoissonSampling=True)
            composed_mech = compose(
                [poisson_sample(gm1, prob, improved_bound_flag=True)], [coeff])
            eps_optimal_rdp.append(composed_mech.approx_delta(eps))

    print('optimal conversion', eps_optimal_rdp)
    print('quarture result', eps_quarture)
    print('RDP result', eps_rdp)
    import matplotlib.pyplot as plt

    props = fm.FontProperties(family='Gill Sans',
                              fname='/Library/Fonts/GillSans.ttc')
    f, ax = plt.subplots()
    plt.figure(num=0, figsize=(12, 8), dpi=80, facecolor='w', edgecolor='k')
    #plt.plot(klist,naive_rdp, 'g.-.', linewidth=2)
    plt.plot(klist, eps_rdp, 'm.-.', linewidth=2)
    plt.plot(klist, eps_optimal_rdp, 'y.-', linewidth=2)
    plt.plot(klist, eps_phi_left, 'cx--', linewidth=2)
    plt.plot(klist, eps_phi_right, 'rx--', linewidth=2)
    plt.plot(klist, eps_quarture, 'bx--', linewidth=2)
    plt.plot(klist, fft_lower, 'gs-', linewidth=1)
    plt.plot(klist, fft_higher, 'rs-', linewidth=1)
    plt.ylim([1e-12, 1e-1])
    plt.yscale('log')
    #plt.plot(klist, doc['20']['rdp'], '--k', linewidth=2)
    #plt.plot(klist, doc['20']['eps'], '--r^', linewidth=2)
    plt.legend([
        r'BBGHS_RDP_conversion', 'Optimal_RDP_Conversion',
        '$\phi$-function_lower', '$\phi$-function_upper',
        'Double quadrature method', 'FA lower bound', 'FA higher bound'
    ],
               loc='best',
               fontsize=17)
    plt.grid(True)
    plt.xticks(fontsize=20)
    plt.yticks(fontsize=20)
    plt.xlabel(
        r'Number of Composition ($\epsilon=1.0, \sigma=2$, sample probability=$0.02$)',
        fontsize=20)
    plt.ylabel(r'$\delta$', fontsize=20)
    ax.set_title('Title', fontproperties=props)
    #plt.show()
    plt.savefig('exp4_delta.pdf', bbox_inches='tight')
示例#8
0
def exp_2a():

    eps_a = []   #standard SVT
    eps_e = []   #Laplace-SVT (via RDP)
    eps_g = []   #Gaussian SVT c>1
    eps_g_c = [] #c=1 for Gaussian SVT
    eps_i = []
    eps_kov = [] #generalized SVT
    eps_noisy = []
    k_list =  [int(1.4**i) for i in range(int(math.floor(math.log(n,1.4)))+1)]
    print(len(k_list))

    query = np.zeros(n)
    rho = np.random.normal(scale=sigma_1)
    lap_rho = np.random.laplace(loc=0.0, scale=lambda_rho)

    """
    compute eps for noisy screening
    p = Prob[ nu > Margin]
    q = Prob[ nu - 1 > margin]
    
    count_gau counts #tops in Gaussian-SVT
    count_lap counts #tops in Laplace-SVT
    """

    count_gau = 0
    count_lap = 0

    # the following is for data-dependent screening in CVPR-20
    p = scipy.stats.norm.logsf(margin, scale=sigma_2)
    q = scipy.stats.norm.logsf(margin + 1, scale=sigma_2)
    params = {}
    params['logp'] = p
    params['logq'] = q
    per_screen_mech = NoisyScreenMechanism(params, name='NoisyScreen')
    per_gaussian_mech = ExactGaussianMechanism(sigma_2,name='GM1')
    index = []
    compose = Composition()
    for idx, qu in enumerate(query):
        nu = np.random.normal(scale=sigma_2)
        lap_nu = np.random.laplace(loc=0.0, scale=lambda_nu)
        if nu >= rho + margin:
            count_gau += 1
        if lap_nu >= lap_rho + margin:
            count_lap += 1
        count_gau = max(count_gau, 1)
        count_lap = max(count_lap, 1)

        if idx in k_list:
            index.append(idx)
            print('number of queries passing threshold', count_gau)

            #eps_a records the standard SVT
            eps_a.append(eps_1 * count_lap + eps_1)
            # compose data-dependent screening
            screen_mech = compose([per_screen_mech], [idx])
            gaussian_mech = compose([per_gaussian_mech], [idx])

            # standard SVT with RDP calculation
            param_lap_svt = {}
            param_lap_svt['b'] = lambda_rho
            param_lap_svt['k'] = idx
            param_lap_svt['c'] = count_lap
            lapsvtrdp_mech = LaplaceSVT_Mechanism(param_lap_svt)
            eps_e.append(lapsvtrdp_mech.get_approxDP(delta))

            # stage-wise generalized SVT, k is the maximum length of each chunk
            k = int(idx / np.sqrt(count_gau))
            generalized_mech = StageWiseMechanism({'sigma':sigma_1,'k':k, 'c':count_gau})
            eps_kov.append(generalized_mech.get_approxDP(delta))

            # Gaussian-SVT c>1 with RDP, k is the total length before algorithm stops
            gaussianSVT_c = GaussianSVT_Mechanism({'sigma':sigma_1,'k':idx, 'c':count_gau}, rdp_c_1=False)
            eps_g.append(gaussianSVT_c.get_approxDP(delta))

            #Gaussian-SVT with c=1, we use average_k as the approximate maximum length of each chunk, margin is used in Proposition 10
            average_k = int(idx / max(count_gau, 1))
            params_SVT = {}
            params_SVT['k'] = average_k
            params_SVT['sigma'] = sigma_1
            params_SVT['margin'] = margin
            per_gaussianSVT_mech = GaussianSVT_Mechanism(params_SVT)
            gaussianSVT_mech = compose([per_gaussianSVT_mech],[max(count_gau, 1)])
            eps_g_c.append(gaussianSVT_mech.get_approxDP(delta))

            eps_i.append(gaussian_mech.get_approxDP(delta))  # Gaussian Mechanism
            eps_noisy.append(screen_mech.get_approxDP(delta))

    import matplotlib
    import matplotlib.pyplot as plt

    font = {'family': 'times',
            'weight': 'bold',
            'size': 18}

    props = fm.FontProperties(family='Gill Sans', fname='/Library/Fonts/GillSans.ttc')
    f, ax = plt.subplots()
    plt.figure(num=0, figsize=(12, 8), dpi=80, facecolor='w', edgecolor='k')
    plt.loglog(index, eps_a, '-r', linewidth=2)
    plt.loglog(index, eps_e, '--g^', linewidth=2)
    plt.loglog(index, eps_g, '-c^', linewidth=2)
    plt.loglog(index, eps_g_c, '-bs', linewidth=2)
    plt.loglog(index, eps_i, '--k', linewidth=2)
    plt.loglog(index, eps_noisy, color='brown', linewidth=2)
    plt.loglog(index, eps_kov, color='hotpink', linewidth=2)
    plt.legend(
        ['Laplace-SVT (Pure-DP from Lyu et al., 2017)', 'Laplace-SVT (via RDP)', 'Gaussian-SVT c>1 (RDP by Theorem 11)',
         'Gaussian-SVT c=1 (RDP by Theorem 8)', 'Gaussian Mechanism', 'Noisy Screening (data-dependent RDP)',
         'Stage-wise generalized SVT'], loc='best', fontsize=17)
    plt.grid(True)
    plt.xticks(fontsize=20)
    plt.yticks(fontsize=20)
    plt.xlabel(r'Iterations', fontsize=20)
    plt.ylabel(r'$\epsilon$', fontsize=20)
    ax.set_title('Title', fontproperties=props)

    plt.savefig('exp2a.pdf', bbox_inches='tight')
示例#9
0
from autodp.mechanism_zoo import ExactGaussianMechanism, PureDP_Mechanism
from autodp.transformer_zoo import Composition, AmplificationBySampling
import matplotlib.pyplot as plt

sigma1 = 5.0
sigma2 = 8.0

gm1 = ExactGaussianMechanism(sigma1, name='GM1')
gm2 = ExactGaussianMechanism(sigma2, name='GM2')
SVT = PureDP_Mechanism(eps=0.1, name='SVT')

# run gm1 for 3 rounds
# run gm2 for 5 times
# run SVT for once

# compose them with the transformation: compose.
compose = Composition()

poisson_sample = AmplificationBySampling(PoissonSampling=True)
subsample = AmplificationBySampling(PoissonSampling=False)

prob = 0.1
coeffs = [30, 50, 10]

composed_mech = compose([gm1, gm2, SVT], coeffs)

composed_poissonsampled_mech = compose([
    poisson_sample(gm1, prob),
    poisson_sample(gm2, prob),
    poisson_sample(SVT, prob)
], coeffs)