Beispiel #1
0
    def test_kl_div(self):
        """Test a problem with kl_div.
        """
        import numpy as np
        import cvxpy as cp

        kK=50
        kSeed=10

        prng=np.random.RandomState(kSeed)
        #Generate a random reference distribution
        npSPriors=prng.uniform(0.0,1.0,(kK,1))
        npSPriors=npSPriors/sum(npSPriors)

        #Reference distribution
        p_refProb=cp.Parameter(kK,1,sign='positive')
        #Distribution to be estimated
        v_prob=cp.Variable(kK,1)
        objkl=0.0
        for k in xrange(kK):
            objkl += cp.kl_div(v_prob[k,0],p_refProb[k,0])

        constrs=[sum([v_prob[k,0] for k in xrange(kK)])==1]
        klprob=cp.Problem(cp.Minimize(objkl),constrs)
        p_refProb.value=npSPriors
        result = klprob.solve(solver=SCS, verbose=True)
        self.assertItemsAlmostEqual(v_prob.value, npSPriors)
Beispiel #2
0
def solver(r_b, eps = 0.1):
    pi_bn = cp.Variable(len(r_b))
    uniform = np.ones_like(r_b)/len(r_b)
    constraints = []
    constraints.append(pi_bn>=0)
    constraints.append(cp.sum(pi_bn) == 1)
    constraints.append(cp.kl_div(pi_bn, uniform)<=eps)
    obj = cp.Minimize([email protected](pi_bn))
    prob = cp.Problem(obj, constraints)
    prob.solve(cp.ECOS)
    return pi_bn.value.tolist()
Beispiel #3
0
    def test_mosek_exp(self):
        """
        Formulate the following exponential cone problem with cvxpy
            min   3 * x[0] + 2 * x[1] + x[2]
            s.t.  0.1 <= x[0] + x[1] + x[2] <= 1
                  x >= 0
                  x[0] >= x[1] * exp(x[2] / x[1])
        and solve with MOSEK and ECOS. Ensure that MOSEK and ECOS have the same
        primal and dual solutions.

        Note that the exponential cone constraint can be rewritten in terms of the
        relative entropy cone. The correspondence is as follows:
                x[0] >= x[1] * exp(x[2] / x[1])
            iff
                x[1] * log(x[1] / x[0]) + x[2] <= 0.
        """
        if cvx.MOSEK in cvx.installed_solvers():
            import mosek
            if hasattr(mosek.conetype, 'pexp'):
                # Formulate and solve the problem with CVXPY
                x = cvx.Variable(shape=(3, 1))
                constraints = [
                    sum(x) <= 1.0,
                    sum(x) >= 0.1, x >= 0.01,
                    cvx.kl_div(x[1], x[0]) + x[1] - x[0] + x[2] <= 0
                ]
                obj = cvx.Minimize(3 * x[0] + 2 * x[1] + x[0])
                prob = cvx.Problem(obj, constraints)
                prob.solve(solver=cvx.MOSEK)
                val_mosek = prob.value
                x_mosek = x.value.flatten().tolist()
                duals_mosek = [c.dual_value for c in constraints]
                prob.solve(solver=cvx.ECOS)
                val_ecos = prob.value
                x_ecos = x.value.flatten().tolist()
                duals_ecos = [c.dual_value for c in constraints]

                # verify results
                self.assertAlmostEqual(val_mosek, val_ecos)
                self.assertItemsAlmostEqual(x_mosek, x_ecos, places=4)
                self.assertEqual(len(duals_ecos), len(duals_mosek))
                for i in range(len(duals_mosek)):
                    if isinstance(duals_mosek[i], float):
                        self.assertAlmostEqual(duals_mosek[i],
                                               duals_ecos[i],
                                               places=4)
                    else:
                        self.assertItemsAlmostEqual(duals_mosek[i].tolist(),
                                                    duals_ecos[i].tolist(),
                                                    places=4)
            else:
                pass
Beispiel #4
0
def kl_inverse(q, c):
    '''Compute kl inverse using Relative Entropy Programming'''
    p_bernoulli = cvx.Variable(2)
    q_bernoulli = np.array([q, 1 - q])
    constraints = [
        c >= cvx.sum(cvx.kl_div(q_bernoulli, p_bernoulli)),
        0 <= p_bernoulli[0], p_bernoulli[0] <= 1,
        p_bernoulli[1] == 1.0 - p_bernoulli[0]
    ]
    prob = cvx.Problem(cvx.Maximize(p_bernoulli[0]), constraints)
    prob.solve(verbose=False, solver=cvx.ECOS)

    return p_bernoulli.value[0]
Beispiel #5
0
def lr_method(h):

    # parameters and equations
    o = 100
    p = 3
    u = 0.51
    ki = 10**(
        -2)  # increase the value of ki because the original value is too small
    B = 2 * 10**6
    Vu = 1.1
    N0 = 10**(-10)
    wi = np.array([1 if i % 2 == 1 else 1 for i in range(len(h))
                   ])  # default weights [1, 1.5, 1, 1.5, 1, 1.5, ...]

    # optimization variables
    tau_i = cvx.Variable(len(h))
    fi = cvx.Variable(len(h))
    ei = cvx.Variable(len(h))

    # optimization objective and constraints
    result = cvx.sum(-cvx.multiply(wi,fi)*10**6+cvx.multiply(wi,(cvx.kl_div(tau_i,(cvx.multiply(ei,h)+tau_i*N0)/N0)\
                     +tau_i-(cvx.multiply(ei,h)+tau_i*N0)/N0))*B/Vu/np.log(2))
    objective = cvx.Minimize(result)
    constraints = [
        tau_i >= 0.0,
        cvx.sum(tau_i) <= 1.0, ei >= 0, fi >= 0,
        ei + cvx.multiply(ki, fi**3) <= u * p * h * (1 - cvx.sum(tau_i))
    ]
    prob = cvx.Problem(objective, constraints)
    rewards = prob.solve(solver=cvx.MOSEK)  # solve the problem by MOSEK

    local_rate = wi * (fi.value) * 10**6
    offloading_rate = wi * B / Vu * tau_i.value * np.log2(1 + ei.value * h /
                                                          (N0 * tau_i.value))
    mode = []
    for i in range(len(h)):
        if local_rate[i] < offloading_rate[i]:
            mode.append(1)
        else:
            mode.append(0)

    # compute the sum_rate with binary offloading
    E = u * p * h * (1 - np.sum(tau_i.value))
    sum_rate = 0
    for i in range(len(mode)):
        if mode[i] == 1:
            sum_rate += wi[i] * B / Vu * tau_i.value[i] * np.log2(
                1 + E[i] * h[i] / (N0 * tau_i.value[i]))
        else:
            sum_rate += wi[i] * (E[i] / ki)**(1 / 3) * 10**6
    return sum_rate, mode
Beispiel #6
0
def kl_inverse(q, c):
    
    p_bernoulli = cvx.Variable(2)

    q_bernoulli = np.array([q,1-q])

    constraints = [c >= cvx.sum(cvx.kl_div(q_bernoulli,p_bernoulli)), 0 <= p_bernoulli[0], p_bernoulli[0] <= 1, p_bernoulli[1] == 1.0-p_bernoulli[0]]

    prob = cvx.Problem(cvx.Maximize(p_bernoulli[0]), constraints)

    # Solve problem
    opt = prob.solve(verbose=False, solver=solver=cvx.SCS) # solver=cvx.ECOS
    
    return p_bernoulli.value[0] 
Beispiel #7
0
def optimal_power(n, a_val, b_val, P_tot: float = 1.0, W_tot: float = 1.0):
    '''
Boyd and Vandenberghe, Convex Optimization, exercise 4.62 page 210
Optimal power and bandwidth allocation in a Gaussian broadcast channel.

We consider a communication system in which a central node transmits messages
to n receivers. Each receiver channel is characterized by its (transmit) power
level Pi ≥ 0 and its bandwidth Wi ≥ 0. The power and bandwidth of a receiver
channel determine its bit rate Ri (the rate at which information can be sent)
via
   Ri=αiWi log(1 + βiPi/Wi),
where αi and βi are known positive constants. For Wi=0, we take Ri=0 (which
is what you get if you take the limit as Wi → 0).  The powers must satisfy a
total power constraint, which has the form
P1 + · · · + Pn = Ptot,
where Ptot > 0 is a given total power available to allocate among the channels.
Similarly, the bandwidths must satisfy
W1 + · · · +Wn = Wtot,
where Wtot > 0 is the (given) total available bandwidth. The optimization
variables in this problem are the powers and bandwidths, i.e.,
P1, . . . , Pn, W1, . . . ,Wn.
The objective is to maximize the total utility, sum(ui(Ri),i=1..n)
where ui: R → R is the utility function associated with the ith receiver.
  '''
    # Input parameters: alpha and beta are constants from R_i equation
    n = len(a_val)
    if n != len(b_val):
        print('alpha and beta vectors must have same length!')
        return 'failed', np.nan, np.nan, np.nan
    P = cvx.Variable(n)
    W = cvx.Variable(n)
    alpha = cvx.Parameter(n)
    beta = cvx.Parameter(n)
    alpha.value = np.array(a_val)
    beta.value = np.array(b_val)
    # This function will be used as the objective so must be DCP; i.e. element-wise multiplication must occur inside kl_div, not outside otherwise the solver does not know if it is DCP...
    R=cvx.kl_div(cvx.multiply(alpha, W),
                 cvx.multiply(alpha, W + cvx.multiply(beta, P))) - \
      cvx.multiply(alpha, cvx.multiply(beta, P))
    objective = cvx.Minimize(cvx.sum(R))
    constraints = [
        P >= 0.0, W >= 0.0,
        cvx.sum(P) - P_tot == 0.0,
        cvx.sum(W) - W_tot == 0.0
    ]
    prob = cvx.Problem(objective, constraints)
    prob.solve()
    return prob.status, -prob.value, P.value, W.value
Beispiel #8
0
def minimum_kl(p, Theta):
    n = len(p)
    q = cvxpy.Variable(shape=n)
    lp = cvxpy.Parameter(shape=n)
    pi = cvxpy.Parameter(shape=n)
    lp.value = np.log(p)
    pi.value = compute_beta(args.alpha, args.beta, Theta)
    constraints = [q >= 0.0, cvxpy.sum(q) == 1.0]
    R = cvxpy.kl_div(q, pi) - cvxpy.multiply(q, lp)
    objective = cvxpy.Minimize(cvxpy.sum(R))
    prob = cvxpy.Problem(objective, constraints)
    try:
        prob.solve()
    except:
        prob.solve(solver="CVXOPT")
    return np.abs(q.value)
def optimal_power(n, a_val, b_val, P_tot=1.0, W_tot=1.0):
  '''
Boyd and Vandenberghe, Convex Optimization, exercise 4.62 page 210
Optimal power and bandwidth allocation in a Gaussian broadcast channel.

We consider a communication system in which a central node transmits messages
to n receivers. Each receiver channel is characterized by its (transmit) power
level Pi ≥ 0 and its bandwidth Wi ≥ 0. The power and bandwidth of a receiver
channel determine its bit rate Ri (the rate at which information can be sent)
via
   Ri=αiWi log(1 + βiPi/Wi),
where αi and βi are known positive constants. For Wi=0, we take Ri=0 (which
is what you get if you take the limit as Wi → 0).  The powers must satisfy a
total power constraint, which has the form
P1 + · · · + Pn = Ptot,
where Ptot > 0 is a given total power available to allocate among the channels.
Similarly, the bandwidths must satisfy
W1 + · · · +Wn = Wtot,
where Wtot > 0 is the (given) total available bandwidth. The optimization
variables in this problem are the powers and bandwidths, i.e.,
P1, . . . , Pn, W1, . . . ,Wn.
The objective is to maximize the total utility, sum(ui(Ri),i=1..n)
where ui: R → R is the utility function associated with the ith receiver.
  '''
  # Input parameters: alpha and beta are constants from R_i equation
  n=len(a_val)
  if n!=len(b_val):
    print('alpha and beta vectors must have same length!')
    return 'failed',np.nan,np.nan,np.nan
  P=cvx.Variable(n)
  W=cvx.Variable(n)
  alpha=cvx.Parameter(n)
  beta =cvx.Parameter(n)
  alpha.value=np.array(a_val)
  beta.value =np.array(b_val)
  # This function will be used as the objective so must be DCP; i.e. element-wise multiplication must occur inside kl_div, not outside otherwise the solver does not know if it is DCP...
  R=cvx.kl_div(cvx.mul_elemwise(alpha, W),
               cvx.mul_elemwise(alpha, W + cvx.mul_elemwise(beta, P))) - \
    cvx.mul_elemwise(alpha, cvx.mul_elemwise(beta, P))
  objective=cvx.Minimize(cvx.sum_entries(R))
  constraints=[P>=0.0,
               W>=0.0,
               cvx.sum_entries(P)-P_tot==0.0,
               cvx.sum_entries(W)-W_tot==0.0]
  prob=cvx.Problem(objective, constraints)
  prob.solve()
  return prob.status,-prob.value,P.value,W.value
Beispiel #10
0
 def minimum_kl(self, x):
     p = self.likelihood_estimator(x)
     n = len(p)
     q = cvxpy.Variable(shape=n)
     lp = cvxpy.Parameter(shape=n)
     pi = cvxpy.Parameter(shape=n)
     lp.value = np.log(p + 1e-8)
     pi.value = self.priors
     constraints = [q >= 0.0, cvxpy.sum(q) == 1.0]
     R = cvxpy.kl_div(q, pi) + q - pi - cvxpy.multiply(q, lp)
     objective = cvxpy.Minimize(cvxpy.sum(R))
     prob = cvxpy.Problem(objective, constraints)
     try:
         prob.solve()
     except:
         prob.solve(solver="CVXOPT")
     return q.value
Beispiel #11
0
 def test_expcone_2(self) -> None:
     x = cp.Variable(shape=(3,))
     tempcons = [cp.sum(x) <= 1.0, cp.sum(x) >= 0.1, x >= 0.01,
                 cp.kl_div(x[1], x[0]) + x[1] - x[0] + x[2] <= 0]
     sigma = cp.suppfunc(x, tempcons)
     y = cp.Variable(shape=(3,))
     a = np.array([-3, -2, -1])  # this is negative of objective in mosek_conif.py example
     expr = -sigma(y)
     objective = cp.Maximize(expr)
     cons = [y == a]
     prob = cp.Problem(objective, cons)
     prob.solve(solver='ECOS')
     # Check for expected objective value
     epi_actual = prob.value
     direct_actual = expr.value
     expect = 0.235348211
     self.assertLessEqual(abs(epi_actual - expect), 1e-6)
     self.assertLessEqual(abs(direct_actual - expect), 1e-6)
Beispiel #12
0
def relative_c_age(s, i):
    constraints = list()
    idx_set = np.arange(s.m) != i
    # variable definitions
    c_var = cvxpy.Variable(shape=(s.m, 1),
                           name='c^{(' + str(i) + '})_' + str(s))
    nu_var = cvxpy.Variable(shape=(s.m - 1, 1),
                            name='nu^{(' + str(i) + '})_' + str(s),
                            nonneg=True)
    # variable non-negativity constraints
    constraints.append(c_var[idx_set] >= 0)
    # main constraints
    constraints.append(
        (s.alpha[idx_set, :] - s.alpha[i, :]).T *
        nu_var == np.zeros(shape=(s.n, 1)))  # convex cover constraint
    kl_expr1 = cvxpy.kl_div(nu_var, np.exp(1) * c_var[idx_set])
    kl_expr2 = nu_var - np.exp(1) * c_var[idx_set]
    rel_ent = kl_expr1 + kl_expr2
    constraints.append(
        cvxpy.sum(rel_ent) - c_var[i] <= 0)  # relative entropy constraint
    return c_var, nu_var, constraints
Beispiel #13
0
def kl_inverse_r(c, q, params):  #right kl inverse
    # KL(q||p) <= c
    # KLinv(c||p) = q
    # solve: sup  q
    #       s.t.  KL(q||p) <= c
    p_bernoulli = cvx.Variable(2)

    q_bernoulli = np.array([q, 1 - q])

    constraints = [
        c >= cvx.sum(cvx.kl_div(p_bernoulli, q_bernoulli)),
        0 <= p_bernoulli[0], p_bernoulli[0] <= 1,
        p_bernoulli[1] == 1.0 - p_bernoulli[0]
    ]

    prob = cvx.Problem(cvx.Maximize(p_bernoulli[0]), constraints)

    # Solve problem
    opt = prob.solve(verbose=params['verbose'], solver=params['solver'])

    return p_bernoulli.value[0]
Beispiel #14
0
def FTRL(T, MAB, eta=10, alg='exp_3'):

    K = len(MAB)
    S = np.zeros((K, ))
    losses = np.zeros((K, ))
    rewards = np.zeros((T, ))
    draws = 0 * rewards
    arms = np.linspace(0, K - 1, K, dtype='int')

    for t in trange(T):
        x = cp.Variable(K, pos=True)
        temp_1 = cp.Constant(value=np.ones((K, )))
        temp_2 = cp.Constant(value=losses)
        constraints = [cp.sum(cp.multiply(temp_1, x)) == 1]
        if alg == 'log_barrier':
            obj = cp.Minimize(
                cp.sum(cp.multiply(temp_2, x)) - 1 / eta * cp.sum(cp.log(x)))
        elif alg == 'inf':
            obj = cp.Minimize(
                cp.sum(cp.multiply(temp_2, x)) - 2 / eta * cp.sum(cp.sqrt(x)))
        else:
            obj = cp.Minimize(
                cp.sum(cp.multiply(temp_2, x)) + 1 / eta *
                (cp.sum(cp.kl_div(x, temp_1)) - K))
        pb = cp.Problem(obj, constraints)
        try:
            pb.solve()
            P = x.value
        except:
            P = np.ones((K, )) / K
        # print('Probability distribution:', P)
        if not np.sum(P) == 1:
            P = P / np.sum(P)
        action = np.random.choice(arms, p=P)
        X = 1 * MAB[action].sample().squeeze()
        S[action] = S[action] + X / P[action]
        losses[action] = losses[action] + (-X) / P[action]
        rewards[t] = X
        draws[t] = action
    return rewards, draws
    def CVXOPT_programming(self, M, S, K, costs, C):
        failed = 0
        if not all(i >= 0 for i in costs):
            return np.zeros(S), np.zeros(M), 0, 1
        # Define QP parameters (directly)
        G1 = C / self.parameters['tau_inv']
        h1 = costs

        G2 = -np.identity(M)
        h2 = np.zeros(M)
        G = np.concatenate((G1, G2), axis=0)
        h = np.concatenate((h1, h2), axis=None)

        R = cvx.Variable(shape=(M, 1))
        K = K.reshape((M, 1)) * self.parameters['tau_inv']
        h = h.reshape((M + S, 1))

        # Construct the QP, invoke solver
        obj = cvx.Minimize(cvx.sum(cvx.kl_div(K + 1e-10, R + 1e-10)))
        constraints = [G * R <= h]
        prob = cvx.Problem(obj, constraints)
        prob.solver_stats
        try:
            prob.solve(solver=cvx.ECOS,
                       abstol=1e-12,
                       reltol=1e-12,
                       warm_start=True,
                       verbose=False,
                       max_iters=300)
        except:
            N = np.zeros(S)
            R = np.zeros(M)
            return R, N, 0, 1
        # Extract optimal value and solution
        N = (constraints[0].dual_value)[0:S]
        R = R.value / self.parameters['tau_inv']
        R = R.reshape(M)
        N = N.reshape(S)
        return R, N, prob.value, failed
    def test_difference_kl_div_rel_entr(self) -> None:
        """A test showing the difference between kl_div and rel_entr
        """
        x = cvx.Variable()
        y = cvx.Variable()

        kl_div_prob = cvx.Problem(cvx.Minimize(cvx.kl_div(x, y)),
                                  constraints=[x + y <= 1])
        kl_div_prob.solve(solver=cvx.ECOS)
        self.assertItemsAlmostEqual(x.value, y.value)
        self.assertItemsAlmostEqual(kl_div_prob.value, 0)

        rel_entr_prob = cvx.Problem(cvx.Minimize(cvx.rel_entr(x, y)),
                                    constraints=[x + y <= 1])
        rel_entr_prob.solve(solver=cvx.ECOS)
        """
        Reference solution computed by passing the following command to Wolfram Alpha:
        minimize x*log(x/y) subject to {x + y <= 1, 0 <= x, 0 <= y}
        """
        self.assertItemsAlmostEqual(x.value, 0.2178117, places=4)
        self.assertItemsAlmostEqual(y.value, 0.7821882, places=4)
        self.assertItemsAlmostEqual(rel_entr_prob.value, -0.278464)
Beispiel #17
0
def limited_information_privacy_approximate_upper_lb(P0: np.ndarray,
                                                     P1: np.ndarray):
    """ Computes a pair of policies that upper bounds the privacy lower bound
    Parameters
    ----------
    P0, P1 : np.ndarray
        Numpy matrices containing the transition probabilities for models M0 and M1
        Each matrix should have dimensions |actions|x|states|x|states|
    Returns
    -------
    L : float
        Upper bound of I_L
    pi0, pi1 : np.ndarray
        The computed policies
    """
    P0, P1 = sanity_check_probabilities(P0, P1)
    na = P0.shape[0]
    ns = P1.shape[1]
    gamma = cp.Variable(1, nonneg=True)
    pi0 = cp.Variable((ns, na), nonneg=True)
    pi1 = cp.Variable((ns, na), nonneg=True)

    constraint = []
    constraint_pi0 = [cp.sum(pi0[s, :]) == 1 for s in range(ns)]
    constraint_pi1 = [cp.sum(pi1[s, :]) == 1 for s in range(ns)]
    for s in range(ns):
        Ds = 0.
        for y in range(ns):
            P1_pi1 = P1[:, s, y] @ pi1[s, :]
            P0_pi0 = P0[:, s, y] @ pi0[s, :]
            Ds += cp.kl_div(P1_pi1, P0_pi0) + P1_pi1 - P0_pi0
        constraint += [Ds <= gamma]

    constraints = constraint + constraint_pi0 + constraint_pi1
    problem = cp.Problem(cp.Minimize(gamma), constraints)

    result = problem.solve()
    return result, pi0.value, pi1.value
Beispiel #18
0
    def get_dS(W, p):
        """ Rate of Shannon entropy change, for rate matrix W and distribution p """

        """ We rewrite -sum_{i,j} p_i W_ji ln p_j as the "KL-like" expression
               1/tau sum_{i,j} p_i T_ji ln (p_i T_ji/p_j T_ji)
        where tau = -min_i W_ii is the fastest time scale in R and
        T_ji = delta_{ji} + tau W_ji is a conditional probability distribuiton. This 
        lets us indicate to cvxpy that -sum_{i,j} p_i W_ji ln p_j is convex in p.
        """

        tau  = -1/np.min(np.diag(W))
        T    = np.eye(n) + tau*W
        assert(np.all(T>=0))

        dS = 0.
        for i in range(n):
            for j in range(n):
                if i == j: 
                    continue
                if np.isclose(T[i,j],0):
                    continue
                dS += cp.kl_div( T[i,j] * p[j], T[i,j] * p[i]) + T[i,j] * p[j] - T[i,j] * p[i]
        return dS / tau
    def test_kl_div(self) -> None:
        """Test a problem with kl_div.
        """
        kK = 50
        kSeed = 10

        prng = np.random.RandomState(kSeed)
        # Generate a random reference distribution
        npSPriors = prng.uniform(0.0, 1.0, kK)
        npSPriors = npSPriors / sum(npSPriors)

        # Reference distribution
        p_refProb = cvx.Parameter(kK, nonneg=True)
        # Distribution to be estimated
        v_prob = cvx.Variable(kK)
        objkl = cvx.sum(cvx.kl_div(v_prob, p_refProb))

        constrs = [cvx.sum(v_prob) == 1]
        klprob = cvx.Problem(cvx.Minimize(objkl), constrs)
        p_refProb.value = npSPriors
        klprob.solve(solver=cvx.SCS, verbose=True)
        self.assertItemsAlmostEqual(v_prob.value, npSPriors, places=3)
        klprob.solve(solver=cvx.ECOS, verbose=True)
        self.assertItemsAlmostEqual(v_prob.value, npSPriors)
Beispiel #20
0
    def test_kl_div(self):
        """Test a problem with kl_div.
        """
        kK = 50
        kSeed = 10

        prng = np.random.RandomState(kSeed)
        # Generate a random reference distribution
        npSPriors = prng.uniform(0.0, 1.0, (kK, 1))
        npSPriors = npSPriors/sum(npSPriors)

        # Reference distribution
        p_refProb = cp.Parameter((kK, 1), nonneg=True)
        # Distribution to be estimated
        v_prob = cp.Variable((kK, 1))
        objkl = 0.0
        for k in range(kK):
            objkl += cp.kl_div(v_prob[k, 0], p_refProb[k, 0])

        constrs = [sum(v_prob[k, 0] for k in range(kK)) == 1]
        klprob = cp.Problem(cp.Minimize(objkl), constrs)
        p_refProb.value = npSPriors
        klprob.solve(solver=cp.SCS)
        self.assertItemsAlmostEqual(v_prob.value, npSPriors)
Beispiel #21
0
def relative_c_sage_star(s, v):
    """
    Given the Signomial s and a CVXPY variable "v", return a list of CVXPY Constraint objects such
    that v is a conic dual variable to the constraint "s.c \in C_{SAGE}(s.alpha)".

    :param s: a Signomial object
    :param v: a CVXPY Variable with v.size == s.m.
    :return a list of CVXPY Constraint objects.

    Remark 1: The CVXPY function kl_div operates in a way that differs from the relative entropy function as described
    in the literature on SAGE relaxations. Refer to the CVXPY documentation if our usage seems odd.

    Remark 2: This implementation is vectorized to minimize the length of the list "constraints". By doing this we
    significantly speed up the process of CVXPY converting our problem to its internal standard form.
    """
    alpha, c = s.alpha_c_arrays()
    if s.m <= 2:
        return [v >= 0]
    non_constants = [
        i for i, c_i in enumerate(c) if not isinstance(c_i, __NUMERIC_TYPES__)
    ]
    N_I = [i for i, c_i in enumerate(c) if (i in non_constants) or c_i < 0]
    Nc_I = [i for i, c_i in enumerate(c) if (i in non_constants) or c_i > 0]
    # variable definitions
    mu = cvxpy.Variable(shape=(len(N_I), s.n), name=('mu_' + str(v.id)))
    # constraints
    constraints = []
    for i, ii in enumerate(N_I):
        # i = the index used for "mu", ii = index used for alpha and v
        j_neq_ii = [j for j in Nc_I if j != ii]
        expr1 = v[ii] * np.ones((len(j_neq_ii), 1))
        expr2 = cvxpy.kl_div(expr1, v[j_neq_ii]) + expr1 - v[j_neq_ii]
        expr3 = (alpha[ii, :] - alpha[j_neq_ii, :]) * mu[i, :].T
        constraints.append(expr2 <= cvxpy.reshape(expr3, (len(j_neq_ii), 1)))
    constraints.append(v[list(set(N_I + Nc_I))] >= 0)
    return constraints
Beispiel #22
0
def OptimizeWell(well_info,
                 supply='external',
                 tol=1e-7,
                 shift_size=1,
                 eps=1e-20,
                 alpha=0.5,
                 R0t_0=10,
                 verbose=False,
                 max_iters=1000):
    """
    Uses convex optimization to find the steady state of the ecological dynamics.
    """

    #UNPACK INPUT
    y0 = well_info['y0'].copy()
    params_comp = well_info['params'].copy()
    N = y0[:params_comp['S']]
    R = y0[params_comp['S']:]

    #COMPRESS PARAMETERS TO GET RID OF EXTINCT SPECIES
    not_extinct_consumers = N > 0
    if supply == 'external':
        not_extinct_resources = np.ones(len(R), dtype=bool)
    else:
        not_extinct_resources = R > 0
    params_comp['c'] = params_comp['c'][not_extinct_consumers, :]
    params_comp['c'] = params_comp['c'][:, not_extinct_resources]
    params_comp['D'] = params_comp['D'][not_extinct_resources, :]
    params_comp['D'] = params_comp['D'][:, not_extinct_resources]
    for name in ['m', 'g', 'K']:
        if name in params_comp.keys():
            if type(params_comp[name]) == np.ndarray:
                assert len(
                    params_comp[name]) == len(N), 'Invalid length for ' + name
                params_comp[name] = params_comp[name][not_extinct_consumers]
    for name in ['l', 'w', 'r', 'tau', 'R0']:
        if name in params_comp.keys():
            if type(params_comp[name]) == np.ndarray:
                assert len(
                    params_comp[name]) == len(R), 'Invalid length for ' + name
                params_comp[name] = params_comp[name][not_extinct_resources]
    S = len(params_comp['c'])
    M = len(params_comp['c'].T)

    failed = 0
    if params_comp['l'] != 0:
        assert supply == 'external', 'Replenishment must be external for crossfeeding dynamics.'

        #Make Q matrix and effective weight vector
        w_mat = np.kron(np.ones((M, 1)), np.ones((1, M)) * params_comp['w'])
        Q = np.eye(M) - params_comp['l'] * params_comp['D'] * w_mat / (w_mat.T)
        Qinv = np.linalg.inv(Q)
        Qinv_aa = np.diag(Qinv)
        w = Qinv_aa * (
            1 - params_comp['l']) * params_comp['w'] / params_comp['tau']
        Qinv = Qinv - np.diag(Qinv_aa)

        #Construct variables for optimizer
        G = params_comp['c'] * params_comp['w'] * (
            1 -
            params_comp['l']) / w  #Divide by w, because we will multiply by wR
        if isinstance(params_comp['m'], np.ndarray):
            h = params_comp['m'].reshape((S, 1))
        else:
            h = np.ones((S, 1)) * params_comp['m']

        #Initialize effective resource concentrations
        R0t = R0t_0 * np.ones(M)

        #Set up the loop
        Rf = np.inf
        Rf_old = 0

        k = 0
        ncyc = 0
        Delta = 1
        Delta_old = 1
        while np.linalg.norm(Rf_old - Rf) > tol and k < max_iters:
            try:
                start_time = time.time()

                wR = cvx.Variable(shape=(M, 1))  #weighted resources

                #Need to multiply by w to get properly weighted KL divergence
                R0t = np.sqrt(R0t**2 + eps)
                wR0 = (R0t * w).reshape((M, 1))

                #Solve
                obj = cvx.Minimize(cvx.sum(cvx.kl_div(wR0, wR)))
                constraints = [G * wR <= h, wR >= 0]
                prob = cvx.Problem(obj, constraints)
                prob.solver_stats
                prob.solve(solver=cvx.ECOS,
                           abstol=1e-8,
                           reltol=1e-8,
                           warm_start=True,
                           verbose=False,
                           max_iters=5000)

                #Record the results
                Rf_old = Rf
                Nf = constraints[0].dual_value[0:S].reshape(S)
                Rf = wR.value.reshape(M) / w

                #Update the effective resource concentrations
                R0t_new = params_comp['R0'] + Qinv.dot(
                    (params_comp['R0'] - Rf) /
                    params_comp['tau']) * (params_comp['tau'] / Qinv_aa)
                Delta_R0t = R0t_new - R0t
                R0t = R0t + alpha * Delta_R0t

                Delta_old = Delta
                Delta = np.linalg.norm(Rf_old - Rf)
                if verbose:
                    print('Iteration: ' + str(k))
                    print('Delta: ' + str(Delta))
                    print('---------------- ' +
                          str(time.time() - start_time)[:4] +
                          ' s ----------------')
            except:
                #If optimization fails, try new R0t
                shift = shift_size * np.random.randn(M)
                R0t = np.abs(R0t + shift)

                if verbose:
                    print('Added ' + str(shift_size) + ' times random numbers')
            k += 1
            #Check for limit cycle
            if np.isfinite(Delta) and Delta > tol and np.abs(
                    Delta - Delta_old) < 0.1 * tol:
                ncyc += 1
            if ncyc > 10:
                print('Limit cycle detected')
                k = max_iters

        if k == max_iters:
            failed = 1
        else:
            if verbose:
                print('success')

    elif params_comp['l'] == 0:
        if supply == 'external':
            G = params_comp['c'] * params_comp[
                'tau']  #Multiply by tau, because wR has tau in the denominator
            if isinstance(params_comp['m'], np.ndarray):
                h = params_comp['m'].reshape((S, 1))
            else:
                h = np.ones((S, 1)) * params_comp['m']

            wR = cvx.Variable(shape=(M, 1))  #weighted resources

            #Need to multiply by w to get properly weighted KL divergence
            wR0 = (params_comp['R0'] * params_comp['w'] * np.ones(M) /
                   params_comp['tau']).reshape((M, 1))

            #Solve
            obj = cvx.Minimize(cvx.sum(cvx.kl_div(wR0, wR)))
            constraints = [G * wR <= h]
            prob = cvx.Problem(obj, constraints)
            prob.solver_stats
            prob.solve(solver=cvx.ECOS,
                       abstol=1e-8,
                       reltol=1e-8,
                       warm_start=True,
                       verbose=False,
                       max_iters=5000)

            #Record the results
            Nf = constraints[0].dual_value[0:S].reshape(S)
            Rf = wR.value.reshape(M) * params_comp['tau'] / params_comp['w']

        elif supply == 'self-renewing':
            #Format constants and variables
            if isinstance(params_comp['m'], np.ndarray):
                h = params_comp['m']
            else:
                h = np.ones(S) * params_comp['m']
            if isinstance(params_comp['w'], np.ndarray):
                w = params_comp['w']
            else:
                w = np.ones(M) * params_comp['w']
            if isinstance(params_comp['r'], np.ndarray):
                r = params_comp['r']
            else:
                r = np.ones(M) * params_comp['r']
            R0 = params_comp['R0']
            R_opt = cvx.Variable(M)

            #Make constraints
            G = params_comp['c'] * params_comp['w']
            G = np.vstack((G, -np.eye(M)))
            h = np.hstack((h, np.zeros(M)))

            #Solve
            obj = cvx.Minimize(
                (1 / 2) * cvx.quad_form(R0 - R_opt, np.diag(w * r)))
            constraints = [G @ R_opt <= h]
            prob = cvx.Problem(obj, constraints)
            prob.solve(solver=cvx.ECOS,
                       abstol=1e-9,
                       feastol=1e-7,
                       abstol_inacc=1e-5,
                       feastol_inacc=1e-5,
                       max_iters=5000)

            #Record the results
            Nf = constraints[0].dual_value[:S]
            Rf = R_opt.value
        elif supply == 'predator':
            #Format constants and variables
            if isinstance(params_comp['m'], np.ndarray):
                h = params_comp['m']
            else:
                h = np.ones(S) * params_comp['m']
            if isinstance(params_comp['w'], np.ndarray):
                w = params_comp['w']
            else:
                w = np.ones(M) * params_comp['w']
            r = params_comp['r']
            u = params_comp['u']
            R0 = params_comp['R0']
            R_opt = cvx.Variable(M)

            #Make constraints
            G = params_comp['c'] * params_comp['w']
            G = np.vstack((G, -np.eye(M)))
            h = np.hstack((h, np.zeros(M)))

            #Solve
            obj = cvx.Minimize((1 / 2) *
                               cvx.quad_form(R0 - R_opt, np.diag(w * r)) +
                               u.T @ R_opt)
            constraints = [G @ R_opt <= h]
            prob = cvx.Problem(obj, constraints)
            prob.solve(solver=cvx.ECOS,
                       abstol=1e-9,
                       feastol=1e-7,
                       abstol_inacc=1e-5,
                       feastol_inacc=1e-5,
                       max_iters=5000)

            #Record the results
            Nf = constraints[0].dual_value[:S]
            Rf = R_opt.value
        else:
            print('supply must be external or self-renewing')
            failed = True

    if not failed:
        N_new = np.zeros(len(N))
        R_new = np.zeros(len(R))
        N_new[np.where(not_extinct_consumers)[0]] = Nf
        R_new[np.where(not_extinct_resources)[0]] = Rf
    else:
        N_new = np.nan * N
        R_new = np.nan * R
        if verbose:
            print('Optimization Failed.')

    return np.hstack((N_new, R_new))
Beispiel #23
0
 prox("NORM_2", lambda: cp.norm(X, "fro")),
 prox("NORM_2", lambda: cp.norm2(x)),
 prox("NORM_NUCLEAR", lambda: cp.norm(X, "nuc")),
 prox("SECOND_ORDER_CONE", None, C_soc_scaled),
 prox("SECOND_ORDER_CONE", None, C_soc_scaled_translated),
 prox("SECOND_ORDER_CONE", None, C_soc_translated),
 prox("SECOND_ORDER_CONE", None, lambda: [cp.norm(X, "fro") <= t]),
 prox("SECOND_ORDER_CONE", None, lambda: [cp.norm2(x) <= t]),
 prox("SEMIDEFINITE", None, lambda: [X >> 0]),
 prox("SUM_DEADZONE", f_dead_zone),
 prox("SUM_EXP", lambda: cp.sum_entries(cp.exp(x))),
 prox("SUM_HINGE", f_hinge),
 prox("SUM_HINGE", lambda: cp.sum_entries(cp.max_elemwise(1-x, 0))),
 prox("SUM_HINGE", lambda: cp.sum_entries(cp.max_elemwise(1-x, 0))),
 prox("SUM_INV_POS", lambda: cp.sum_entries(cp.inv_pos(x))),
 prox("SUM_KL_DIV", lambda: cp.sum_entries(cp.kl_div(p1,q1))),
 prox("SUM_LARGEST", lambda: cp.sum_largest(x, 4)),
 prox("SUM_LOGISTIC", lambda: cp.sum_entries(cp.logistic(x))),
 prox("SUM_NEG_ENTR", lambda: cp.sum_entries(-cp.entr(x))),
 prox("SUM_NEG_LOG", lambda: cp.sum_entries(-cp.log(x))),
 prox("SUM_QUANTILE", f_quantile),
 prox("SUM_QUANTILE", f_quantile_elemwise),
 prox("SUM_SQUARE", f_least_squares_matrix),
 prox("SUM_SQUARE", lambda: f_least_squares(20)),
 prox("SUM_SQUARE", lambda: f_least_squares(5)),
 prox("SUM_SQUARE", f_quad_form),
 prox("TOTAL_VARIATION_1D", lambda: cp.tv(x)),
 prox("ZERO", None, C_linear_equality),
 prox("ZERO", None, C_linear_equality_matrix_lhs),
 prox("ZERO", None, C_linear_equality_matrix_rhs),
 prox("ZERO", None, C_linear_equality_multivariate),
	def CVXOPT_crossfeeding(self, S, M, K, C, D, e, costs,tol=1e-7,shift_size=1,eps=1e-20,
                 alpha=0.5,R0t_0=10,verbose=False,max_iters=1000):
	        Q = np.eye(M) - (1-e)*D
	        Qinv = np.linalg.inv(Q)
	        Qinv_aa = np.diag(Qinv)
	        w = Qinv_aa*e
	        Qinv = Qinv - np.diag(Qinv_aa)
	        #Construct variables for optimizer
	        G = C*e/w
	        h = costs.reshape((S,1))
	        #Set up the loop
	        Rf = np.inf
	        Rf_old = 0
	        k=0
	        ncyc=0
	        Delta = 1
	        Delta_old=1
	        failed = 0
	        R0t=K
	        while np.linalg.norm(Rf_old - Rf) > tol and k < max_iters:
	            try:
	                start_time = time.time()
	        
	                wR = cvx.Variable(shape=(M,1)) #weighted resources
	        
	                #Need to multiply by w to get properly weighted KL divergence
	                R0t = np.sqrt(R0t**2+eps)
	                wR0 = (R0t*w).reshape((M,1))

	                #Solve
	                obj = cvx.Minimize(cvx.sum(cvx.kl_div(wR0, wR)))
	                constraints = [G*wR <= h, wR >= 0]
	                prob = cvx.Problem(obj, constraints)
	                prob.solver_stats
	                prob.solve(solver=cvx.ECOS,abstol=0.1*tol,reltol=0.1*tol,warm_start=True,verbose=False,max_iters=200)

	                #Record the results
	                Rf_old = Rf
	                Nf=constraints[0].dual_value[0:S].reshape(S)
	                Rf=wR.value.reshape(M)/w

	                #Update the effective resource concentrations
	                R0t_new = K+ Qinv.dot(K-Rf)/Qinv_aa
	                Delta_R0t = R0t_new-R0t
	                R0t = R0t + alpha*Delta_R0t
	                
	                Delta_old = Delta
	                Delta = np.linalg.norm(Rf_old - Rf)
	                if verbose:
	                    print('Iteration: '+str(k))
	                    print('Delta: '+str(Delta))
	                    print('---------------- '+str(time.time()-start_time)[:4]+' s ----------------')
	            except:
	                #If optimization fails, try new R0t
	                shift = shift_size*np.random.randn(M)
	                if np.min(R0t + shift) < 0: #Prevent any values from becoming negative
	                    R0t = R0t_0*np.ones(M)
	                    Rf = np.inf
	                    Rf_old = 0
	                else:
	                    R0t = R0t + shift
	                if verbose:
	                    print('Added '+str(eps)+' times random numbers')
	            k+=1
	            #Check for limit cycle
	            if np.isfinite(Delta) and Delta > tol and np.abs(Delta-Delta_old) < 0.1*tol:
	                ncyc+=1
	            if ncyc > 10:
	                print('Limit cycle detected')
	                k = max_iters
	        if k == max_iters:
	            failed = 1
	        return Rf, Nf, failed
Beispiel #25
0
def attacked_FTRL(T,
                  MAB,
                  target_arm,
                  eta=10,
                  alg='exp_3',
                  delta=0.99,
                  constant_attack=False):

    K = len(MAB)
    true_S = np.zeros((K, ))
    true_losses = np.zeros((K, ))
    N = np.zeros((K, ))
    estimated_losses = np.zeros((K, ))
    rewards = np.zeros((T, ))
    draws = 0 * rewards
    arms = np.linspace(0, K - 1, K, dtype='int')
    attacks = np.zeros((T, ))
    time_of_attacks = np.zeros((T, ))
    for t in trange(T):
        x = cp.Variable(K, pos=True)
        temp_1 = cp.Constant(value=np.ones((K, )))
        temp_2 = cp.Constant(value=estimated_losses)
        constraints = [cp.sum(cp.multiply(temp_1, x)) == 1]
        if alg == 'log_barrier':
            obj = cp.Minimize(
                cp.sum(cp.multiply(temp_2, x)) - 1 / eta * cp.sum(cp.log(x)))
        elif alg == 'inf':
            obj = cp.Minimize(
                cp.sum(cp.multiply(temp_2, x)) - 2 / eta * cp.sum(cp.sqrt(x)))
        else:
            obj = cp.Minimize(
                cp.sum(cp.multiply(temp_2, x)) + 1 / eta *
                (cp.sum(cp.kl_div(x, temp_1)) - K))
        pb = cp.Problem(obj, constraints)
        try:
            pb.solve()
            P = x.value
        except:
            P = np.ones((K, )) / K
        # print("\nThe optimal value is", pb.value)
        # print("A solution x is")
        # print(x.value)
        # print("A dual solution corresponding to the inequality constraints is")
        # print(pb.constraints[0].dual_value)
        # print('Probability distribution:', P)
        if not np.sum(P) == 1:
            P = P / np.sum(P)
        if t < K:
            action = t
            attack_t = 0
        else:
            action = np.random.choice(arms, p=P)
            if action != target_arm:
                time_of_attacks[t] = 1
                beta = np.sqrt(
                    np.log(np.pi**2 * K * N**2 / (3 * delta)) / (2 * N))
                if constant_attack:
                    attack_t = -2 * np.maximum(
                        0, MAB[action].mean - MAB[target_arm].mean)
                else:
                    attack_t = -np.maximum(
                        (true_S / N)[action] - (true_S / N)[target_arm] +
                        beta[action] + beta[target_arm], 0)
            else:
                attack_t = 0
        attacks[t] = attack_t
        true_X = 1 * MAB[action].sample().squeeze()
        X = true_X + attack_t
        true_S[action] = true_S[action] + true_X
        true_losses[action] = true_losses[action] + (1 - true_X) / P[action]
        estimated_losses[action] = estimated_losses[action] + (1 -
                                                               X) / P[action]
        N[action] = N[action] + 1
        rewards[t] = true_X
        draws[t] = action
    return rewards, draws, attacks, time_of_attacks
Beispiel #26
0
def kl_ucb_zpd(progression_graph, trace_problems_dict, kl_ucb_lower_threshold,
               kl_ucb_n0, kl_ucb_n1, timeout, p_threshold, student):
    def is_correct(problem, answer):
        return answer == problem[2]

    traces = set(progression_graph.keys())
    traces.remove("")

    # Create nodes to store algorithm-specific trace details.
    trace_node_dict = {
        trace: KL_UCB_node(kl_ucb_n0, kl_ucb_n1)
        for trace in traces
    }
    trace_node_dict[""] = KL_UCB_node(0, 1)  # Jon Snow knows nothing.
    log = f'Trace -> KL-UCB Node dictionary created.'
    logger.info(log)

    # Create a dependency graph of traces. (Reverse of the progression graph.)
    dependency_graph = {}
    for trace in progression_graph.keys():
        dependency_graph[trace] = []

    for trace, more_complex_traces in progression_graph.items():
        for i in more_complex_traces:
            dependency_graph[i].append(trace)

    log = f"Generated dependency graph: "
    for trace, less_complex_trace in dependency_graph.items():
        log += f"\n{trace} -> {less_complex_trace}"
    logger.info(log)

    # Create two maps One from trace to traces less-complex than it. Another
    # from trace to traces more-complex than it.
    trace_to_less_complex_traces_dict = {}
    trace_to_more_complex_traces_dict = {}
    for trace in traces:
        trace_to_less_complex_traces_dict[trace] = set()
        trace_to_more_complex_traces_dict[trace] = set()

    for trace in traces:
        unadded_set = set(progression_graph[trace])
        more_complex_traces_set = set()
        while len(unadded_set) > 0:
            elem = unadded_set.pop()
            unadded_set |= set(progression_graph[elem])
            more_complex_traces_set.add(elem)
            trace_to_less_complex_traces_dict[elem].add(trace)

        trace_to_more_complex_traces_dict[trace] = more_complex_traces_set

    log = f"Generated map from trace to less complex traces: "
    for t, lct in trace_to_less_complex_traces_dict.items():
        log += f"\n{t} -> {lct}"
    logger.info(log)

    log = f"Generated map from trace to more complex traces: "
    for t, mct in trace_to_more_complex_traces_dict.items():
        log += f"\n{t} -> {mct}"
    logger.info(log)

    # Do topological ordering of the progression graph.
    sorted_traces = sorted(traces, key=cmp_to_key(cmp_trace))

    log = f'Generalised topological sort of the traces.\n'
    for trace in sorted_traces:
        log += f'\nTrace - {trace}'
    logger.info(log)

    # Run the kl-ucb bandit algorithm.
    # t = 1 is over when initialising the nodes.
    t = 2
    while t < timeout:
        # Create a dict that maps each max entropy value to the corresponding
        # traces.
        fp_traces_dict = defaultdict(set)
        for trace in traces:
            node = trace_node_dict[trace]
            kl_limit = (math.log(1 + t * math.log(math.log(t, 2), 2), 2) /
                        (node.n0_t0 + node.n1_t0))
            # print(kl_limit)
            u = cp.Variable()
            kl_d = (
                (cp.kl_div(node.p_t0, u) + cp.kl_div(1 - node.p_t0, 1 - u)) /
                math.log(2))
            constraints = [kl_d <= kl_limit, u <= 1, u >= 0]
            #            obj = cp.Maximize((cp.entr(u) + cp.entr(1 - u)) / math.log(2))
            obj = cp.Minimize(u)
            # print(f"obj is dcp {obj.is_dcp()}")
            prob = cp.Problem(obj, constraints)
            prob.solve()
            # print(f"Trace {trace} and p:{u.value}")
            if prob.value < kl_ucb_lower_threshold:
                fp_traces_dict[prob.value].add(trace)

        if len(fp_traces_dict) == 0:
            logger.info(f"No traces above kl_ucb_lower_threshold")
            continue

        log = (f'f(p) for each trace calculated for round {t}.')
        for fp, ts in fp_traces_dict.items():
            log += f'\nfp: {fp} -> Traces: {ts}'
        logger.info(log)

        # Select the trace with the maximum entropy among all traces, i.e. the
        # arm, in topological order.
        max_fp, max_fp_traces_set = itemgetter(0)(sorted(
            fp_traces_dict.items(), key=itemgetter(0), reverse=True))

        for trace in sorted_traces:
            if trace in max_fp_traces_set:
                trace_arm = trace
                break

        # Ask the student a problem corresponding to the chosen trace and record
        # the answer.
        chosen_problem = trace_problems_dict[trace_arm][0]
        answer = student.solve(chosen_problem)
        node = trace_node_dict[trace_arm]

        log = (f'\nMax fp: {max_fp}\nMax traces: {max_fp_traces_set}'
               f'\nTrace-arm: {trace_arm}\nProblem: {chosen_problem}'
               f'\nAnswer: {answer}')
        logger.info(log)

        # Update the nodes of the algorithm according to the correctness of the
        # answer.
        if is_correct(chosen_problem, answer):
            node = trace_node_dict[trace_arm]
            node.n1_t1 = node.n1_t0 + 1
            node.n0_t1 = node.n0_t0
            node.p_t1 = node.n1_t1 / (node.n0_t1 + node.n1_t1)
            for trace in trace_to_less_complex_traces_dict[trace_arm]:
                node = trace_node_dict[trace]
                node.n1_t1 = node.n1_t0 + 1
                node.n0_t1 = node.n0_t0
                node.p_t1 = node.n1_t1 / (node.n0_t1 + node.n1_t1)
        else:
            # Calculate probability of answering by taking product of the
            # probabilities of the dependants of chosen trace.
            node = trace_node_dict[trace_arm]
            node.n1_t1 = node.n1_t0
            node.n0_t1 = node.n0_t0 + 1
            node.p_t1 = node.n1_t1 / (node.n0_t1 + node.n1_t1)

            for trace in trace_to_more_complex_traces_dict[trace_arm]:
                node = trace_node_dict[trace]
                node.n1_t1 = node.n1_t0
                node.n0_t1 = node.n0_t0 + 1
                node.p_t1 = node.n1_t1 / (node.n0_t1 + node.n1_t1)

        for trace, node in trace_node_dict.items():
            node.update()

        log = f'Updation of nodes completed.'
        for trace, node in trace_node_dict.items():
            log += f'\nTrace: {trace} -> Node: {node}'
        logger.info(log)

        if all([s == KC_STATE.LEARNED for s in student.kc_states.values()]):
            print("Yipe")
            break

        t += 1

    init_zpd = set()
    for trace, dependencies in dependency_graph.items():
        if trace_node_dict[trace].p_t0 <= p_threshold:
            dependency_threshold = [
                trace_node_dict[t].p_t0 > p_threshold for t in dependencies
            ]
            for i, threshold in enumerate(dependency_threshold):
                if threshold:
                    init_zpd.add(dependencies[i])
            if any(dependency_threshold):
                init_zpd.add(trace)

    return init_zpd
def optimize_quad_PAC_bound_bisection(costs_precomputed, p0, delta):
    '''Performs REP on the quadratic PAC-Bayes bound by sweeping on L_hat,
    bisectional search on lambda'''

    # Number of actions
    L = len(p0)

    # Number of environments
    m = np.shape(costs_precomputed)[0]

    C_bar = (1 / m) * (np.ones((1, m)) @ costs_precomputed)
    min_cost = np.min(C_bar)
    max_cost = np.max(C_bar)

    L_hats = np.linspace(min_cost, max_cost,
                         np.ceil((max_cost - min_cost) / 0.001))
    R_p0 = np.log(2 * np.sqrt(m) / delta) / (2 * m)

    # Initialize vectors for storing optimal solutions
    tau_opt = ((C_bar @ p0 + R_p0)**0.5 + R_p0**0.5)**2
    p_opt = p0

    for j in range(len(L_hats)):
        terminate = False
        L_hat = L_hats[j]
        min_lambda0 = (L_hat * R_p0 + R_p0**2)**0.5
        max_lambda0 = (tau_opt - L_hat) / 2 - R_p0
        if min_lambda0 > max_lambda0:
            # If this happens then the prior gives a lower tau than any valid
            # lambda choice
            terminate = True
        while not terminate:
            lambda0 = (min_lambda0 + max_lambda0) / 2

            # Create cost function variable
            tau = cvx.Variable()

            # Create variable for probability vector
            p = cvx.Variable(L)

            cost_empirical = (1 / m) * cvx.sum(costs_precomputed * p)
            R = (cvx.sum(cvx.kl_div(p, p0)) +
                 np.log(2 * np.sqrt(m) / delta)) / (2 * m)
            # R = 0.0

            # Constraints
            constraints = [
                tau >= L_hat + 2 * R + 2 * lambda0,
                lambda0**2 >= L_hat * R + R**2, L_hat == cost_empirical,
                p >= 0,
                cvx.sum(p) == 1
            ]

            prob = cvx.Problem(cvx.Minimize(tau), constraints)

            # Solve problem
            opt = prob.solve(verbose=False,
                             solver=cvx.MOSEK)  # , max_iters=3000)
            if np.isinf(opt) or (opt is None):
                min_lambda0 = lambda0
            else:
                max_lambda0 = lambda0

            if np.abs(lambda0 - (min_lambda0 + max_lambda0) / 2) < 0.001:
                terminate = True

            # Store optimal value and optimizer
            if (opt < tau_opt):
                tau_opt = opt
                p_opt = p.value

    new_emp_cost = (costs_precomputed @ p_opt).mean()

    return tau_opt, p_opt, new_emp_cost
Beispiel #28
0
def limited_information_privacy_utility(rho: float,
                                        lmbd: float,
                                        P0: np.ndarray,
                                        P1: np.ndarray,
                                        R0: np.ndarray,
                                        R1: np.ndarray,
                                        initial_points: int = 1,
                                        max_iterations: int = 30,
                                        solver=cp.ECOS,
                                        debug: bool = False,
                                        pi0: np.ndarray = None):
    """ Optimize the privacy-utility value function over the two policies
    in the limited information setting
    Parameters
    ----------
    rho : float
        Weight given to policy pi_1 (1-rho for policy pi_0)
    lmbd : float
        Weight given to the privacy term
    P0, P1 : np.ndarray
        Numpy matrices containing the transition probabilities for model M0 and M1
        Each matrix should have dimensions |actions|x|states|x|states|
    R0, R1 : np.ndarray
        Numpy matrices containing the rewards for model M0 and M1
        Each matrix should have dimensions |states|x|actions|
    initial_points : int, optional
        Number of initial random points to use to solve the concave problem.
        Default value is 1.
    max_iterations : int, optional
        Maximum number of iterations. Should be larger than initial_points.
        Default value is 30.
    solver : cvxpy.Solver, optional
        Solver used to solve the problem. Default solver is ECOS
    debug : bool, optional
        If true, prints the solver output.
    pi0 : np.ndarray, optional
        If a policy pi0 is provided, then we optimize over pi1
        the problem max_{pi1} V(pi1) - lambda I_F(pi0,pi1).
        In this case rho is set to 1 for simplicity.
    Returns
    -------
    I_L : float
        Inverse of the privacy level
    xi1, xi0 : np.ndarray
        Stationary distributions over states and actions achieving the best
        level of utility-privacy
    """

    # Sanity checks
    P0, P1 = sanity_check_probabilities(P0, P1)
    R0, R1 = sanity_check_rewards(R0, R1)
    initial_points = int(initial_points) if initial_points >= 1 else 1
    max_iterations = initial_points if initial_points > max_iterations else int(
        max_iterations)

    if rho < 0 or rho > 1:
        raise ValueError('Rho should be in [0,1]')

    if lmbd < 0:
        raise ValueError('Lambda should be non-negative')

    na = P0.shape[0]
    ns = P1.shape[1]

    if pi0 is not None:
        _xi0, _ = compute_stationary_distribution(P0, pi0)
        rho = 1

    best_res, best_xi1, best_xi0 = np.inf, None, None

    # Loop through initial points and return best result
    i = 0
    n = 0
    while i == 0 or (i < initial_points and n < max_iterations):
        n += 1

        # Construct the problem to find minimum privacy
        gamma = cp.Variable(1, nonneg=True)
        xi0 = cp.Variable((ns, na), nonneg=True) if pi0 is None else _xi0
        xi1 = cp.Variable((ns, na), nonneg=True)

        kl_div_stationary_dis = 0
        for s in range(ns):
            kl_div_stationary_dis += cp.kl_div(cp.sum(
                xi1[s, :]), cp.sum(xi0[s, :])) + cp.sum(xi1[s, :]) - cp.sum(
                    xi0[s, :])
        objective = gamma - lmbd * kl_div_stationary_dis

        # stationarity constraints
        stationarity_constraint0 = 0
        stationarity_constraint1 = 0
        for a in range(na):
            stationarity_constraint0 += xi0[:,
                                            a].T @ (P0[a, :, :] - np.eye(ns))
            stationarity_constraint1 += xi1[:,
                                            a].T @ (P1[a, :, :] - np.eye(ns))

        constraints = [stationarity_constraint1 == 0, cp.sum(xi1) == 1]

        if pi0 is None:
            constraints += [cp.sum(xi0) == 1, stationarity_constraint0 == 0]

        # Privacy-utility constraints
        privacy_utility_constraint = 0
        for s in range(ns):
            for y in range(ns):
                privacy_utility_constraint += lmbd * (
                    cp.kl_div(xi1[s, :] @ P1[:, s, y], xi0[s, :] @ P0[:, s, y])
                    + (xi1[s, :] @ P1[:, s, y]) - (xi0[s, :] @ P0[:, s, y]))
            for a in range(na):
                privacy_utility_constraint -= (
                    rho * xi1[s, a] * R1[s, a] +
                    (1 - rho) * xi0[s, a] * R0[s, a])

        constraints += [privacy_utility_constraint <= gamma]

        # Solve problem
        problem = cp.Problem(cp.Minimize(objective), constraints)
        if not dccp.is_dccp(problem):
            raise Exception('Problem is not Concave with convex constraints!')
        try:
            result = problem.solve(method='dccp',
                                   ccp_times=1,
                                   verbose=debug,
                                   solver=solver)
        except Exception as err:
            continue

        # Check if results are better than previous ones
        if result[0] is not None:
            i += 1
            if result[0] < best_res:
                best_res, best_xi1, best_xi0 = result[0], xi1.value, \
                    xi0.value if pi0 is None else xi0

    # Make sure to normalize the results
    best_xi0 += eps
    best_xi1 += eps
    best_xi0 /= np.sum(best_xi0) if not np.isclose(np.sum(best_xi0), 0) else 1.
    best_xi1 /= np.sum(best_xi1) if not np.isclose(np.sum(best_xi1), 0) else 1.
    return best_res, best_xi1, best_xi0
Beispiel #29
0
def limited_information_privacy_lb(P0: np.ndarray,
                                   P1: np.ndarray,
                                   initial_points: int = 1,
                                   max_iterations: int = 30,
                                   solver=cp.ECOS,
                                   debug=False):
    """ Computes the policies that achieves the best level of privacy in the
    limited information setting
    Parameters
    ----------
    P0, P1 : np.ndarray
        Numpy matrices containing the transition probabilities for models M0 and M1
        Each matrix should have dimensions |actions|x|states|x|states|
    initial_points : int, optional
        Number of initial random points to use to solve the concave problem.
        Default value is 1.
    max_iterations : int, optional
        Maximum number of iterations. Should be larger than initial_points.
        Default value is 30.
    solver : cvxpy.Solver, optional
        Solver used to solve the problem. Default solver is ECOS
    debug : bool, optional
        If true, prints the solver output.
    Returns
    -------
    I_L : float
        Inverse of the privacy level
    xi1, xi0 : np.ndarray
        Stationary distributions over states and actions achieving the best
        level of privacy
    """
    P0, P1 = sanity_check_probabilities(P0, P1)
    initial_points = int(initial_points) if initial_points >= 1 else 1
    max_iterations = initial_points if initial_points > max_iterations else int(
        max_iterations)

    na, ns = P0.shape[0], P0.shape[1]

    best_res, best_xi1, best_xi0 = np.inf, None, None
    # Compute KL divergences
    I = compute_KL_divergence_models(P0, P1)

    # Loop through initial points and return best result
    i = 0
    n = 0
    while i == 0 or (i < initial_points and n < max_iterations):
        n += 1
        gamma = cp.Variable(1)
        xi0 = cp.Variable((ns, na), nonneg=True)
        xi1 = cp.Variable((ns, na), nonneg=True)

        kl_div_statinary_dis = 0
        for s in range(ns):
            kl_div_statinary_dis += cp.entr(cp.sum(xi1[s, :]))

        # stationarity constraints
        stationarity_constraint = 0
        for a in range(na):
            stationarity_constraint += xi1[:, a].T @ (P1[a, :, :] - np.eye(ns))

        constraints = [stationarity_constraint == 0, cp.sum(xi1) == 1]

        # Privacy constraints
        privacy_constraint = 0
        for s in range(ns):
            constraints += [cp.sum(xi0[s, :]) == 1]
            for y in range(ns):
                privacy_constraint += cp.kl_div(
                    xi1[s, :] @ P1[:, s, y], xi0[s, :] @ P0[:, s, y]) + (
                        xi1[s, :] @ P1[:, s, y]) - (xi0[s, :] @ P0[:, s, y])

        constraints += [privacy_constraint <= gamma]
        objective = gamma + kl_div_statinary_dis

        # Solve problem
        problem = cp.Problem(cp.Minimize(objective), constraints)
        if not dccp.is_dccp(problem):
            raise Exception('Problem is not Concave with convex constraints!')
        try:
            result = problem.solve(method='dccp',
                                   ccp_times=1,
                                   verbose=debug,
                                   solver=solver)
        except Exception as err:
            continue

        # Check if results are better than previous ones
        if result[0] is not None:
            i += 1
            if result[0] < best_res:
                best_res, best_xi1, best_xi0 = result[0], xi1.value, xi0.value

    # Make sure to normalize the results
    best_xi0 += eps
    best_xi1 += eps
    best_xi0 /= np.sum(best_xi0) if not np.isclose(np.sum(best_xi0), 0) else 1.
    best_xi1 /= np.sum(best_xi1) if not np.isclose(np.sum(best_xi1), 0) else 1.
    return best_res, best_xi1, best_xi0
Beispiel #30
0
 prox("NORM_2", lambda: cp.norm2(x)),
 prox("NORM_NUCLEAR", lambda: cp.norm(X, "nuc")),
 #prox("QUAD_OVER_LIN", lambda: cp.quad_over_lin(p, q1)),
 prox("SECOND_ORDER_CONE", None, C_soc_scaled),
 prox("SECOND_ORDER_CONE", None, C_soc_scaled_translated),
 prox("SECOND_ORDER_CONE", None, C_soc_translated),
 prox("SECOND_ORDER_CONE", None, lambda: [cp.norm(X, "fro") <= t]),
 prox("SECOND_ORDER_CONE", None, lambda: [cp.norm2(x) <= t]),
 prox("SEMIDEFINITE", None, lambda: [X >> 0]),
 prox("SUM_DEADZONE", f_dead_zone),
 prox("SUM_EXP", lambda: cp.sum_entries(cp.exp(x))),
 prox("SUM_HINGE", f_hinge),
 prox("SUM_HINGE", lambda: cp.sum_entries(cp.max_elemwise(1-x, 0))),
 prox("SUM_HINGE", lambda: cp.sum_entries(cp.max_elemwise(1-x, 0))),
 prox("SUM_INV_POS", lambda: cp.sum_entries(cp.inv_pos(x))),
 prox("SUM_KL_DIV", lambda: cp.sum_entries(cp.kl_div(p1,q1))),
 prox("SUM_LARGEST", lambda: cp.sum_largest(x, 4)),
 prox("SUM_LOGISTIC", lambda: cp.sum_entries(cp.logistic(x))),
 prox("SUM_NEG_ENTR", lambda: cp.sum_entries(-cp.entr(x))),
 prox("SUM_NEG_LOG", lambda: cp.sum_entries(-cp.log(x))),
 prox("SUM_QUANTILE", f_quantile),
 prox("SUM_QUANTILE", f_quantile_elemwise),
 prox("SUM_SQUARE", f_least_squares_matrix),
 prox("SUM_SQUARE", lambda: f_least_squares(20)),
 prox("SUM_SQUARE", lambda: f_least_squares(5)),
 prox("SUM_SQUARE", f_quad_form),
 prox("TOTAL_VARIATION_1D", lambda: cp.tv(x)),
 prox("ZERO", None, C_linear_equality),
 prox("ZERO", None, C_linear_equality_matrix_lhs),
 prox("ZERO", None, C_linear_equality_matrix_rhs),
 prox("ZERO", None, C_linear_equality_multivariate),
Beispiel #31
0
def rel_H(x, y):
    # relative entropy in Boyd
    return cvx.sum(cvx.kl_div(x, y) + x - y)
Beispiel #32
0
u=0.51
ki=10**(-2) # increase the value of ki because the original value is too small 
B=2*10**6
Vu=1.1 
N0=10**(-10)
h=np.array([2.52690569892026e-06,1.44441867078275e-06,9.33368801933646e-07,2.23291617751371e-06,9.21244504161081e-07])


# optimization variables
tau_i = cvx.Variable(len(h))
fi = cvx.Variable(len(h))
ei = cvx.Variable(len(h))
a = 1 - cvx.sum(tau_i)

# optimization objective and constraints 
result = cvx.sum(-fi*10**6+(cvx.kl_div(tau_i,(cvx.multiply(ei,h)+tau_i*N0)/N0)\
                 +tau_i-(cvx.multiply(ei,h)+tau_i*N0)/N0)*B/Vu/np.log(2)) 
objective = cvx.Minimize(result)
constraints = [tau_i >= 0,a >= 0,ei >= 0,fi >= 0,ei + cvx.multiply(ki,fi**3) <= u*p*h*a]
prob = cvx.Problem(objective, constraints)
rewards = prob.solve(solver = cvx.MOSEK) # solve the problem by MOSEK


local_rate = (fi.value)*10**6
offloading_rate = B/Vu*tau_i.value*np.log2(1+ei.value*h/(N0*tau_i.value))
# mode = []
# for i in range(len(h)):
    # if local_rate[i] < offloading_rate[i]:
        # mode.append(1)
    # else:
        # mode.append(0)
Beispiel #33
0
 prox("NORM_2", lambda: cp.norm2(x)),
 prox("NORM_NUCLEAR", lambda: cp.norm(X, "nuc")),
 #prox("QUAD_OVER_LIN", lambda: cp.quad_over_lin(p, q1)),
 prox("SECOND_ORDER_CONE", None, C_soc_scaled),
 prox("SECOND_ORDER_CONE", None, C_soc_scaled_translated),
 prox("SECOND_ORDER_CONE", None, C_soc_translated),
 prox("SECOND_ORDER_CONE", None, lambda: [cp.norm(X, "fro") <= t]),
 prox("SECOND_ORDER_CONE", None, lambda: [cp.norm2(x) <= t]),
 prox("SEMIDEFINITE", None, lambda: [X >> 0]),
 prox("SUM_DEADZONE", f_dead_zone),
 prox("SUM_EXP", lambda: cp.sum_entries(cp.exp(x))),
 prox("SUM_HINGE", f_hinge),
 prox("SUM_HINGE", lambda: cp.sum_entries(cp.max_elemwise(1 - x, 0))),
 prox("SUM_HINGE", lambda: cp.sum_entries(cp.max_elemwise(1 - x, 0))),
 prox("SUM_INV_POS", lambda: cp.sum_entries(cp.inv_pos(x))),
 prox("SUM_KL_DIV", lambda: cp.sum_entries(cp.kl_div(p1, q1))),
 prox("SUM_LARGEST", lambda: cp.sum_largest(x, 4)),
 prox("SUM_LOGISTIC", lambda: cp.sum_entries(cp.logistic(x))),
 prox("SUM_NEG_ENTR", lambda: cp.sum_entries(-cp.entr(x))),
 prox("SUM_NEG_LOG", lambda: cp.sum_entries(-cp.log(x))),
 prox("SUM_QUANTILE", f_quantile),
 prox("SUM_QUANTILE", f_quantile_elemwise),
 prox("SUM_SQUARE", f_least_squares_matrix),
 prox("SUM_SQUARE", lambda: f_least_squares(20)),
 prox("SUM_SQUARE", lambda: f_least_squares(5)),
 prox("SUM_SQUARE", f_quad_form),
 prox("TOTAL_VARIATION_1D", lambda: cp.tv(x)),
 prox("ZERO", None, C_linear_equality),
 prox("ZERO", None, C_linear_equality_matrix_lhs),
 prox("ZERO", None, C_linear_equality_matrix_rhs),
 prox("ZERO", None, C_linear_equality_multivariate),
Beispiel #34
0
    def test_kl_div(self):
        """Test a problem with kl_div.
        """
        import numpy as np
        import cvxpy as cp

        kK=10
        kSeed=10

        prng=np.random.RandomState(kSeed)
        #Generate a random reference distribution
        npSPriors=prng.uniform(0.0,1.0,kK)
        npSPriors=npSPriors/np.sum(npSPriors)

        #Reference distribution
        p_refProb=cp.Parameter(kK,1,sign='positive')
        #Distribution to be estimated
        v_prob=cp.Variable(kK,1)
        objkl=0.0
        for k in xrange(kK):
            objkl += cp.kl_div(v_prob[k,0],p_refProb[k,0])

        constrs=[sum([v_prob[k,0] for k in xrange(kK)])==1]
        klprob=cp.Problem(cp.Minimize(objkl),constrs)
        p_refProb.value=npSPriors
        result = klprob.solve()
        print result

    # # Risk return tradeoff curve
    # def test_risk_return_tradeoff(self):
    #     from math import sqrt
    #     from cvxopt import matrix
    #     from cvxopt.blas import dot
    #     from cvxopt.solvers import qp, options
    #     import scipy

    #     n = 4
    #     S = matrix( [[ 4e-2,  6e-3, -4e-3,   0.0 ],
    #                  [ 6e-3,  1e-2,  0.0,    0.0 ],
    #                  [-4e-3,  0.0,   2.5e-3, 0.0 ],
    #                  [ 0.0,   0.0,   0.0,    0.0 ]] )
    #     pbar = matrix([.12, .10, .07, .03])

    #     N = 100
    #     # CVXPY
    #     Sroot = numpy.asmatrix(scipy.linalg.sqrtm(S))
    #     x = cp.Variable(n, name='x')
    #     mu = cp.Parameter(name='mu')
    #     mu.value = 1 # TODO cp.Parameter("positive")
    #     objective = cp.Minimize(-pbar*x + mu*quad_over_lin(Sroot*x,1))
    #     constraints = [sum(x) == 1, x >= 0]
    #     p = cp.Problem(objective, constraints)

    #     mus = [ 10**(5.0*t/N-1.0) for t in range(N) ]
    #     xs = []
    #     for mu_val in mus:
    #         mu.value = mu_val
    #         p.solve()
    #         xs.append(x.value)
    #     returns = [ dot(pbar,x) for x in xs ]
    #     risks = [ sqrt(dot(x, S*x)) for x in xs ]

    #     # QP solver