(self, label_index, unlabel_index, batch_size=5, qp_solver='ECOS', **kwargs)
Select indexes from the unlabel_index for querying.

        Parameters
        ----------
        label_index: {list, np.ndarray, IndexCollection}
            The indexes of labeled samples.

        unlabel_index: {list, np.ndarray, IndexCollection}
            The indexes of unlabeled samples.

        batch_size: int, optional (default=1)
            Selection batch size.

        qp_solver: str, optional (default='ECOS')
            The solver in cvxpy to solve QP, must be one of
            ['ECOS', 'OSQP']
            ECOS: https://www.embotech.com/ECOS
            OSQP: https://osqp.org/

        Returns
        -------
        selected_idx: list
            The selected indexes which is a subset of unlabel_index.
Select indexes from the unlabel_index for querying.
Select indexes from the unlabel_index for querying .
def select(self, label_index, unlabel_index, batch_size=5, qp_solver='ECOS', **kwargs):
        """Select indexes from the unlabel_index for querying.

        Parameters
        ----------
        label_index: {list, np.ndarray, IndexCollection}
            The indexes of labeled samples.

        unlabel_index: {list, np.ndarray, IndexCollection}
            The indexes of unlabeled samples.

        batch_size: int, optional (default=1)
            Selection batch size.

        qp_solver: str, optional (default='ECOS')
            The solver in cvxpy to solve QP, must be one of
            ['ECOS', 'OSQP']
            ECOS: https://www.embotech.com/ECOS
            OSQP: https://osqp.org/

        Returns
        -------
        selected_idx: list
            The selected indexes which is a subset of unlabel_index.
        """
        cvxpy = self._cvxpy
        assert (batch_size > 0)
        assert (isinstance(unlabel_index, collections.Iterable))
        assert (isinstance(label_index, collections.Iterable))
        unlabel_index = np.asarray(unlabel_index)
        label_index = np.asarray(label_index)
        if len(unlabel_index) <= batch_size:
            return unlabel_index

        KLL = self._K[np.ix_(label_index, label_index)]
        KLU = self._K[np.ix_(label_index, unlabel_index)]
        KUU = self._K[np.ix_(unlabel_index, unlabel_index)]

        L_len = len(label_index)
        U_len = len(unlabel_index)
        N = L_len + U_len

        # precision of ADMM
        MAX_ITER = 1000
        ABSTOL = 1e-4
        RELTOL = 1e-2

        # train a linear model in kernel form for
        theta = np.linalg.inv(KLL + self._gamma * np.eye(L_len)).dot(self.y[label_index])

        # start optimization
        dr_weight = np.ones(U_len)  # informativeness % representativeness
        es_weight = np.ones(U_len)  # easiness
        last_round_selected = []
        iter_round = 0
        while 1:
            iter_round += 1
            # solve QP
            P = 0.5 * self._mu * KUU
            pred_of_unlab = theta.dot(KLU)
            a = es_weight * (pred_of_unlab * pred_of_unlab + 2 * np.abs(pred_of_unlab))
            q = self._mu * (
                    (U_len - batch_size) / N * np.ones(L_len).dot(KLU) - (L_len + batch_size) / N * np.ones(U_len).dot(
                KUU)) + a
            # cvx
            x = cvxpy.Variable(U_len)
            objective = cvxpy.Minimize(0.5 * cvxpy.quad_form(x, P) + q.T @ x)
            constraints = [0 <= x, x <= 1, es_weight @ x == batch_size]
            prob = cvxpy.Problem(objective, constraints)
            # The optimal objective value is returned by `prob.solve()`.
            # result = prob.solve(solver=cvxpy.OSQP if qp_solver == 'OSQP' else cvxpy.ECOS)
            try:
                result = prob.solve(solver=cvxpy.OSQP if qp_solver == 'OSQP' else cvxpy.ECOS)
            except cvxpy.error.DCPError:
                result = prob.solve(solver=cvxpy.OSQP if qp_solver == 'OSQP' else cvxpy.ECOS, gp=True)
            # Sometimes the constraints can not be satisfied,
            # thus we relax the constraints to get an approximate solution.
            if not (type(result) == float and result != float('inf') and result != float('-inf')):
                # P = 0.5 * self._mu * KUU
                # pred_of_unlab = theta.dot(KLU)
                # a = es_weight * (pred_of_unlab * pred_of_unlab + 2 * np.abs(pred_of_unlab))
                # q = self._mu * (
                #     (U_len - batch_size) / N * np.ones(L_len).dot(KLU) - (L_len + batch_size) / N * np.ones(U_len).dot(
                #         KUU)) + a
                # cvx
                x = cvxpy.Variable(U_len)
                objective = cvxpy.Minimize(0.5 * cvxpy.quad_form(x, P) + q.T @ x)
                constraints = [0 <= x, x <= 1]
                prob = cvxpy.Problem(objective, constraints)
                # The optimal objective value is returned by `prob.solve()`.
                try:
                    result = prob.solve(solver=cvxpy.OSQP if qp_solver == 'OSQP' else cvxpy.ECOS)
                except cvxpy.error.DCPError:
                    result = prob.solve(solver=cvxpy.OSQP if qp_solver == 'OSQP' else cvxpy.ECOS, gp=True)

            # The optimal value for x is stored in `x.value`.
            # print(x.value)
            dr_weight = np.array(x.value)
            # print(dr_weight)
            # print(result)
            if len(np.shape(dr_weight)) == 2:
                dr_weight = dr_weight.T[0]
            # end cvx

            # update easiness weight
            worst_loss = dr_weight * (pred_of_unlab * pred_of_unlab + 2 * np.abs(pred_of_unlab))
            es_weight = np.zeros(U_len)
            es_weight_tmp = 1 - (worst_loss / self._lambda)
            update_indices = np.nonzero(worst_loss < self._lambda)[0]
            es_weight[update_indices] = es_weight_tmp[update_indices]

            # record selected indexes and judge convergence
            dr_largest = nlargestarg(dr_weight * es_weight, batch_size)
            select_ind = np.asarray(unlabel_index)[dr_largest]
            if set(last_round_selected) == set(select_ind) or iter_round > 15:
                return select_ind
            else:
                last_round_selected = copy.copy(select_ind)
                # print(dr_largest)
                # print(dr_weight[dr_largest])

            # ADMM optimization process
            # Filter less important instances for efficiency
            mix_weight = dr_weight * es_weight
            mix_weight[mix_weight < 0] = 0
            validind = np.nonzero(mix_weight > 0.001)[0]
            if len(validind) < 1:
                validind = nlargestarg(mix_weight, 1)
            vKlu = KLU[:, validind]

            delta = np.zeros(len(validind))  # dual variable in ADMM
            z = theta.dot(vKlu)  # auxiliary variable in ADMM

            # pre-computed constants in ADMM
            A = 2 * KLL.dot(KLL) + self._rho * vKlu.dot(vKlu.T) + 2 * self._gamma * KLL
            pinvA = np.linalg.pinv(A)
            rz = self._rho * vKlu
            rc = 2 * KLL.dot(self.y[label_index])
            kdenom = np.sqrt(mix_weight[validind] + self._rho / 2)
            ci = mix_weight[validind] / kdenom

            for solver_iter in range(MAX_ITER):
                # theta update
                r = rz.dot(z.T) + vKlu.dot(delta) + rc
                theta = pinvA.dot(r)

                # z update
                zold = z
                vud = self._rho * theta.dot(vKlu)
                vi = (vud - delta) / (2 * kdenom)
                ztmp = np.abs(vi) - ci
                ztmp[ztmp < 0] = 0
                ksi = np.sign(vi) * ztmp
                z = ksi / kdenom

                # delta update
                delta += self._rho * (z - theta.dot(vKlu))

                # judge convergence
                r_norm = np.linalg.norm((theta.dot(vKlu) - z))
                s_norm = np.linalg.norm(-self._rho * (z - zold))
                eps_pri = np.sqrt(len(validind)) * ABSTOL + RELTOL * max(np.linalg.norm(z),
                                                                         np.linalg.norm(theta.dot(vKlu)))
                eps_dual = np.sqrt(len(validind)) * ABSTOL + RELTOL * np.linalg.norm(delta)
                if r_norm < eps_pri and s_norm < eps_dual:
                    break
def select ( self , label_index , unlabel_index , batch_size = 5 , qp_solver = 'ECOS' , * * kwargs ) : cvxpy = self . _cvxpy assert ( batch_size > 0 ) assert ( isinstance ( unlabel_index , collections . Iterable ) ) assert ( isinstance ( label_index , collections . Iterable ) ) unlabel_index = np . asarray ( unlabel_index ) label_index = np . asarray ( label_index ) if len ( unlabel_index ) <= batch_size : return unlabel_index KLL = self . _K [ np . ix_ ( label_index , label_index ) ] KLU = self . _K [ np . ix_ ( label_index , unlabel_index ) ] KUU = self . _K [ np . ix_ ( unlabel_index , unlabel_index ) ] L_len = len ( label_index ) U_len = len ( unlabel_index ) N = L_len + U_len # precision of ADMM MAX_ITER = 1000 ABSTOL = 1e-4 RELTOL = 1e-2 # train a linear model in kernel form for theta = np . linalg . inv ( KLL + self . _gamma * np . eye ( L_len ) ) . dot ( self . y [ label_index ] ) # start optimization dr_weight = np . ones ( U_len ) # informativeness % representativeness es_weight = np . ones ( U_len ) # easiness last_round_selected = [ ] iter_round = 0 while 1 : iter_round += 1 # solve QP P = 0.5 * self . _mu * KUU pred_of_unlab = theta . dot ( KLU ) a = es_weight * ( pred_of_unlab * pred_of_unlab + 2 * np . abs ( pred_of_unlab ) ) q = self . _mu * ( ( U_len - batch_size ) / N * np . ones ( L_len ) . dot ( KLU ) - ( L_len + batch_size ) / N * np . ones ( U_len ) . dot ( KUU ) ) + a # cvx x = cvxpy . Variable ( U_len ) objective = cvxpy . Minimize ( 0.5 * cvxpy . quad_form ( x , P ) + q . T @ x ) constraints = [ 0 <= x , x <= 1 , es_weight @ x == batch_size ] prob = cvxpy . Problem ( objective , constraints ) # The optimal objective value is returned by `prob.solve()`. # result = prob.solve(solver=cvxpy.OSQP if qp_solver == 'OSQP' else cvxpy.ECOS) try : result = prob . solve ( solver = cvxpy . OSQP if qp_solver == 'OSQP' else cvxpy . ECOS ) except cvxpy . error . DCPError : result = prob . solve ( solver = cvxpy . OSQP if qp_solver == 'OSQP' else cvxpy . ECOS , gp = True ) # Sometimes the constraints can not be satisfied, # thus we relax the constraints to get an approximate solution. if not ( type ( result ) == float and result != float ( 'inf' ) and result != float ( '-inf' ) ) : # P = 0.5 * self._mu * KUU # pred_of_unlab = theta.dot(KLU) # a = es_weight * (pred_of_unlab * pred_of_unlab + 2 * np.abs(pred_of_unlab)) # q = self._mu * ( #     (U_len - batch_size) / N * np.ones(L_len).dot(KLU) - (L_len + batch_size) / N * np.ones(U_len).dot( #         KUU)) + a # cvx x = cvxpy . Variable ( U_len ) objective = cvxpy . Minimize ( 0.5 * cvxpy . quad_form ( x , P ) + q . T @ x ) constraints = [ 0 <= x , x <= 1 ] prob = cvxpy . Problem ( objective , constraints ) # The optimal objective value is returned by `prob.solve()`. try : result = prob . solve ( solver = cvxpy . OSQP if qp_solver == 'OSQP' else cvxpy . ECOS ) except cvxpy . error . DCPError : result = prob . solve ( solver = cvxpy . OSQP if qp_solver == 'OSQP' else cvxpy . ECOS , gp = True ) # The optimal value for x is stored in `x.value`. # print(x.value) dr_weight = np . array ( x . value ) # print(dr_weight) # print(result) if len ( np . shape ( dr_weight ) ) == 2 : dr_weight = dr_weight . T [ 0 ] # end cvx # update easiness weight worst_loss = dr_weight * ( pred_of_unlab * pred_of_unlab + 2 * np . abs ( pred_of_unlab ) ) es_weight = np . zeros ( U_len ) es_weight_tmp = 1 - ( worst_loss / self . _lambda ) update_indices = np . nonzero ( worst_loss < self . _lambda ) [ 0 ] es_weight [ update_indices ] = es_weight_tmp [ update_indices ] # record selected indexes and judge convergence dr_largest = nlargestarg ( dr_weight * es_weight , batch_size ) select_ind = np . asarray ( unlabel_index ) [ dr_largest ] if set ( last_round_selected ) == set ( select_ind ) or iter_round > 15 : return select_ind else : last_round_selected = copy . copy ( select_ind ) # print(dr_largest) # print(dr_weight[dr_largest]) # ADMM optimization process # Filter less important instances for efficiency mix_weight = dr_weight * es_weight mix_weight [ mix_weight < 0 ] = 0 validind = np . nonzero ( mix_weight > 0.001 ) [ 0 ] if len ( validind ) < 1 : validind = nlargestarg ( mix_weight , 1 ) vKlu = KLU [ : , validind ] delta = np . zeros ( len ( validind ) ) # dual variable in ADMM z = theta . dot ( vKlu ) # auxiliary variable in ADMM # pre-computed constants in ADMM A = 2 * KLL . dot ( KLL ) + self . _rho * vKlu . dot ( vKlu . T ) + 2 * self . _gamma * KLL pinvA = np . linalg . pinv ( A ) rz = self . _rho * vKlu rc = 2 * KLL . dot ( self . y [ label_index ] ) kdenom = np . sqrt ( mix_weight [ validind ] + self . _rho / 2 ) ci = mix_weight [ validind ] / kdenom for solver_iter in range ( MAX_ITER ) : # theta update r = rz . dot ( z . T ) + vKlu . dot ( delta ) + rc theta = pinvA . dot ( r ) # z update zold = z vud = self . _rho * theta . dot ( vKlu ) vi = ( vud - delta ) / ( 2 * kdenom ) ztmp = np . abs ( vi ) - ci ztmp [ ztmp < 0 ] = 0 ksi = np . sign ( vi ) * ztmp z = ksi / kdenom # delta update delta += self . _rho * ( z - theta . dot ( vKlu ) ) # judge convergence r_norm = np . linalg . norm ( ( theta . dot ( vKlu ) - z ) ) s_norm = np . linalg . norm ( - self . _rho * ( z - zold ) ) eps_pri = np . sqrt ( len ( validind ) ) * ABSTOL + RELTOL * max ( np . linalg . norm ( z ) , np . linalg . norm ( theta . dot ( vKlu ) ) ) eps_dual = np . sqrt ( len ( validind ) ) * ABSTOL + RELTOL * np . linalg . norm ( delta ) if r_norm < eps_pri and s_norm < eps_dual : break