def max_local(input: dit.Distribution, conditional: np.ndarray, eps: float = 0.01): rvs = input.get_rv_names() sorted_rvs = np.argsort([ entropy(input.marginal([rv], rv_mode='indices').pmf) for rv in range(len(rvs)) ]) nudge_vectors = np.zeros( (input.outcome_length(), int(len(input) / 3), 3) ) # For each random variable we get (hopefully) a different nudge vector of len the input size max_impacts = np.zeros(input.outcome_length()) for rv in sorted_rvs: nudge_vectors[rv, :, :], max_impacts[rv], _ = max_individual( input, conditional, eps / len(sorted_rvs), rv) return nudge_vectors, max_impacts
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 max_individual_nudge(old_X: dit.Distribution, YgivenX: np.ndarray, eps: float = 0.01): if old_X.outcome_length() == 1: return max_global_nudge(old_X, YgivenX, eps) nudges, minimal_idx = max_nudge(old_X.copy('linear'), YgivenX, eps=eps, nudge_type='individual') # print("individual eps",sum([sum(abs(nudge)) for nudge in nudges]), eps, old_X.outcome_length()) return do_max_individual_nudge(old_X, nudges, minimal_idx)
def test_insert_join(): """ Test insert_join """ outcomes = ['00', '01', '10', '11'] pmf = [1/4]*4 d = Distribution(outcomes, pmf) assert_raises(IndexError, insert_join, d, 5, [[0], [1]]) for idx in range(d.outcome_length()): d2 = insert_join(d, idx, [[0], [1]]) m = d2.marginal([idx]) npt.assert_allclose(d2.pmf, m.pmf)
def test_insert_join(): """ Test insert_join """ outcomes = ['00', '01', '10', '11'] pmf = [1 / 4] * 4 d = Distribution(outcomes, pmf) with pytest.raises(IndexError): insert_join(d, 5, [[0], [1]]) for idx in range(d.outcome_length()): d2 = insert_join(d, idx, [[0], [1]]) m = d2.marginal([idx]) assert np.allclose(d2.pmf, m.pmf)
def max_local_nudge1(old_X: dit.Distribution, YgivenX: np.ndarray, eps: float = 0.01): if old_X.outcome_length() == 1: return max_global_nudge(old_X, YgivenX, eps) mask = old_X._mask base = old_X.get_base() new_X = old_X.copy(base=base) old_X.make_dense() outcomes = old_X.outcomes rvs = old_X.get_rv_names() individual_nudges, _ = max_nudge(old_X.copy('linear'), YgivenX, eps=eps, nudge_type='local') new_Xs = np.zeros((old_X.outcome_length(), len(old_X))) for i, nudges in enumerate(individual_nudges): tmp = do_max_individual_nudge(old_X, nudges, i) # print(i, tmp.pmf, old_X.pmf, new_Xs) new_Xs[i, :] = tmp.pmf - old_X.pmf nudge = new_Xs.sum(axis=0) nudge = eps * nudge / (abs(nudge).sum()) if base == 'linear': perform_nudge(new_X, nudge) else: log_nudge, sign = np.log(np.abs(nudge)), np.sign(nudge) perform_log_nudge(new_X, log_nudge, sign) 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 do_derkjanistic_nudge(input_dist: dit.Distribution, nudge_size:float): "Unoptimized derkjanistic nudge" rvs = input_dist.outcome_length() alphabet = input_dist.alphabet[0] new_distribution = input_dist.pmf for _ in range(len(new_distribution)): state_vectors = np.tile(np.random.choice(alphabet, rvs, replace=True), (4, 1)) x_i, x_j = np.random.choice(rvs, 2, replace=False) states_i = np.random.choice(alphabet, 2, replace=False) states_j = np.random.choice(alphabet, 2, replace=False) for i in range(2): for j in range(2): state_vectors[i * 2 + j, [x_i, x_j]] = states_i[i], states_j[j] state_strings = sorted([tuple(vector) for vector in state_vectors]) #print(input_dist.outcomes) state_indices = [i for i, sample in enumerate(input_dist.sample_space()) if sample in state_strings] selected_states = [{'label': label, 'index': index, 'prob': input_dist[label]} for label, index in zip(state_strings, state_indices)] random.shuffle(selected_states) #print(selected_states) if np.random.random() > 0.5: negs = (selected_states[0], selected_states[3]) poss = (selected_states[1], selected_states[2]) else: negs = (selected_states[1], selected_states[2]) poss = (selected_states[0], selected_states[3]) this_mutation_size = min(input_dist[negs[0]['label']], input_dist[negs[1]['label']], 1-input_dist[poss[0]['label']], 1-input_dist[poss[1]['label']], nudge_size) this_mutation_size = np.random.uniform(0, this_mutation_size) for neg in negs: new_distribution[neg['index']] -= this_mutation_size for pos in poss: new_distribution[pos['index']] += this_mutation_size if np.any(new_distribution < 0): print("something went wrong") print("negative states {}".format(negs)) print("positive_states {}".format(poss)) print("the mutation size {}".format(this_mutation_size)) print("the negative probs {}, {}".format(new_distribution[negs[0]["index"]], new_distribution[negs[1]["index"]])) print("the positive probs {}, {}".format(new_distribution[poss[0]["index"]], new_distribution[poss[1]["index"]])) print(new_distribution) raise ValueError() return new_distribution
def max_local_nudge2(old_X: dit.Distribution, YgivenX: np.ndarray, eps: float = 0.01): if old_X.outcome_length() == 1: return max_global_nudge(old_X, YgivenX, eps) mask = old_X._mask base = old_X.get_base() new_X = old_X.copy(base=base) old_X.make_dense() rvs = old_X.get_rv_names() sorted_rvs = np.argsort([ entropy(old_X.marginal([rv], rv_mode='indices').pmf) for rv in range(len(rvs)) ]) oldshape = len(old_X) outcomes = old_X.outcomes # print("before", new_X.pmf.shape) for i, rv in enumerate(sorted_rvs): nudges, _ = max_nudge(new_X.copy('linear'), YgivenX, eps=(eps / len(sorted_rvs)), nudge_type='individual', minimal_entropy_idx=rv) # print("local eps",sum([sum(abs(nudge)) for nudge in nudges]), eps, old_X.outcome_length()) new_X = do_max_individual_nudge(new_X, nudges, rv, True) # print("after {}".format(i), new_X.pmf.shape) new_X.make_dense() newshape = len(new_X) # if oldshape != newshape: # print(nudges) # print("after {} and making dense".format(i), new_X.pmf.shape) 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