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
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)
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)
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)
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))
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))
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)
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
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))
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
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)
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
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
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
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))
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)
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)