//  [python]
def optimize_cluster_labels_via_cut_point_in_the_dual_space(self, f_pq, f_qp, is_max_approx=True, debug=True):

        # it is highly recommended to use max approximation for estimating the divergence function.

        # all computations are done in numpy here.
        # no need for backpropagation, so no tensors

        # f_pq and f_qp are dual function representations (1-D) of data points.
        # for the optimization of cut point in the dual space so the respective cluster labels, raw features are not required.
        # cluster labels are estimated afresh, without the knowledge of cluster labels from the past iteration.

        assert f_pq.ndim == 1
        assert f_qp.ndim == 1

        assert not np.all(np.isnan(f_pq))
        assert not np.all(np.isnan(f_qp))

        def compute_kl_div_for_cluster_opt(z):

            assert z.dtype == np.bool
            if z.sum() in [0, z.size]:
                return -math.inf

            num_ones = z.sum()
            num_zero = z.size - num_ones

            if is_max_approx:
                kl_pq = f_pq[z].mean() - f_pq[~z].max() + math.log(num_zero)
                kl_qp = f_qp[~z].mean() - f_qp[z].max() + math.log(num_ones)
            else:
                kl_pq = f_pq[z].mean() - s.logsumexp(f_pq[~z]) + math.log(num_zero)
                kl_qp = f_qp[~z].mean() - s.logsumexp(f_qp[z]) + math.log(num_ones)
            
            kl_div = kl_pq + kl_qp
            
            return kl_div

        n = f_pq.size
        assert f_qp.size == n

        # this is used for regularizing the optimization of clusters in the dual space, so as not to choose anomalies/outliers as individual clusters.
        min_cluster_size = int(self.min_frac_of_cluster_size*n)

        if debug:
            print(f'min_cluster_size={min_cluster_size}')

        # sorting the input data points as per their dual function values
        sort_idx_pq = f_pq.argsort()
        kl_div_for_cluster_configs_pq = np.zeros(n)
        # optimizing cut point in the dual space
        for j in range(n):
            if (j < min_cluster_size) or (j >= (n-min_cluster_size)):
                kl_div_for_cluster_configs_pq[j] = -math.inf
            else:
                z = np.zeros(n, dtype=np.bool)
                # mean is computed on ones for f_pq, which should be on higher values to keep KL-D positive
                z[sort_idx_pq[j:]] = True
                kl_div_for_cluster_configs_pq[j] = compute_kl_div_for_cluster_opt(z=z)

        # cut point with maximal KL-divergence
        cut_in_sort_idx_pq = kl_div_for_cluster_configs_pq.argmax()
        kl_div_opt_pq = kl_div_for_cluster_configs_pq[cut_in_sort_idx_pq]
        # cluster labels as per the cut point
        labels_opt_pq = np.zeros(n, dtype=np.bool)
        labels_opt_pq[sort_idx_pq[cut_in_sort_idx_pq:]] = True

        if debug:
            plt.close()
            plt.plot(f_pq[sort_idx_pq], kl_div_for_cluster_configs_pq, 'b.')
            plt.xlabel(f'f_pq')
            plt.ylabel('KL-D')
            plt.show()

        cut_in_sort_idx_pq, sort_idx_pq = (None,)*2

        # todo: refactor code to avoid redundancies
        # same as above for the opposite direction of divergence function
        sort_idx_qp = f_qp.argsort()
        kl_div_for_cluster_configs_qp = np.zeros(n)
        for j in range(n):
            if (j < min_cluster_size) or (j >= (n-min_cluster_size)):
                kl_div_for_cluster_configs_qp[j] = -math.inf
            else:
                z = np.zeros(n, dtype=np.bool)
                # ~z is used for KL q -> p
                # mean is computed on zeros for f_qp, which should be on higher values to keep KL-D positive
                z[sort_idx_qp[:j]] = True
                kl_div_for_cluster_configs_qp[j] = compute_kl_div_for_cluster_opt(z=z)
        cut_in_sort_idx_qp = kl_div_for_cluster_configs_qp.argmax()
        kl_div_opt_qp = kl_div_for_cluster_configs_qp[cut_in_sort_idx_qp]
        labels_opt_qp = np.zeros(n, dtype=np.bool)
        labels_opt_qp[sort_idx_qp[:cut_in_sort_idx_qp]] = True

        if debug:
            plt.close()
            plt.plot(f_qp[sort_idx_qp], kl_div_for_cluster_configs_qp, 'r.')
            plt.xlabel(f'f_qp')
            plt.ylabel('KL-D')
            plt.show()

        cut_in_sort_idx_qp, sort_idx_qp = (None,)*2

        if debug and (npr.random() < 0.1):

            plt.close()
            plt.scatter(
                x=f_pq,
                y=f_qp,
                c=labels_opt_pq,
            )
            plt.xlabel(r'$f_{p \to q}$', fontsize=16)
            plt.ylabel(r'$f_{q \to p}$', fontsize=16)
            plt.legend()
            plt.title(f'KLpq={kl_div_opt_pq}')
            plt.show()

            plt.close()
            plt.scatter(
                x=f_pq,
                y=f_qp,
                c=labels_opt_qp,
            )
            plt.xlabel(r'$f_{p \to q}$', fontsize=16)
            plt.ylabel(r'$f_{q \to p}$', fontsize=16)
            plt.legend()
            plt.title(f'KLqp={kl_div_opt_qp}')
            plt.show()

        return labels_opt_pq if (kl_div_opt_pq > kl_div_opt_qp) else labels_opt_qp