//  [python]
def NewSmarterSeparate(self, num_samples, args_K, regu):
        """Default mask sampler
        Generates feature mask and node mask independently
        Favours masks with a high weight + smart space allocation algorithm

        Args:
            num_samples (int): number of masks desired 
            args_K (int): maximum size of masks favoured
            regu (binary): nodes or features 

        Returns:
            tensor: dataset of samples
        """
        if regu == None:
            z_ = self.Smarter(num_samples, args_K, regu)
            return z_

        # Favour features - special coalitions don't study node's effect
        elif regu > 0.5:
            M = self.F
            z_ = torch.ones(num_samples, M)
            z_[1::2] = torch.zeros(num_samples//2, M) # case k = 0 
            i = 2
            k = 1
            P = num_samples * 9/10
            while i < P and k <= min(args_K, M-1): 

                # All coalitions of order k can be sampled 
                if i + 2 * scipy.special.comb(M,k) <= P:
                    L = list(combinations(range(M), k))
                    for c in L:
                        z_[i,c] = torch.zeros(k)
                        z_[i+1,c] = torch.ones(k)
                        i += 2
            
                # All coalitions of order k cannot be sampled
                else: 
                    weight = torch.ones(M)
                    L = list(combinations(range(M), k))
                    random.shuffle(L)
                    while i < min(P, len(L)):
                        cw = torch.tensor([sum(weight[list(c)]) for c in L])
                        c_idx = torch.argmax(cw).item()
                        c = list(L[c_idx])
                        p = float(random.randint(0,1))
                        z_[i,:] = torch.tensor(p).repeat(M)
                        z_[i,c] =  torch.tensor(1-p).repeat(len(c))
                        weight[list(c)] = torch.tensor([1/(1+1/el.item()) for el in weight[list(c)]])
                        i += 1
                    k += 1
            
            # Random coal
            z_[i:, :] = torch.empty( max(0, num_samples-i), M).random_(2)

            print(f"random samples: {num_samples-i}")
            return z_

       # Favour features - special coalitions don't study node's effect
        elif regu < 0.5:
            M = self.M - self.F
            z_ = torch.ones(num_samples, M)
            z_[1::2] = torch.zeros(num_samples//2, M) # case k = 0 
            i = 2
            k = 1
            P = int(num_samples * 9/10)
            while i < P and k <= min(args_K, M-1): 

                # All coalitions of order k can be sampled 
                if i + 2 * scipy.special.comb(M,k) <= P:
                    L = list(combinations(range(M), k))
                    for c in L:
                        z_[i,c] = torch.zeros(k)
                        z_[i+1,c] = torch.ones(k)
                        i += 2
                    k += 1
            
                # All coalitions of order k cannot be sampled
                else: 
                    weight = torch.ones(M)
                    L = list(combinations(range(M), k))
                    random.shuffle(L)
                    while i < min(P, len(L)):
                        cw = torch.tensor([sum(weight[list(c)]) for c in L])
                        c_idx = torch.argmax(cw).item()
                        c = list(L[c_idx])
                        p = float(random.randint(0,1))
                        z_[i,:] = torch.tensor(p).repeat(M)
                        z_[i,c] =  torch.tensor(1-p).repeat(len(c))
                        weight[list(c)] = torch.tensor([1/(1+1/el.item()) for el in weight[list(c)]])
                        i += 1
                    k += 1
            
            # Random coal
            z_[i:, :] = torch.empty( max(0, num_samples-i), M).random_(2)
            return z_