Example #1
0
def individual_nudge(old_X: dit.Distribution,
                     eps: float = 0.01,
                     rvs_other=None) -> dit.Distribution:
    mask = old_X._mask
    base = old_X.get_base()
    if old_X.outcome_length() == 1:
        return global_nudge(old_X, eps)
    outcomes = old_X.outcomes
    rv_names = old_X.get_rv_names()

    if rvs_other == None:
        rvs = old_X.get_rv_names()
        rvs_other = np.random.choice(rvs, len(rvs) - 1, replace=False)

    X_other, Xi_given_Xother = old_X.condition_on(rvs_other)
    nudge_size = len(Xi_given_Xother[0])

    if base == 'linear':
        nudge = generate_nudge(nudge_size, eps / len(Xi_given_Xother))
        for Xi in Xi_given_Xother:
            perform_nudge(Xi, nudge)
    else:
        nudge, sign = generate_log_nudge(nudge_size, eps)
        for Xi in Xi_given_Xother:
            perform_log_nudge(Xi, nudge, sign)
    new_X = dit.joint_from_factors(X_other, Xi_given_Xother).copy(base)
    #add back any missing outcomes
    dct = {o: new_X[o] if o in new_X.outcomes else 0.0 for o in outcomes}
    #print(outcomes, dct)
    new_X = dit.Distribution(dct)
    new_X.set_rv_names(rv_names)
    new_X.make_dense()
    new_X._mask = mask
    return new_X
Example #2
0
def test_bad_marginal():
    d = dit.example_dists.Xor()
    pY, pXZgY = d.condition_on([1])

    # Incompatible marginal
    pY = dit.Distribution(['0', '1', '2'], [.25, .5, .25])
    assert_raises(dit.exceptions.ditException,
                  dit.joint_from_factors, pY, pXZgY, strict=False)

    # Compatible marginal that is not trim.
    pY = dit.Distribution(['0', '1', '2'], [.25, .75, 0])
    pY.make_dense()
    pYXZ = dit.joint_from_factors(pY, pXZgY, strict=False)

    # Compatible marginal that is not trim.
    # Note here that we have created a completely different distribution
    # where the outcomes for X are '0' and '2' now.
    pY = dit.Distribution(['0', '1', '2'], [.25, 0, .75])
    pY.make_dense()
    pYXZ = dit.joint_from_factors(pY, pXZgY, strict=False)
Example #3
0
def test_bad_marginal():
    d = dit.example_dists.Xor()
    pY, pXZgY = d.condition_on([1])

    # Incompatible marginal
    pY = dit.Distribution(['0', '1', '2'], [.25, .5, .25])
    with pytest.raises(dit.exceptions.ditException):
        dit.joint_from_factors(pY, pXZgY, strict=False)

    # Compatible marginal that is not trim.
    pY = dit.Distribution(['0', '1', '2'], [.25, .75, 0])
    pY.make_dense()
    pYXZ = dit.joint_from_factors(pY, pXZgY, strict=False)

    # Compatible marginal that is not trim.
    # Note here that we have created a completely different distribution
    # where the outcomes for X are '0' and '2' now.
    pY = dit.Distribution(['0', '1', '2'], [.25, 0, .75])
    pY.make_dense()
    pYXZ = dit.joint_from_factors(pY, pXZgY, strict=False)
Example #4
0
def test_joint_from_factors_rvname():
    d = dit.example_dists.Xor()
    d.pmf = dit.math.pmfops.jittered(d.pmf, .4)
    d.set_rv_names('XYZ')
    pY, pXZgY = d.condition_on('Y')

    # Standard
    pXYZ = dit.joint_from_factors(pY, pXZgY)
    assert pXYZ.is_approx_equal(d)

    # Now we make them have incompatible masks.
    pY._new_mask()
    with pytest.raises(dit.exceptions.ditException):
        dit.joint_from_factors(pY, pXZgY, strict=True)

    # Build out of order now.
    pYXZ = dit.joint_from_factors(pY, pXZgY, strict=False)
    # This is one instance where ['YXZ'] is not treated the same as 'YXZ'
    d2 = d.coalesce(['YXZ'], extract=True)
    assert pYXZ.is_approx_equal(d2)
Example #5
0
def test_joint_from_factors_rvname():
    d = dit.example_dists.Xor()
    d.pmf = dit.math.pmfops.jittered(d.pmf, .4)
    d.set_rv_names('XYZ')
    pY, pXZgY = d.condition_on('Y')

    # Standard
    pXYZ = dit.joint_from_factors(pY, pXZgY)
    assert_true(pXYZ.is_approx_equal(d))

    # Now we make them have incompatible masks.
    pY._new_mask()
    assert_raises(dit.exceptions.ditException,
                  dit.joint_from_factors, pY, pXZgY, strict=True)

    # Build out of order now.
    pYXZ = dit.joint_from_factors(pY, pXZgY, strict=False)
    # This is one instance where ['YXZ'] is not treated the same as 'YXZ'
    d2 = d.coalesce(['YXZ'], extract=True)
    assert_true(pYXZ.is_approx_equal(d2))
Example #6
0
def test_channel_capacity_no_rvnames():
    epsilon = .3
    pXY = BEC_joint(epsilon)
    pX, pYgX = pXY.condition_on([0])
    cc, pXopt = dit.algorithms.channel_capacity(pYgX, pX)

    # Verify channel capacity.
    np.testing.assert_allclose(cc, 1 - epsilon)

    # Verify maximizing distribution.
    assert_true(pX.is_approx_equal(pXopt))

    # Verify joint distribution at channel capacity.
    pXYopt = dit.joint_from_factors(pXopt, pYgX)
    assert_true(pXY.is_approx_equal(pXYopt))
Example #7
0
def test_channel_capacity_no_rvnames():
    epsilon = 0.3
    pXY = BEC_joint(epsilon)
    pX, pYgX = pXY.condition_on([0])
    cc, pXopt = channel_capacity(pYgX, pX)

    # Verify channel capacity.
    assert np.allclose(cc, 1 - epsilon)

    # Verify maximizing distribution.
    assert pX.is_approx_equal(pXopt)

    # Verify joint distribution at channel capacity.
    pXYopt = joint_from_factors(pXopt, pYgX)
    assert pXY.is_approx_equal(pXYopt)
Example #8
0
def experiment(inputs):
    level, n_vars, dists, interventions, seed = inputs
    np.random.seed(seed)
    n_states = 3

    nudges = [individual_nudge, local_nudge, synergistic_nudge, derkjanistic_nudge, global_nudge]
    # nudges = [individual_nudge, local_nudge, synergistic_nudge, global_nudge]
    means = np.zeros((dists, len(nudges)))
    for i in range(dists):
        XY = generate_distribution(n_vars + 1, n_states, level)  # +1 for the output variable
        old_Y = XY.marginal('Y').copy('linear')
        old_X, YgivenX = get_marginals(XY)
        [Y.make_dense() for Y in YgivenX]
        oldest_X = old_X.copy()

        intervention_results = np.zeros((len(nudges), interventions))
        for j in range(interventions):
            for idx, nudge in enumerate(nudges):
                if not np.allclose(old_X.pmf, oldest_X.pmf):
                    raise ValueError("Something went wrong during {}. Original X has changed".format(nudge.__name__))
                new_X = None
                try:
                    new_X = nudge(old_X)
                except IndexError as e:
                    print(level, n_vars, nudge, e)
                    raise e
                try:
                    new_Y = dit.joint_from_factors(new_X, YgivenX).marginal('Y').copy('linear')
                except InvalidNormalization as e:
                    print(nudge)
                    print('new_x = {}'.format(sum(new_X.pmf)), new_X.pmf)
                    raise e
                except ditException as e:
                    print(nudge)
                    old_X.make_dense()
                    new_X.make_dense()
                    print(level, n_vars, seed, i, old_X.pmf, new_X.pmf)
                    print(level, n_vars, seed, i,
                          "oldX has {} outcomes, newX has {} outcomes\nYgivenX has {} cond distributions,old_x has 0 outcomes at{}".format(
                              len(old_X), len(new_X), len(YgivenX), np.flatnonzero(old_X.pmf == 0)))
                    old_X.make_sparse()
                    raise e
                new_Y.make_dense()
                intervention_results[idx, j] = sum(
                    abs(new_Y.pmf - old_Y.pmf))  # np.linalg.norm(new_Y.pmf - old_Y.pmf, ord=1)
        means[i, :] = np.median(intervention_results, axis=1)
    print(level, n_vars, "done")
    return (level, n_vars), means
Example #9
0
def test_channel_capacity_rvnames():
    epsilon = .01
    pXY = BEC_joint(epsilon)
    pXY.set_rv_names('XY')
    pX, pYgX = pXY.condition_on('X')
    cc, pXopt = dit.algorithms.channel_capacity(pYgX, pX)

    # Verify channel capacity.
    np.testing.assert_allclose(cc, 1 - epsilon)

    # Verify maximizing distribution.
    assert_true(pX.is_approx_equal(pXopt))

    # Verify joint distribution at channel capacity.
    pXYopt = dit.joint_from_factors(pXopt, pYgX)
    assert_true(pXY.is_approx_equal(pXYopt))
Example #10
0
def BEC_joint(epsilon):
    """
    The joint distribution for the binary erase channel at channel capacity.

    Parameters
    ----------
    epsilon : float
        The noise level at which the input is erased.

    """
    pX = dit.Distribution(['0', '1'], [1 / 2, 1 / 2])
    pYgX0 = dit.Distribution(['0', '1', 'e'], [1 - epsilon, 0, epsilon])
    pYgX1 = dit.Distribution(['0', '1', 'e'], [0, 1 - epsilon, epsilon])
    pYgX = [pYgX0, pYgX1]
    pXY = dit.joint_from_factors(pX, pYgX, strict=False)
    return pXY
Example #11
0
def test_channel_capacity_rvnames():
    epsilon = 0.01
    pXY = BEC_joint(epsilon)
    pXY.set_rv_names('XY')
    pX, pYgX = pXY.condition_on('X')
    cc, pXopt = channel_capacity(pYgX, pX)

    # Verify channel capacity.
    assert np.allclose(cc, 1 - epsilon)

    # Verify maximizing distribution.
    assert pX.is_approx_equal(pXopt)

    # Verify joint distribution at channel capacity.
    pXYopt = joint_from_factors(pXopt, pYgX)
    assert pXY.is_approx_equal(pXYopt)
Example #12
0
def BEC_joint(epsilon):
    """
    The joint distribution for the binary erase channel at channel capacity.

    Parameters
    ----------
    epsilon : float
        The noise level at which the input is erased.

    """
    pX = Distribution(['0', '1'], [1/2, 1/2])
    pYgX0 = Distribution(['0', '1', 'e'], [1 - epsilon, 0, epsilon])
    pYgX1 = Distribution(['0', '1', 'e'], [0, 1 - epsilon, epsilon])
    pYgX = [pYgX0, pYgX1]
    pXY = joint_from_factors(pX, pYgX, strict=False)
    return pXY
Example #13
0
def do_max_individual_nudge(old_X, nudges, minimal_idx, from_local=False):
    mask = old_X._mask
    base = old_X.get_base()
    rvs = old_X.get_rv_names()
    outcomes = old_X.outcomes
    states = len(old_X.alphabet[0])

    non_minimal_rvs = rvs[:minimal_idx] + rvs[minimal_idx + 1:]
    Xother, Xi_given_Xother = old_X.condition_on(non_minimal_rvs)
    old_shape = len(old_X)
    old_Xis = [Xi.copy() for Xi in Xi_given_Xother]
    for nudge, Xi in zip(nudges, Xi_given_Xother):
        # if from_local:
        #    print("before_nudge", nudge, Xi)

        if base == 'linear':
            perform_nudge(Xi, nudge)
        else:
            log_nudge, sign = np.log(np.abs(nudge)), np.sign(nudge)
            perform_log_nudge(Xi, log_nudge, sign)
        # if from_local:
        #   print("after_nudge",Xi)
    new_X = dit.joint_from_factors(Xother, Xi_given_Xother).copy(base)
    new_X.make_dense()
    new_shape = len(new_X)
    x = new_X.pmf.reshape(-1, states)
    y = [np.all(r == -np.inf) for r in x]
    row_deleted = np.any(y)

    #if from_local and new_shape != old_shape or from_local and row_deleted:
    #    print("nudges:", nudges)
    #    print("old_X:", old_X.pmf.reshape(-1, states))
    #    print("new_X", new_X.pmf.reshape(-1, states))
    #    print("old Xis", np.vstack([oXi.pmf for oXi in old_Xis]))
    #    print("new Xis", np.vstack([nXi.pmf for nXi in Xi_given_Xother]))

    dct = {o: new_X[o] if o in new_X.outcomes else 0.0 for o in outcomes}
    #print(outcomes, dct)
    new_X = dit.Distribution(dct)
    new_X.set_rv_names(rvs)
    new_X._mask = mask
    return new_X
Example #14
0
def optim_experiment(inputs):
    level, n_vars, dists, interventions, seed = inputs
    np.random.seed(seed)
    n_states = 3

    nudges = [max_individual_nudge, max_local_nudge, max_synergistic_nudge,
              max_derkjanistic_nudge, max_global_nudge]
    means = np.zeros((dists, len(nudges)))
    for i in range(dists):
        XY = generate_distribution(n_vars + 1, n_states, level)  # +1 for the output variable
        old_Y = XY.marginal('Y').copy('linear')
        old_X, YgivenX = get_marginals(XY)
        # print(YgivenX[0].get_base())
        [Y.make_dense() for Y in YgivenX]
        oldest_X = old_X.copy()
        # print("YgX old", [Y.pmf for Y in YgivenX])

        intervention_results = np.zeros((len(nudges), interventions))
        for j in range(interventions):
            for idx, nudge in enumerate(nudges):

                new_X = nudge(old_X, YgivenX)
                try:
                    new_XY = dit.joint_from_factors(new_X, YgivenX)
                    new_Y = new_XY.marginal('Y').copy('linear')
                except dit.exceptions.ditException as e:
                    print(level, n_vars, nudge, e)
                    raise e
                new_Y.make_dense()
                # print(idx, "X", old_X.copy('linear').pmf, new_X.copy('linear').pmf)
                # print(idx, "XY", XY.copy('linear').pmf, new_XY.copy('linear').pmf)
                # print(idx, "Y", old_Y.pmf, new_Y.pmf)
                intervention_results[idx, j] = sum(abs(new_Y.pmf - old_Y.pmf))

        means[i, :] = np.median(intervention_results, axis=1)

    print(level, n_vars, "done")
    return (level, n_vars), means
Example #15
0
def test_joint_from_factors():
    d = dit.example_dists.Xor()
    for i in range(3):
        pX, pYgX = d.condition_on([i])
        pXY = dit.joint_from_factors(pX, pYgX)
        assert_true(pXY.is_approx_equal(d))
Example #16
0
def test_joint_from_factors():
    d = dit.example_dists.Xor()
    for i in range(3):
        pX, pYgX = d.condition_on([i])
        pXY = dit.joint_from_factors(pX, pYgX)
        assert pXY.is_approx_equal(d)
Example #17
0
def get_joint(X: dit.Distribution,
              YgX: List[dit.Distribution],
              base=np.e) -> dit.Distribution:
    return dit.joint_from_factors(X, YgX).copy(base=base)