def rejection_sampling_z(N, y, W1, W2): """ A rejection sampling method for sampling the inactive variables from a polytope. **See Also** domains.sample_z """ m, n = W1.shape s = np.dot(W1, y).reshape((m, 1)) # Build a box around z for uniform sampling qps = QPSolver() A = np.vstack((W2, -W2)) b = np.vstack((-1-s, -1+s)).reshape((2*m, 1)) lbox, ubox = np.zeros((1,m-n)), np.zeros((1,m-n)) for i in range(m-n): clb = np.zeros((m-n,1)) clb[i,0] = 1.0 lbox[0,i] = qps.linear_program_ineq(clb, A, b)[i,0] cub = np.zeros((m-n,1)) cub[i,0] = -1.0 ubox[0,i] = qps.linear_program_ineq(cub, A, b)[i,0] bn = BoundedNormalizer(lbox, ubox) Zbox = bn.unnormalize(np.random.uniform(-1.0,1.0,size=(50*N,m-n))) ind = np.all(np.dot(A, Zbox.T) >= b, axis=0) if np.sum(ind) >= N: Z = Zbox[ind,:] return Z[:N,:].reshape((N,m-n)) else: return None
def hit_and_run_z(N, y, W1, W2): m, n = W1.shape # get an initial feasible point qps = QPSolver() lb = -np.ones((m,1)) ub = np.ones((m,1)) c = np.zeros((m,1)) x0 = qps.linear_program_eq(c, W1.T, y.reshape((n,1)), lb, ub) z0 = np.dot(W2.T, x0).reshape((m-n, 1)) # define the polytope A >= b s = np.dot(W1, y).reshape((m, 1)) A = np.vstack((W2, -W2)) b = np.vstack((-1-s, -1+s)).reshape((2*m, 1)) # tolerance ztol = 1e-6 eps0 = ztol/4.0 Z = np.zeros((N, m-n)) for i in range(N): # random direction bad_dir = True count, maxcount = 0, 50 while bad_dir: d = np.random.normal(size=(m-n,1)) bad_dir = np.any(np.dot(A, z0 + eps0*d) <= b) count += 1 if count >= maxcount: warnings.warn('There are no more directions worth pursuing in hit and run. Got {:d} samples.'.format(i)) Z[i:,:] = np.tile(z0, (1,N-i)).transpose() return Z # find constraints that impose lower and upper bounds on eps f, g = b - np.dot(A,z0), np.dot(A, d) # find an upper bound on the step min_ind = np.logical_and(g<=0, f < -np.sqrt(np.finfo(np.float).eps)) eps_max = np.amin(f[min_ind]/g[min_ind]) # find a lower bound on the step max_ind = np.logical_and(g>0, f < -np.sqrt(np.finfo(np.float).eps)) eps_min = np.amax(f[max_ind]/g[max_ind]) # randomly sample eps eps1 = np.random.uniform(eps_min, eps_max) # take a step along d z1 = z0 + eps1*d Z[i,:] = z1.reshape((m-n, )) # update temp vars z0, eps0 = z1, eps1 return Z
def rejection_sampling_z(N, y, W1, W2): """A rejection sampling method for sampling the from a polytope. Parameters ---------- N : int the number of inactive variable samples y : ndarray the value of the active variables W1 : ndarray m-by-n matrix that contains the eigenvector bases of the n-dimensional active subspace W2 : ndarray m-by-(m-n) matrix that contains the eigenvector bases of the (m-n)-dimensional inactive subspace Returns ------- Z : ndarray N-by-(m-n) matrix that contains values of the inactive variable that correspond to the given `y` See Also -------- domains.sample_z Notes ----- The interface for this implementation is written specifically for `domains.sample_z`. """ m, n = W1.shape s = np.dot(W1, y).reshape((m, 1)) # Build a box around z for uniform sampling qps = QPSolver() A = np.vstack((W2, -W2)) b = np.vstack((-1 - s, -1 + s)).reshape((2 * m, 1)) lbox, ubox = np.zeros((1, m - n)), np.zeros((1, m - n)) for i in range(m - n): clb = np.zeros((m - n, 1)) clb[i, 0] = 1.0 lbox[0, i] = qps.linear_program_ineq(clb, A, b)[i, 0] cub = np.zeros((m - n, 1)) cub[i, 0] = -1.0 ubox[0, i] = qps.linear_program_ineq(cub, A, b)[i, 0] bn = BoundedNormalizer(lbox, ubox) Zbox = bn.unnormalize(np.random.uniform(-1.0, 1.0, size=(50 * N, m - n))) ind = np.all(np.dot(A, Zbox.T) >= b, axis=0) if np.sum(ind) >= N: Z = Zbox[ind, :] return Z[:N, :].reshape((N, m - n)) else: return None
def rejection_sampling_z(N, y, W1, W2): """A rejection sampling method for sampling the from a polytope. Parameters ---------- N : int the number of inactive variable samples y : ndarray the value of the active variables W1 : ndarray m-by-n matrix that contains the eigenvector bases of the n-dimensional active subspace W2 : ndarray m-by-(m-n) matrix that contains the eigenvector bases of the (m-n)-dimensional inactive subspace Returns ------- Z : ndarray N-by-(m-n) matrix that contains values of the inactive variable that correspond to the given `y` See Also -------- domains.sample_z Notes ----- The interface for this implementation is written specifically for `domains.sample_z`. """ m, n = W1.shape s = np.dot(W1, y).reshape((m, 1)) # Build a box around z for uniform sampling qps = QPSolver() A = np.vstack((W2, -W2)) b = np.vstack((-1-s, -1+s)).reshape((2*m, 1)) lbox, ubox = np.zeros((1,m-n)), np.zeros((1,m-n)) for i in range(m-n): clb = np.zeros((m-n,1)) clb[i,0] = 1.0 lbox[0,i] = qps.linear_program_ineq(clb, A, b)[i,0] cub = np.zeros((m-n,1)) cub[i,0] = -1.0 ubox[0,i] = qps.linear_program_ineq(cub, A, b)[i,0] bn = BoundedNormalizer(lbox, ubox) Zbox = bn.unnormalize(np.random.uniform(-1.0,1.0,size=(50*N,m-n))) ind = np.all(np.dot(A, Zbox.T) >= b, axis=0) if np.sum(ind) >= N: Z = Zbox[ind,:] return Z[:N,:].reshape((N,m-n)) else: return None
def regularize_z(self, Y, N=1): """Train the global quadratic for the regularization. Parameters ---------- Y : ndarray N-by-n matrix of points in the space of active variables N : int, optional merely there satisfy the interface of `regularize_z`. It should not be anything other than 1 Returns ------- Z : ndarray N-by-(m-n)-by-1 matrix that contains a value of the inactive variables for each value of the inactive variables Notes ----- In contrast to the `regularize_z` in BoundedActiveVariableMap and UnboundedActiveVariableMap, this implementation of `regularize_z` uses a quadratic program to find a single value of the inactive variables for each value of the active variables. """ if N != 1: raise Exception('MinVariableMap needs N=1.') W1, W2 = self.domain.subspaces.W1, self.domain.subspaces.W2 m, n = W1.shape NY = Y.shape[0] qps = QPSolver() Zlist = [] A_ineq = np.vstack((W2, -W2)) for y in Y: c = self._bz.reshape((m-n, 1)) + np.dot(self._zAy, y).reshape((m-n, 1)) b_ineq = np.vstack(( -1-np.dot(W1, y).reshape((m, 1)), -1+np.dot(W1, y).reshape((m, 1)) )) z = qps.quadratic_program_ineq(c, self._zAz, A_ineq, b_ineq) Zlist.append(z) Z = np.array(Zlist).reshape((NY, m-n, N)) return Z
def random_walk_z(N, y, W1, W2): """ A random walk method for sampling the inactive variables from a polytope. **See Also** domains.sample_z """ m, n = W1.shape s = np.dot(W1, y).reshape((m, 1)) # linear program to get starting z0 if np.all(np.zeros((m, 1)) <= 1-s) and np.all(np.zeros((m, 1)) >= -1-s): z0 = np.zeros((m-n, 1)) else: qps = QPSolver() lb = -np.ones((m,1)) ub = np.ones((m,1)) c = np.zeros((m,1)) x0 = qps.linear_program_eq(c, W1.T, y.reshape((n,1)), lb, ub) z0 = np.dot(W2.T, x0).reshape((m-n, 1)) # get MCMC step size sig = 0.1*np.minimum( np.linalg.norm(np.dot(W2, z0) + s - 1), np.linalg.norm(np.dot(W2, z0) + s + 1)) # burn in for i in range(10*N): zc = z0 + sig*np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1-s) and np.all(np.dot(W2, zc) >= -1-s): z0 = zc # sample Z = np.zeros((m-n, N)) for i in range(N): zc = z0 + sig*np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1-s) and np.all(np.dot(W2, zc) >= -1-s): z0 = zc Z[:,i] = z0.reshape((z0.shape[0], )) return Z.reshape((N, m-n))
def regularize_z(self, Y, N=1): if N != 1: raise Exception('MinVariableMap needs N=1.') W1, W2 = self.domain.subspaces.W1, self.domain.subspaces.W2 m, n = W1.shape NY = Y.shape[0] qps = QPSolver() Zlist = [] A_ineq = np.vstack((W2, -W2)) for y in Y: c = self.bz.reshape((m-n, 1)) + np.dot(self.zAy, y).reshape((m-n, 1)) b_ineq = np.vstack(( -1-np.dot(W1, y).reshape((m, 1)), -1+np.dot(W1, y).reshape((m, 1)) )) z = qps.quadratic_program_ineq(c, self.zAz, A_ineq, b_ineq) Zlist.append(z) return np.array(Zlist).reshape((NY, m-n, N))
def random_walk_z(N, y, W1, W2): """ I tried getting a random walk to work for MCMC sampling from the polytope that z lives in. But it doesn't seem to work very well. Gonna try rejection sampling. """ m, n = W1.shape s = np.dot(W1, y).reshape((m, 1)) # linear program to get starting z0 if np.all(np.zeros((m, 1)) <= 1-s) and np.all(np.zeros((m, 1)) >= -1-s): z0 = np.zeros((m-n, 1)) else: qps = QPSolver() lb = -np.ones((m,1)) ub = np.ones((m,1)) c = np.zeros((m,1)) x0 = qps.linear_program_eq(c, W1.T, y.reshape((n,1)), lb, ub) z0 = np.dot(W2.T, x0).reshape((m-n, 1)) # get MCMC step size sig = 0.1*np.minimum( np.linalg.norm(np.dot(W2, z0) + s - 1), np.linalg.norm(np.dot(W2, z0) + s + 1)) # burn in for i in range(10*N): zc = z0 + sig*np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1-s) and np.all(np.dot(W2, zc) >= -1-s): z0 = zc # sample Z = np.zeros((m-n, N)) for i in range(N): zc = z0 + sig*np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1-s) and np.all(np.dot(W2, zc) >= -1-s): z0 = zc Z[:,i] = z0.reshape((z0.shape[0], )) return Z.reshape((N, m-n))
def hit_and_run_z(N, y, W1, W2): """ A hit and run method for sampling the inactive variables from a polytope. **See Also** domains.sample_z """ m, n = W1.shape # get an initial feasible point using the Chebyshev center. huge props to # David Gleich for showing me the Chebyshev center. s = np.dot(W1, y).reshape((m, 1)) normW2 = np.sqrt( np.sum( np.power(W2, 2), axis=1 ) ).reshape((m,1)) A = np.hstack(( np.vstack((W2, -W2.copy())), np.vstack((normW2, normW2.copy())) )) b = np.vstack((1-s, 1+s)).reshape((2*m, 1)) c = np.zeros((m-n+1,1)) c[-1] = -1.0 qps = QPSolver() zc = qps.linear_program_ineq(c, -A, -b) z0 = zc[:-1].reshape((m-n, 1)) # define the polytope A >= b s = np.dot(W1, y).reshape((m, 1)) A = np.vstack((W2, -W2)) b = np.vstack((-1-s, -1+s)).reshape((2*m, 1)) # tolerance ztol = 1e-6 eps0 = ztol/4.0 Z = np.zeros((N, m-n)) for i in range(N): # random direction bad_dir = True count, maxcount = 0, 50 while bad_dir: d = np.random.normal(size=(m-n,1)) bad_dir = np.any(np.dot(A, z0 + eps0*d) <= b) count += 1 if count >= maxcount: logging.getLogger(__name__).warn('There are no more directions worth pursuing in hit and run. Got {:d} samples.'.format(i)) Z[i:,:] = np.tile(z0, (1,N-i)).transpose() return Z # find constraints that impose lower and upper bounds on eps f, g = b - np.dot(A,z0), np.dot(A, d) # find an upper bound on the step min_ind = np.logical_and(g<=0, f < -np.sqrt(np.finfo(np.float).eps)) eps_max = np.amin(f[min_ind]/g[min_ind]) # find a lower bound on the step max_ind = np.logical_and(g>0, f < -np.sqrt(np.finfo(np.float).eps)) eps_min = np.amax(f[max_ind]/g[max_ind]) # randomly sample eps eps1 = np.random.uniform(eps_min, eps_max) # take a step along d z1 = z0 + eps1*d Z[i,:] = z1.reshape((m-n, )) # update temp var z0 = z1.copy() return Z
def random_walk_z(N, y, W1, W2): """A random walk method for sampling from a polytope. Parameters ---------- N : int the number of inactive variable samples y : ndarray the value of the active variables W1 : ndarray m-by-n matrix that contains the eigenvector bases of the n-dimensional active subspace W2 : ndarray m-by-(m-n) matrix that contains the eigenvector bases of the (m-n)-dimensional inactive subspace Returns ------- Z : ndarray N-by-(m-n) matrix that contains values of the inactive variable that correspond to the given `y` See Also -------- domains.sample_z Notes ----- The interface for this implementation is written specifically for `domains.sample_z`. """ m, n = W1.shape s = np.dot(W1, y).reshape((m, 1)) # linear program to get starting z0 if np.all(np.zeros((m, 1)) <= 1 - s) and np.all( np.zeros((m, 1)) >= -1 - s): z0 = np.zeros((m - n, 1)) else: qps = QPSolver() lb = -np.ones((m, 1)) ub = np.ones((m, 1)) c = np.zeros((m, 1)) x0 = qps.linear_program_eq(c, W1.T, y.reshape((n, 1)), lb, ub) z0 = np.dot(W2.T, x0).reshape((m - n, 1)) # get MCMC step size sig = 0.1 * np.minimum(np.linalg.norm(np.dot(W2, z0) + s - 1), np.linalg.norm(np.dot(W2, z0) + s + 1)) # burn in for i in range(10 * N): zc = z0 + sig * np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1 - s) and np.all( np.dot(W2, zc) >= -1 - s): z0 = zc # sample Z = np.zeros((m - n, N)) for i in range(N): zc = z0 + sig * np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1 - s) and np.all( np.dot(W2, zc) >= -1 - s): z0 = zc Z[:, i] = z0.reshape((z0.shape[0], )) return Z.reshape((N, m - n))
def hit_and_run_z(N, y, W1, W2): """A hit and run method for sampling the inactive variables from a polytope. Parameters ---------- N : int the number of inactive variable samples y : ndarray the value of the active variables W1 : ndarray m-by-n matrix that contains the eigenvector bases of the n-dimensional active subspace W2 : ndarray m-by-(m-n) matrix that contains the eigenvector bases of the (m-n)-dimensional inactive subspace Returns ------- Z : ndarray N-by-(m-n) matrix that contains values of the inactive variable that correspond to the given `y` See Also -------- domains.sample_z Notes ----- The interface for this implementation is written specifically for `domains.sample_z`. """ m, n = W1.shape # get an initial feasible point using the Chebyshev center. huge props to # David Gleich for showing me the Chebyshev center. s = np.dot(W1, y).reshape((m, 1)) normW2 = np.sqrt(np.sum(np.power(W2, 2), axis=1)).reshape((m, 1)) A = np.hstack((np.vstack( (W2, -W2.copy())), np.vstack((normW2, normW2.copy())))) b = np.vstack((1 - s, 1 + s)).reshape((2 * m, 1)) c = np.zeros((m - n + 1, 1)) c[-1] = -1.0 qps = QPSolver() zc = qps.linear_program_ineq(c, -A, -b) z0 = zc[:-1].reshape((m - n, 1)) # define the polytope A >= b s = np.dot(W1, y).reshape((m, 1)) A = np.vstack((W2, -W2)) b = np.vstack((-1 - s, -1 + s)).reshape((2 * m, 1)) # tolerance ztol = 1e-6 eps0 = ztol / 4.0 Z = np.zeros((N, m - n)) for i in range(N): # random direction bad_dir = True count, maxcount = 0, 50 while bad_dir: d = np.random.normal(size=(m - n, 1)) bad_dir = np.any(np.dot(A, z0 + eps0 * d) <= b) count += 1 if count >= maxcount: Z[i:, :] = np.tile(z0, (1, N - i)).transpose() return Z # find constraints that impose lower and upper bounds on eps f, g = b - np.dot(A, z0), np.dot(A, d) # find an upper bound on the step min_ind = np.logical_and(g <= 0, f < -np.sqrt(np.finfo(np.float).eps)) eps_max = np.amin(f[min_ind] / g[min_ind]) # find a lower bound on the step max_ind = np.logical_and(g > 0, f < -np.sqrt(np.finfo(np.float).eps)) eps_min = np.amax(f[max_ind] / g[max_ind]) # randomly sample eps eps1 = np.random.uniform(eps_min, eps_max) # take a step along d z1 = z0 + eps1 * d Z[i, :] = z1.reshape((m - n, )) # update temp var z0 = z1.copy() return Z
def random_walk_z(N, y, W1, W2): """A random walk method for sampling from a polytope. Parameters ---------- N : int the number of inactive variable samples y : ndarray the value of the active variables W1 : ndarray m-by-n matrix that contains the eigenvector bases of the n-dimensional active subspace W2 : ndarray m-by-(m-n) matrix that contains the eigenvector bases of the (m-n)-dimensional inactive subspace Returns ------- Z : ndarray N-by-(m-n) matrix that contains values of the inactive variable that correspond to the given `y` See Also -------- domains.sample_z Notes ----- The interface for this implementation is written specifically for `domains.sample_z`. """ m, n = W1.shape s = np.dot(W1, y).reshape((m, 1)) # linear program to get starting z0 if np.all(np.zeros((m, 1)) <= 1-s) and np.all(np.zeros((m, 1)) >= -1-s): z0 = np.zeros((m-n, 1)) else: qps = QPSolver() lb = -np.ones((m,1)) ub = np.ones((m,1)) c = np.zeros((m,1)) x0 = qps.linear_program_eq(c, W1.T, y.reshape((n,1)), lb, ub) z0 = np.dot(W2.T, x0).reshape((m-n, 1)) # get MCMC step size sig = 0.1*np.minimum( np.linalg.norm(np.dot(W2, z0) + s - 1), np.linalg.norm(np.dot(W2, z0) + s + 1)) # burn in for i in range(10*N): zc = z0 + sig*np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1-s) and np.all(np.dot(W2, zc) >= -1-s): z0 = zc # sample Z = np.zeros((m-n, N)) for i in range(N): zc = z0 + sig*np.random.normal(size=z0.shape) if np.all(np.dot(W2, zc) <= 1-s) and np.all(np.dot(W2, zc) >= -1-s): z0 = zc Z[:,i] = z0.reshape((z0.shape[0], )) return Z.reshape((N, m-n))
def hit_and_run_z(N, y, W1, W2): """A hit and run method for sampling the inactive variables from a polytope. Parameters ---------- N : int the number of inactive variable samples y : ndarray the value of the active variables W1 : ndarray m-by-n matrix that contains the eigenvector bases of the n-dimensional active subspace W2 : ndarray m-by-(m-n) matrix that contains the eigenvector bases of the (m-n)-dimensional inactive subspace Returns ------- Z : ndarray N-by-(m-n) matrix that contains values of the inactive variable that correspond to the given `y` See Also -------- domains.sample_z Notes ----- The interface for this implementation is written specifically for `domains.sample_z`. """ m, n = W1.shape # get an initial feasible point using the Chebyshev center. huge props to # David Gleich for showing me the Chebyshev center. s = np.dot(W1, y).reshape((m, 1)) normW2 = np.sqrt( np.sum( np.power(W2, 2), axis=1 ) ).reshape((m,1)) A = np.hstack(( np.vstack((W2, -W2.copy())), np.vstack((normW2, normW2.copy())) )) b = np.vstack((1-s, 1+s)).reshape((2*m, 1)) c = np.zeros((m-n+1,1)) c[-1] = -1.0 qps = QPSolver() zc = qps.linear_program_ineq(c, -A, -b) z0 = zc[:-1].reshape((m-n, 1)) # define the polytope A >= b s = np.dot(W1, y).reshape((m, 1)) A = np.vstack((W2, -W2)) b = np.vstack((-1-s, -1+s)).reshape((2*m, 1)) # tolerance ztol = 1e-6 eps0 = ztol/4.0 Z = np.zeros((N, m-n)) for i in range(N): # random direction bad_dir = True count, maxcount = 0, 50 while bad_dir: d = np.random.normal(size=(m-n,1)) bad_dir = np.any(np.dot(A, z0 + eps0*d) <= b) count += 1 if count >= maxcount: Z[i:,:] = np.tile(z0, (1,N-i)).transpose() return Z # find constraints that impose lower and upper bounds on eps f, g = b - np.dot(A,z0), np.dot(A, d) # find an upper bound on the step min_ind = np.logical_and(g<=0, f < -np.sqrt(np.finfo(np.float).eps)) eps_max = np.amin(f[min_ind]/g[min_ind]) # find a lower bound on the step max_ind = np.logical_and(g>0, f < -np.sqrt(np.finfo(np.float).eps)) eps_min = np.amax(f[max_ind]/g[max_ind]) # randomly sample eps eps1 = np.random.uniform(eps_min, eps_max) # take a step along d z1 = z0 + eps1*d Z[i,:] = z1.reshape((m-n, )) # update temp var z0 = z1.copy() return Z