예제 #1
0
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
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
    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
예제 #6
0
    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
예제 #7
0
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))
예제 #8
0
    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))
예제 #9
0
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))
예제 #10
0
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
예제 #11
0
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))
예제 #12
0
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
예제 #13
0
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))
예제 #14
0
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