{
    "file_diffs": [
        {
            "old_file_content": "import warnings\nfrom unittest.mock import patch\n\nimport numpy as np\nfrom scipy import stats\nfrom scipy import sparse as sp\nimport sklearn.metrics as skl_metrics\nfrom sklearn.utils.extmath import row_norms, safe_sparse_dot\nfrom sklearn.metrics import pairwise_distances\n\nfrom Orange.distance import _distance\nfrom Orange.statistics import util\n\nfrom .base import (Distance, DistanceModel, FittedDistance, FittedDistanceModel,\n                   SklDistance, _orange_to_numpy)\n\n\nclass EuclideanRowsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between rows.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize,\n                 continuous, discrete,\n                 means, stdvars, dist_missing2_cont,\n                 dist_missing_disc, dist_missing2_disc):\n        super().__init__(attributes, 1, impute)\n        self.normalize = normalize\n        self.continuous = continuous\n        self.discrete = discrete\n        self.means = means\n        self.vars = stdvars\n        self.dist_missing2_cont = dist_missing2_cont\n        self.dist_missing_disc = dist_missing_disc\n        self.dist_missing2_disc = dist_missing2_disc\n\n    def compute_distances(self, x1, x2=None):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and then uses `row_norms`\n          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2\n          (the trick from sklearn);\n        - calls a function in Cython that recomputes the distances between pairs\n          of rows that yielded nan\n        - calls a function in Cython that adds the contributions of discrete\n          columns\n        \"\"\"\n        if self.continuous.any():\n            data1, data2 = self.continuous_columns(\n                x1, x2, self.means, np.sqrt(2 * self.vars))\n\n            # adapted from sklearn.metric.euclidean_distances\n            xx = row_norms(data1, squared=True)[:, np.newaxis]\n            if x2 is not None:\n                yy = row_norms(data2, squared=True)[np.newaxis, :]\n            else:\n                yy = xx.T\n            distances = safe_sparse_dot(data1, data2.T, dense_output=True)\n            distances *= -2\n            distances += xx\n            distances += yy\n            with np.errstate(invalid=\"ignore\"):  # Nans are fixed below\n                np.maximum(distances, 0, out=distances)\n            if x2 is None:\n                distances.flat[::distances.shape[0] + 1] = 0.0\n            fixer = _distance.fix_euclidean_rows_normalized if self.normalize \\\n                else _distance.fix_euclidean_rows\n            fixer(distances, data1, data2,\n                  self.means, self.vars, self.dist_missing2_cont,\n                  x2 is not None)\n        else:\n            distances = np.zeros((x1.shape[0],\n                                  (x2 if x2 is not None else x1).shape[0]))\n\n        if np.any(self.discrete):\n            data1, data2 = self.discrete_columns(x1, x2)\n            _distance.euclidean_rows_discrete(\n                distances, data1, data2, self.dist_missing_disc,\n                self.dist_missing2_disc, x2 is not None)\n\n        if x2 is None:\n            _distance.lower_to_symmetric(distances)\n        return np.sqrt(distances)\n\n\nclass EuclideanColumnsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between columns.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize, means, stdvars):\n        super().__init__(attributes, 0, impute)\n        self.normalize = normalize\n        self.means = means\n        self.vars = stdvars\n\n    def compute_distances(self, x1, x2=None):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and then uses `row_norms`\n          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2\n          (the trick from sklearn);\n        - calls a function in Cython that adds the contributions of discrete\n          columns\n        \"\"\"\n        if self.normalize:\n            x1 = x1 - self.means\n            x1 /= np.sqrt(2 * self.vars)\n\n        # adapted from sklearn.metric.euclidean_distances\n        xx = row_norms(x1.T, squared=True)[:, np.newaxis]\n        distances = safe_sparse_dot(x1.T, x1, dense_output=True)\n        distances *= -2\n        distances += xx\n        distances += xx.T\n        with np.errstate(invalid=\"ignore\"):  # Nans are fixed below\n            np.maximum(distances, 0, out=distances)\n        distances.flat[::distances.shape[0] + 1] = 0.0\n\n        fixer = _distance.fix_euclidean_cols_normalized if self.normalize \\\n            else _distance.fix_euclidean_cols\n        fixer(distances, x1, self.means, self.vars)\n        return np.sqrt(distances)\n\n\nclass Euclidean(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = True\n    supports_normalization = True\n    fallback = SklDistance('euclidean')\n    rows_model_type = EuclideanRowsModel\n\n    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):\n        # pylint: disable=arguments-differ\n        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)\n\n    def get_continuous_stats(self, column):\n        \"\"\"\n        Return mean, variance and distance betwwen pairs of missing values\n        for the given columns. The method is called by inherited `fit_rows`\n        to construct a row-distance model\n        \"\"\"\n        mean = util.nanmean(column)\n        var = util.nanvar(column)\n        if self.normalize:\n            if var == 0:\n                return None\n            dist_missing2_cont = 1\n        else:\n            dist_missing2_cont = 2 * var\n            if np.isnan(dist_missing2_cont):\n                dist_missing2_cont = 0\n        return mean, var, dist_missing2_cont\n\n    def fit_cols(self, attributes, x, n_vals):\n        \"\"\"\n        Return `EuclideanColumnsModel` with stored means and variances\n        for normalization and imputation.\n        \"\"\"\n        def nowarn(msg, cat, *args, **kwargs):\n            if cat is RuntimeWarning and msg in (\n                    \"Mean of empty slice\", \"Degrees of freedom <= 0 for slice\"):\n                if self.normalize:\n                    raise ValueError(\"some columns have no defined values\")\n            else:\n                orig_warn(msg, cat, *args, **kwargs)\n\n        self.check_no_discrete(n_vals)\n        # catch_warnings resets the registry for \"once\", while avoiding this\n        # warning would be annoying and slow, hence patching\n        orig_warn = warnings.warn\n        with patch(\"warnings.warn\", new=nowarn):\n            means = np.nanmean(x, axis=0)\n            stdvars = np.nanvar(x, axis=0)\n        if self.normalize and not stdvars.all():\n            raise ValueError(\"some columns are constant\")\n        return EuclideanColumnsModel(\n            attributes, self.impute, self.normalize, means, stdvars)\n\n\nclass ManhattanRowsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between rows.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize,\n                 continuous, discrete,\n                 medians, mads, dist_missing2_cont,\n                 dist_missing_disc, dist_missing2_disc):\n        super().__init__(attributes, 1, impute)\n        self.normalize = normalize\n        self.continuous = continuous\n        self.discrete = discrete\n        self.medians = medians\n        self.mads = mads\n        self.dist_missing2_cont = dist_missing2_cont\n        self.dist_missing_disc = dist_missing_disc\n        self.dist_missing2_disc = dist_missing2_disc\n\n    def compute_distances(self, x1, x2):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and computes distances\n          ignoring the possibility of nans\n        - recomputes the distances between pairs of rows that yielded nans\n        - adds the contributions of discrete columns using the same function as\n          the Euclidean distance\n        \"\"\"\n        if self.continuous.any():\n            data1, data2 = self.continuous_columns(\n                x1, x2, self.medians, 2 * self.mads)\n            distances = _distance.manhattan_rows_cont(\n                data1, data2, x2 is not None)\n            if self.normalize:\n                _distance.fix_manhattan_rows_normalized(\n                    distances, data1, data2, x2 is not None)\n            else:\n                _distance.fix_manhattan_rows(\n                    distances, data1, data2,\n                    self.medians, self.mads, self.dist_missing2_cont,\n                    x2 is not None)\n        else:\n            distances = np.zeros((x1.shape[0],\n                                  (x2 if x2 is not None else x1).shape[0]))\n\n        if np.any(self.discrete):\n            data1, data2 = self.discrete_columns(x1, x2)\n            # For discrete attributes, Euclidean is same as Manhattan\n            _distance.euclidean_rows_discrete(\n                distances, data1, data2, self.dist_missing_disc,\n                self.dist_missing2_disc, x2 is not None)\n\n        if x2 is None:\n            _distance.lower_to_symmetric(distances)\n        return distances\n\n\nclass ManhattanColumnsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Manhattan distances between columns.\n\n    Medians are used as offsets for normalization, and two MADS are\n    used for scaling.\n    \"\"\"\n\n    def __init__(self, attributes, impute, normalize, medians, mads):\n        super().__init__(attributes, 0, impute)\n        self.normalize = normalize\n        self.medians = medians\n        self.mads = mads\n\n    def compute_distances(self, x1, x2=None):\n        if self.normalize:\n            x1 = x1 - self.medians\n            x1 /= 2\n            x1 /= self.mads\n        return _distance.manhattan_cols(x1, self.medians, self.mads, self.normalize)\n\n\nclass Manhattan(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = True\n    supports_normalization = True\n    fallback = SklDistance('manhattan')\n    rows_model_type = ManhattanRowsModel\n\n    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):\n        # pylint: disable=arguments-differ\n        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)\n\n    def get_continuous_stats(self, column):\n        \"\"\"\n        Return median, MAD and distance betwwen pairs of missing values\n        for the given columns. The method is called by inherited `fit_rows`\n        to construct a row-distance model\n        \"\"\"\n        median = np.nanmedian(column)\n        mad = np.nanmedian(np.abs(column - median))\n        if self.normalize:\n            if mad == 0:\n                return None\n            dist_missing2_cont = 1\n        else:\n            dist_missing2_cont = 2 * mad\n            if np.isnan(dist_missing2_cont):\n                dist_missing2_cont = 0\n        return median, mad, dist_missing2_cont\n\n    def fit_cols(self, attributes, x, n_vals):\n        \"\"\"\n        Return `ManhattanColumnsModel` with stored medians and MADs\n        for normalization and imputation.\n        \"\"\"\n        self.check_no_discrete(n_vals)\n        if x.size == 0:\n            medians = np.zeros(len(x))\n            mads = np.zeros(len(x))\n        else:\n            medians = np.nanmedian(x, axis=0)\n            mads = np.nanmedian(np.abs(x - medians), axis=0)\n        if self.normalize and (np.isnan(mads).any() or not mads.all()):\n            raise ValueError(\n                \"some columns have zero absolute distance from median, \"\n                \"or no values\")\n        return ManhattanColumnsModel(\n            attributes, self.impute, self.normalize, medians, mads)\n\n\nclass Cosine(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = False\n    fallback = SklDistance('cosine')\n\n    @staticmethod\n    def discrete_to_indicators(x, discrete):\n        \"\"\"Change non-zero values of discrete attributes to 1.\"\"\"\n        if discrete.any():\n            x = x.copy()\n            for col, disc in enumerate(discrete):\n                if disc:\n                    x[:, col].clip(0, 1, out=x[:, col])\n        return x\n\n    def fit_rows(self, attributes, x, n_vals):\n        \"\"\"Return a model for cosine distances with stored means for imputation\n        \"\"\"\n        discrete = n_vals > 0\n        x = self.discrete_to_indicators(x, discrete)\n        means = util.nanmean(x, axis=0)\n        means = np.nan_to_num(means)\n        return self.CosineModel(attributes, self.axis, self.impute,\n                                discrete, means)\n\n    fit_cols = fit_rows\n\n    def get_continuous_stats(self, column):\n        # Implement an unneeded abstract method to silence pylint\n        return None\n\n    class CosineModel(FittedDistanceModel):\n        \"\"\"Model for computation of cosine distances across rows and columns.\n        All non-zero discrete values are treated as 1.\"\"\"\n        def __init__(self, attributes, axis, impute, discrete, means):\n            super().__init__(attributes, axis, impute)\n            self.discrete = discrete\n            self.means = means\n\n        def compute_distances(self, x1, x2):\n            \"\"\"\n            The method imputes the missing values as means and calls\n            safe_sparse_dot. Imputation simplifies computation at a cost of\n            (theoretically) slightly wrong distance between pairs of missing\n             values.\n            \"\"\"\n\n            def prepare_data(x):\n                if self.discrete.any():\n                    data = Cosine.discrete_to_indicators(x, self.discrete)\n                else:\n                    data = x.copy()\n                for col, mean in enumerate(self.means):\n                    column = data[:, col]\n                    column[np.isnan(column)] = mean\n                if self.axis == 0:\n                    data = data.T\n                data /= row_norms(data)[:, np.newaxis]\n                return data\n\n            data1 = prepare_data(x1)\n            data2 = data1 if x2 is None else prepare_data(x2)\n            dist = safe_sparse_dot(data1, data2.T)\n            np.clip(dist, -1, 1, out=dist)\n            if x2 is None:\n                diag = np.diag_indices_from(dist)\n                dist[diag] = np.where(np.isnan(dist[diag]), np.nan, 1.0)\n            return 1 - dist\n\n\nclass JaccardModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of cosine distances across rows and columns.\n    All non-zero values are treated as 1.\n    \"\"\"\n    def __init__(self, attributes, axis, impute, ps):\n        super().__init__(attributes, axis, impute)\n        self.ps = ps\n\n    def compute_distances(self, x1, x2):\n        if sp.issparse(x1):\n            return self._compute_sparse(x1, x2)\n        else:\n            return self._compute_dense(x1, x2)\n\n    def _compute_dense(self, x1, x2):\n        \"\"\"\n        The method uses a function implemented in Cython. Data (`x1` and `x2`)\n        is accompanied by two tables. One is a 2-d table in which elements of\n        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector\n        indicating rows (or column) with nan values.\n\n        The function in Cython uses a fast loop without any conditions to\n        compute distances between rows without missing values, and a slower\n        loop for those with missing values.\n        \"\"\"\n        # view is false positive, pylint: disable=no-member\n        nonzeros1 = np.not_equal(x1, 0).view(np.int8)\n        if self.axis == 1:\n            nans1 = _distance.any_nan_row(x1)\n            if x2 is None:\n                nonzeros2, nans2 = nonzeros1, nans1\n            else:\n                nonzeros2 = np.not_equal(x2, 0).view(np.int8)\n                nans2 = _distance.any_nan_row(x2)\n            return _distance.jaccard_rows(\n                nonzeros1, nonzeros2,\n                x1, x1 if x2 is None else x2,\n                nans1, nans2,\n                self.ps,\n                x2 is not None)\n        else:\n            nans1 = _distance.any_nan_row(x1.T)\n            return _distance.jaccard_cols(\n                nonzeros1, x1, nans1, self.ps)\n\n    @staticmethod\n    def _compute_sparse(x1, x2=None):\n        symmetric = x2 is None\n        if symmetric:\n            x2 = x1\n        x1 = sp.csr_matrix(x1)\n        x1.eliminate_zeros()\n        x2 = sp.csr_matrix(x2)\n        x2.eliminate_zeros()\n        n, m = x1.shape[0], x2.shape[0]\n        matrix = np.zeros((n, m))\n        for i in range(n):\n            xi_ind = set(x1[i].indices)\n            for j in range(i if symmetric else m):\n                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\\\n                           / len(set(x1[i].indices).union(x1[j].indices))\n                matrix[i, j] = jacc\n                if symmetric:\n                    matrix[j, i] = jacc\n        return matrix\n\n\nclass Jaccard(FittedDistance):\n    supports_sparse = True\n    supports_discrete = True\n    ModelType = JaccardModel\n\n    def fit_rows(self, attributes, x, n_vals):\n        \"\"\"\n        Return a model for computation of Jaccard values. The model stores\n        frequencies of non-zero values per each column.\n        \"\"\"\n        if sp.issparse(x):\n            ps = x.getnnz(axis=0)\n        else:\n            ps = np.fromiter(\n                (_distance.p_nonzero(x[:, col]) for col in range(len(n_vals))),\n                dtype=np.double, count=len(n_vals))\n        return JaccardModel(attributes, self.axis, self.impute, ps)\n\n    fit_cols = fit_rows\n\n    def get_continuous_stats(self, column):\n        # Implement an unneeded abstract method to silence pylint\n        return None\n\n\nclass CorrelationDistanceModel(DistanceModel):\n    \"\"\"Helper class for normal and absolute Pearson and Spearman correlation\"\"\"\n    def __init__(self, absolute, axis=1, impute=False):\n        super().__init__(axis, impute)\n        self.absolute = absolute\n\n    def compute_distances(self, x1, x2):\n        rho = self.compute_correlation(x1, x2)\n        if self.absolute:\n            return (1. - np.abs(rho)) / 2.\n        else:\n            return (1. - rho) / 2.\n\n    def compute_correlation(self, x1, x2):\n        raise NotImplementedError()\n\n\nclass SpearmanModel(CorrelationDistanceModel):\n    def compute_correlation(self, x1, x2):\n        if x2 is None:\n            n1 = x1.shape[1 - self.axis]\n            if n1 == 1:\n                rho = 1.0\n            elif n1 == 2:\n                # Special case to properly fill degenerate self correlations\n                # (nan, inf on the diagonals)\n                rho = stats.spearmanr(x1, x1, axis=self.axis)[0]\n                assert rho.shape == (4, 4)\n                rho = rho[:2, :2].copy()\n            else:\n                # scalar if n1 == 1\n                rho = stats.spearmanr(x1, axis=self.axis)[0]\n            return np.atleast_2d(rho)\n        else:\n            return _spearmanr2(x1, x2, axis=self.axis)\n\n\ndef _spearmanr2(a, b, axis=0):\n    \"\"\"\n    Compute all pairwise spearman rank moment correlations between rows\n    or columns of a and b\n\n    Parameters\n    ----------\n    a : (N, M) numpy.ndarray\n        The input cases a.\n    b : (J, K) numpy.ndarray\n        The input cases b. In case of axis == 0: J must equal N;\n        otherwise if axis == 1 then K must equal M.\n    axis : int\n        If 0 the correlation are computed between a and b's columns.\n        Otherwise if 1 the correlations are computed between rows.\n\n    Returns\n    -------\n    cor : (N, J) or (M, K) nd.array\n        If axis == 0 then (N, J) matrix of correlations between a x b columns\n        else a (N, J) matrix of correlations between a x b rows.\n\n    See Also\n    --------\n    scipy.stats.spearmanr\n    \"\"\"\n    a, b = np.atleast_2d(a, b)\n    assert a.shape[axis] == b.shape[axis]\n    ar = np.apply_along_axis(stats.rankdata, axis, a)\n    br = np.apply_along_axis(stats.rankdata, axis, b)\n\n    return _corrcoef2(ar, br, axis=axis)\n\n\ndef _corrcoef2(a, b, axis=0):\n    \"\"\"\n    Compute all pairwise Pearson product-moment correlation coefficients\n    between rows or columns of a and b\n\n    Parameters\n    ----------\n    a : (N, M) numpy.ndarray\n        The input cases a.\n    b : (J, K) numpy.ndarray\n        The input cases b. In case of axis == 0: J must equal N;\n        otherwise if axis == 1 then K must equal M.\n    axis : int\n        If 0 the correlation are computed between a and b's columns.\n        Otherwise if 1 the correlations are computed between rows.\n\n    Returns\n    -------\n    cor : (N, J) or (M, K) nd.array\n        If axis == 0 then (N, J) matrix of correlations between a x b columns\n        else a (N, J) matrix of correlations between a x b rows.\n\n    See Also\n    --------\n    numpy.corrcoef\n    \"\"\"\n    a, b = np.atleast_2d(a, b)\n    if axis not in (0, 1):\n        raise ValueError(\"Invalid axis {} (only 0 or 1 accepted)\".format(axis))\n\n    mean_a = np.mean(a, axis=axis, keepdims=True)\n    mean_b = np.mean(b, axis=axis, keepdims=True)\n    assert a.shape[axis] == b.shape[axis]\n\n    n = a.shape[1 - axis]\n    m = b.shape[1 - axis]\n\n    a = a - mean_a\n    b = b - mean_b\n\n    if axis == 0:\n        C = a.T.dot(b)\n        assert C.shape == (n, m)\n    elif axis == 1:\n        C = a.dot(b.T)\n        assert C.shape == (n, m)\n\n    ss_a = np.sum(a ** 2, axis=axis, keepdims=True)\n    ss_b = np.sum(b ** 2, axis=axis, keepdims=True)\n\n    if axis == 0:\n        ss_a = ss_a.T\n    else:\n        ss_b = ss_b.T\n\n    assert ss_a.shape == (n, 1)\n    assert ss_b.shape == (1, m)\n    C /= np.sqrt(ss_a)\n    C /= np.sqrt(ss_b)\n    return C\n\n\nclass CorrelationDistance(Distance):\n    # pylint: disable=abstract-method\n    supports_missing = False\n\n\nclass SpearmanR(CorrelationDistance):\n    def fit(self, _):\n        return SpearmanModel(False, self.axis, self.impute)\n\n\nclass SpearmanRAbsolute(CorrelationDistance):\n    def fit(self, _):\n        return SpearmanModel(True, self.axis, self.impute)\n\n\nclass PearsonModel(CorrelationDistanceModel):\n    def compute_correlation(self, x1, x2):\n        if x2 is None:\n            c = np.corrcoef(x1, rowvar=self.axis == 1)\n            return np.atleast_2d(c)\n        else:\n            return _corrcoef2(x1, x2, axis=self.axis)\n\n\nclass PearsonR(CorrelationDistance):\n    def fit(self, _):\n        return PearsonModel(False, self.axis, self.impute)\n\n\nclass PearsonRAbsolute(CorrelationDistance):\n    def fit(self, _):\n        return PearsonModel(True, self.axis, self.impute)\n\n\nclass Mahalanobis(Distance):\n    supports_sparse = False\n    supports_missing = False\n\n    def fit(self, data):\n        \"\"\"Return a model with stored inverse covariance matrix\"\"\"\n        x = _orange_to_numpy(data)\n        if self.axis == 0:\n            x = x.T\n        try:\n            c = np.cov(x.T)\n        except:\n            raise MemoryError(\"Covariance matrix is too large.\")\n        try:\n            vi = np.linalg.inv(c)\n        except:\n            raise ValueError(\"Computation of inverse covariance matrix failed.\")\n        return MahalanobisModel(self.axis, self.impute, vi)\n\n\nclass MahalanobisModel(DistanceModel):\n    def __init__(self, axis, impute, vi):\n        super().__init__(axis, impute)\n        self.vi = vi\n\n    def __call__(self, e1, e2=None, impute=None):\n        # argument `impute` is here just for backward compatibility; don't use\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2):\n        if self.axis == 0:\n            x1 = x1.T\n            if x2 is not None:\n                x2 = x2.T\n        if x1.shape[1] != self.vi.shape[0] or \\\n                x2 is not None and x2.shape[1] != self.vi.shape[0]:\n            raise ValueError('Incorrect number of features.')\n        return skl_metrics.pairwise.pairwise_distances(\n            x1, x2, metric='mahalanobis', VI=self.vi)\n\n\n# TODO: Appears to have been used only in the Distances widget (where it had\n# to be handled as a special case and is now replaced with the above class)\n# and in tests. Remove?\nclass MahalanobisDistance:\n    \"\"\"\n    Obsolete class needed for backward compatibility.\n\n    Previous implementation of instances did not have a separate fitting phase,\n    except for MahalanobisDistance, which was implemented in a single class\n    but required first (explicitly) calling the method 'fit'. The backward\n    compatibility hack in :obj:`Distance` cannot handle such use, hence it\n    is provided in this class.\n    \"\"\"\n    def __new__(cls, data=None, axis=1, _='Mahalanobis'):\n        if data is None:\n            return cls\n        return Mahalanobis(axis=axis).fit(data)\n\nclass Hamming(Distance):\n    supports_sparse = False\n    supports_missing = False\n    supports_normalization = False\n    supports_discrete = True\n\n    def fit(self, data):\n        x = _orange_to_numpy(data)\n        if self.axis == 0:\n            return HammingColumnsModel(self.axis, self.impute, x)\n        else:\n            return HammingRowsModel(self.axis, self.impute, x)\n\nclass HammingColumnsModel(DistanceModel):\n    \"\"\"\n    Model for computation of Hamming distances between columns.\n    \"\"\"\n    def __init__(self, axis, impute, x):\n        super().__init__(axis, impute)\n        self.x = x\n\n    def __call__(self, e1, e2=None, impute=None):\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2=None):\n        return pairwise_distances(x1.T, metric='hamming')\n\nclass HammingRowsModel(DistanceModel):\n    \"\"\"\n    Model for computation of Hamming distances between rows.\n    \"\"\"\n    def __init__(self, axis, impute, x):\n        super().__init__(axis, impute)\n        self.x = x\n\n    def __call__(self, e1, e2=None, impute=None):\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2=None):\n        return pairwise_distances(x1, metric='hamming')\n",
            "new_file_content": "import warnings\nfrom unittest.mock import patch\n\nimport numpy as np\nfrom scipy import stats\nfrom scipy import sparse as sp\nimport sklearn.metrics as skl_metrics\nfrom sklearn.utils.extmath import row_norms, safe_sparse_dot\nfrom sklearn.metrics import pairwise_distances\n\nfrom Orange.distance import _distance\nfrom Orange.statistics import util\n\nfrom .base import (Distance, DistanceModel, FittedDistance, FittedDistanceModel,\n                   SklDistance, _orange_to_numpy)\n\n\nclass EuclideanRowsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between rows.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize,\n                 continuous, discrete,\n                 means, stdvars, dist_missing2_cont,\n                 dist_missing_disc, dist_missing2_disc):\n        super().__init__(attributes, 1, impute)\n        self.normalize = normalize\n        self.continuous = continuous\n        self.discrete = discrete\n        self.means = means\n        self.vars = stdvars\n        self.dist_missing2_cont = dist_missing2_cont\n        self.dist_missing_disc = dist_missing_disc\n        self.dist_missing2_disc = dist_missing2_disc\n\n    def compute_distances(self, x1, x2=None):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and then uses `row_norms`\n          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2\n          (the trick from sklearn);\n        - calls a function in Cython that recomputes the distances between pairs\n          of rows that yielded nan\n        - calls a function in Cython that adds the contributions of discrete\n          columns\n        \"\"\"\n        if self.continuous.any():\n            data1, data2 = self.continuous_columns(\n                x1, x2, self.means, np.sqrt(2 * self.vars))\n\n            # adapted from sklearn.metric.euclidean_distances\n            xx = row_norms(data1, squared=True)[:, np.newaxis]\n            if x2 is not None:\n                yy = row_norms(data2, squared=True)[np.newaxis, :]\n            else:\n                yy = xx.T\n            distances = safe_sparse_dot(data1, data2.T, dense_output=True)\n            distances *= -2\n            distances += xx\n            distances += yy\n            with np.errstate(invalid=\"ignore\"):  # Nans are fixed below\n                np.maximum(distances, 0, out=distances)\n            if x2 is None:\n                distances.flat[::distances.shape[0] + 1] = 0.0\n            fixer = _distance.fix_euclidean_rows_normalized if self.normalize \\\n                else _distance.fix_euclidean_rows\n            fixer(distances, data1, data2,\n                  self.means, self.vars, self.dist_missing2_cont,\n                  x2 is not None)\n        else:\n            distances = np.zeros((x1.shape[0],\n                                  (x2 if x2 is not None else x1).shape[0]))\n\n        if np.any(self.discrete):\n            data1, data2 = self.discrete_columns(x1, x2)\n            _distance.euclidean_rows_discrete(\n                distances, data1, data2, self.dist_missing_disc,\n                self.dist_missing2_disc, x2 is not None)\n\n        if x2 is None:\n            _distance.lower_to_symmetric(distances)\n        return np.sqrt(distances)\n\n\nclass EuclideanColumnsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between columns.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize, means, stdvars):\n        super().__init__(attributes, 0, impute)\n        self.normalize = normalize\n        self.means = means\n        self.vars = stdvars\n\n    def compute_distances(self, x1, x2=None):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and then uses `row_norms`\n          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2\n          (the trick from sklearn);\n        - calls a function in Cython that adds the contributions of discrete\n          columns\n        \"\"\"\n        if self.normalize:\n            x1 = x1 - self.means\n            x1 /= np.sqrt(2 * self.vars)\n\n        # adapted from sklearn.metric.euclidean_distances\n        xx = row_norms(x1.T, squared=True)[:, np.newaxis]\n        distances = safe_sparse_dot(x1.T, x1, dense_output=True)\n        distances *= -2\n        distances += xx\n        distances += xx.T\n        with np.errstate(invalid=\"ignore\"):  # Nans are fixed below\n            np.maximum(distances, 0, out=distances)\n        distances.flat[::distances.shape[0] + 1] = 0.0\n\n        fixer = _distance.fix_euclidean_cols_normalized if self.normalize \\\n            else _distance.fix_euclidean_cols\n        fixer(distances, x1, self.means, self.vars)\n        return np.sqrt(distances)\n\n\nclass Euclidean(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = True\n    supports_normalization = True\n    fallback = SklDistance('euclidean')\n    rows_model_type = EuclideanRowsModel\n\n    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):\n        # pylint: disable=arguments-differ\n        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)\n\n    def get_continuous_stats(self, column):\n        \"\"\"\n        Return mean, variance and distance betwwen pairs of missing values\n        for the given columns. The method is called by inherited `fit_rows`\n        to construct a row-distance model\n        \"\"\"\n        mean = util.nanmean(column)\n        var = util.nanvar(column)\n        if self.normalize:\n            if var == 0:\n                return None\n            dist_missing2_cont = 1\n        else:\n            dist_missing2_cont = 2 * var\n            if np.isnan(dist_missing2_cont):\n                dist_missing2_cont = 0\n        return mean, var, dist_missing2_cont\n\n    def fit_cols(self, attributes, x, n_vals):\n        \"\"\"\n        Return `EuclideanColumnsModel` with stored means and variances\n        for normalization and imputation.\n        \"\"\"\n        def nowarn(msg, cat, *args, **kwargs):\n            if cat is RuntimeWarning and msg in (\n                    \"Mean of empty slice\", \"Degrees of freedom <= 0 for slice\"):\n                if self.normalize:\n                    raise ValueError(\"some columns have no defined values\")\n            else:\n                orig_warn(msg, cat, *args, **kwargs)\n\n        self.check_no_discrete(n_vals)\n        # catch_warnings resets the registry for \"once\", while avoiding this\n        # warning would be annoying and slow, hence patching\n        orig_warn = warnings.warn\n        with patch(\"warnings.warn\", new=nowarn):\n            means = np.nanmean(x, axis=0)\n            stdvars = np.nanvar(x, axis=0)\n        if self.normalize and not stdvars.all():\n            raise ValueError(\"some columns are constant\")\n        return EuclideanColumnsModel(\n            attributes, self.impute, self.normalize, means, stdvars)\n\n\nclass ManhattanRowsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between rows.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize,\n                 continuous, discrete,\n                 medians, mads, dist_missing2_cont,\n                 dist_missing_disc, dist_missing2_disc):\n        super().__init__(attributes, 1, impute)\n        self.normalize = normalize\n        self.continuous = continuous\n        self.discrete = discrete\n        self.medians = medians\n        self.mads = mads\n        self.dist_missing2_cont = dist_missing2_cont\n        self.dist_missing_disc = dist_missing_disc\n        self.dist_missing2_disc = dist_missing2_disc\n\n    def compute_distances(self, x1, x2):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and computes distances\n          ignoring the possibility of nans\n        - recomputes the distances between pairs of rows that yielded nans\n        - adds the contributions of discrete columns using the same function as\n          the Euclidean distance\n        \"\"\"\n        if self.continuous.any():\n            data1, data2 = self.continuous_columns(\n                x1, x2, self.medians, 2 * self.mads)\n            distances = _distance.manhattan_rows_cont(\n                data1, data2, x2 is not None)\n            if self.normalize:\n                _distance.fix_manhattan_rows_normalized(\n                    distances, data1, data2, x2 is not None)\n            else:\n                _distance.fix_manhattan_rows(\n                    distances, data1, data2,\n                    self.medians, self.mads, self.dist_missing2_cont,\n                    x2 is not None)\n        else:\n            distances = np.zeros((x1.shape[0],\n                                  (x2 if x2 is not None else x1).shape[0]))\n\n        if np.any(self.discrete):\n            data1, data2 = self.discrete_columns(x1, x2)\n            # For discrete attributes, Euclidean is same as Manhattan\n            _distance.euclidean_rows_discrete(\n                distances, data1, data2, self.dist_missing_disc,\n                self.dist_missing2_disc, x2 is not None)\n\n        if x2 is None:\n            _distance.lower_to_symmetric(distances)\n        return distances\n\n\nclass ManhattanColumnsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Manhattan distances between columns.\n\n    Medians are used as offsets for normalization, and two MADS are\n    used for scaling.\n    \"\"\"\n\n    def __init__(self, attributes, impute, normalize, medians, mads):\n        super().__init__(attributes, 0, impute)\n        self.normalize = normalize\n        self.medians = medians\n        self.mads = mads\n\n    def compute_distances(self, x1, x2=None):\n        if self.normalize:\n            x1 = x1 - self.medians\n            x1 /= 2\n            x1 /= self.mads\n        return _distance.manhattan_cols(x1, self.medians, self.mads, self.normalize)\n\n\nclass Manhattan(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = True\n    supports_normalization = True\n    fallback = SklDistance('manhattan')\n    rows_model_type = ManhattanRowsModel\n\n    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):\n        # pylint: disable=arguments-differ\n        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)\n\n    def get_continuous_stats(self, column):\n        \"\"\"\n        Return median, MAD and distance betwwen pairs of missing values\n        for the given columns. The method is called by inherited `fit_rows`\n        to construct a row-distance model\n        \"\"\"\n        median = np.nanmedian(column)\n        mad = np.nanmedian(np.abs(column - median))\n        if self.normalize:\n            if mad == 0:\n                return None\n            dist_missing2_cont = 1\n        else:\n            dist_missing2_cont = 2 * mad\n            if np.isnan(dist_missing2_cont):\n                dist_missing2_cont = 0\n        return median, mad, dist_missing2_cont\n\n    def fit_cols(self, attributes, x, n_vals):\n        \"\"\"\n        Return `ManhattanColumnsModel` with stored medians and MADs\n        for normalization and imputation.\n        \"\"\"\n        self.check_no_discrete(n_vals)\n        if x.size == 0:\n            medians = np.zeros(len(x))\n            mads = np.zeros(len(x))\n        else:\n            medians = np.nanmedian(x, axis=0)\n            mads = np.nanmedian(np.abs(x - medians), axis=0)\n        if self.normalize and (np.isnan(mads).any() or not mads.all()):\n            raise ValueError(\n                \"some columns have zero absolute distance from median, \"\n                \"or no values\")\n        return ManhattanColumnsModel(\n            attributes, self.impute, self.normalize, medians, mads)\n\n\nclass Cosine(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = False\n    fallback = SklDistance('cosine')\n\n    @staticmethod\n    def discrete_to_indicators(x, discrete):\n        \"\"\"Change non-zero values of discrete attributes to 1.\"\"\"\n        if discrete.any():\n            x = x.copy()\n            for col, disc in enumerate(discrete):\n                if disc:\n                    x[:, col].clip(0, 1, out=x[:, col])\n        return x\n\n    def fit_rows(self, attributes, x, n_vals):\n        \"\"\"Return a model for cosine distances with stored means for imputation\n        \"\"\"\n        discrete = n_vals > 0\n        x = self.discrete_to_indicators(x, discrete)\n        means = util.nanmean(x, axis=0)\n        means = np.nan_to_num(means)\n        return self.CosineModel(attributes, self.axis, self.impute,\n                                discrete, means)\n\n    fit_cols = fit_rows\n\n    def get_continuous_stats(self, column):\n        # Implement an unneeded abstract method to silence pylint\n        return None\n\n    class CosineModel(FittedDistanceModel):\n        \"\"\"Model for computation of cosine distances across rows and columns.\n        All non-zero discrete values are treated as 1.\"\"\"\n        def __init__(self, attributes, axis, impute, discrete, means):\n            super().__init__(attributes, axis, impute)\n            self.discrete = discrete\n            self.means = means\n\n        def compute_distances(self, x1, x2):\n            \"\"\"\n            The method imputes the missing values as means and calls\n            safe_sparse_dot. Imputation simplifies computation at a cost of\n            (theoretically) slightly wrong distance between pairs of missing\n             values.\n            \"\"\"\n\n            def prepare_data(x):\n                if self.discrete.any():\n                    data = Cosine.discrete_to_indicators(x, self.discrete)\n                else:\n                    data = x.copy()\n                for col, mean in enumerate(self.means):\n                    column = data[:, col]\n                    column[np.isnan(column)] = mean\n                if self.axis == 0:\n                    data = data.T\n                data /= row_norms(data)[:, np.newaxis]\n                return data\n\n            data1 = prepare_data(x1)\n            data2 = data1 if x2 is None else prepare_data(x2)\n            dist = safe_sparse_dot(data1, data2.T)\n            np.clip(dist, -1, 1, out=dist)\n            if x2 is None:\n                diag = np.diag_indices_from(dist)\n                dist[diag] = np.where(np.isnan(dist[diag]), np.nan, 1.0)\n            return 1 - dist\n\n\nclass JaccardModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of cosine distances across rows and columns.\n    All non-zero values are treated as 1.\n    \"\"\"\n    def __init__(self, attributes, axis, impute, ps):\n        super().__init__(attributes, axis, impute)\n        self.ps = ps\n\n    def compute_distances(self, x1, x2):\n        if sp.issparse(x1):\n            return self._compute_sparse(x1, x2)\n        else:\n            return self._compute_dense(x1, x2)\n\n    def _compute_dense(self, x1, x2):\n        \"\"\"\n        The method uses a function implemented in Cython. Data (`x1` and `x2`)\n        is accompanied by two tables. One is a 2-d table in which elements of\n        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector\n        indicating rows (or column) with nan values.\n\n        The function in Cython uses a fast loop without any conditions to\n        compute distances between rows without missing values, and a slower\n        loop for those with missing values.\n        \"\"\"\n        # view is false positive, pylint: disable=no-member\n        nonzeros1 = np.not_equal(x1, 0).view(np.int8)\n        if self.axis == 1:\n            nans1 = _distance.any_nan_row(x1)\n            if x2 is None:\n                nonzeros2, nans2 = nonzeros1, nans1\n            else:\n                nonzeros2 = np.not_equal(x2, 0).view(np.int8)\n                nans2 = _distance.any_nan_row(x2)\n            return _distance.jaccard_rows(\n                nonzeros1, nonzeros2,\n                x1, x1 if x2 is None else x2,\n                nans1, nans2,\n                self.ps,\n                x2 is not None)\n        else:\n            nans1 = _distance.any_nan_row(x1.T)\n            return _distance.jaccard_cols(\n                nonzeros1, x1, nans1, self.ps)\n\n    @staticmethod\n    def _compute_sparse(x1, x2=None):\n        symmetric = x2 is None\n        if symmetric:\n            x2 = x1\n        x1 = sp.csr_matrix(x1)\n        x1.eliminate_zeros()\n        x2 = sp.csr_matrix(x2)\n        x2.eliminate_zeros()\n        n, m = x1.shape[0], x2.shape[0]\n        matrix = np.zeros((n, m))\n        for i in range(n):\n            xi_ind = set(x1[i].indices)\n            for j in range(i if symmetric else m):\n                union = len(xi_ind.union(x2[j].indices))\n                if union:\n                    jacc = 1 - len(xi_ind.intersection(x2[j].indices)) / union\n                else:\n                    jacc = 0\n                matrix[i, j] = jacc\n                if symmetric:\n                    matrix[j, i] = jacc\n        return matrix\n\n\nclass Jaccard(FittedDistance):\n    supports_sparse = True\n    supports_discrete = True\n    ModelType = JaccardModel\n\n    def fit_rows(self, attributes, x, n_vals):\n        \"\"\"\n        Return a model for computation of Jaccard values. The model stores\n        frequencies of non-zero values per each column.\n        \"\"\"\n        if sp.issparse(x):\n            ps = x.getnnz(axis=0)\n        else:\n            ps = np.fromiter(\n                (_distance.p_nonzero(x[:, col]) for col in range(len(n_vals))),\n                dtype=np.double, count=len(n_vals))\n        return JaccardModel(attributes, self.axis, self.impute, ps)\n\n    fit_cols = fit_rows\n\n    def get_continuous_stats(self, column):\n        # Implement an unneeded abstract method to silence pylint\n        return None\n\n\nclass CorrelationDistanceModel(DistanceModel):\n    \"\"\"Helper class for normal and absolute Pearson and Spearman correlation\"\"\"\n    def __init__(self, absolute, axis=1, impute=False):\n        super().__init__(axis, impute)\n        self.absolute = absolute\n\n    def compute_distances(self, x1, x2):\n        rho = self.compute_correlation(x1, x2)\n        if self.absolute:\n            return (1. - np.abs(rho)) / 2.\n        else:\n            return (1. - rho) / 2.\n\n    def compute_correlation(self, x1, x2):\n        raise NotImplementedError()\n\n\nclass SpearmanModel(CorrelationDistanceModel):\n    def compute_correlation(self, x1, x2):\n        if x2 is None:\n            n1 = x1.shape[1 - self.axis]\n            if n1 == 1:\n                rho = 1.0\n            elif n1 == 2:\n                # Special case to properly fill degenerate self correlations\n                # (nan, inf on the diagonals)\n                rho = stats.spearmanr(x1, x1, axis=self.axis)[0]\n                assert rho.shape == (4, 4)\n                rho = rho[:2, :2].copy()\n            else:\n                # scalar if n1 == 1\n                rho = stats.spearmanr(x1, axis=self.axis)[0]\n            return np.atleast_2d(rho)\n        else:\n            return _spearmanr2(x1, x2, axis=self.axis)\n\n\ndef _spearmanr2(a, b, axis=0):\n    \"\"\"\n    Compute all pairwise spearman rank moment correlations between rows\n    or columns of a and b\n\n    Parameters\n    ----------\n    a : (N, M) numpy.ndarray\n        The input cases a.\n    b : (J, K) numpy.ndarray\n        The input cases b. In case of axis == 0: J must equal N;\n        otherwise if axis == 1 then K must equal M.\n    axis : int\n        If 0 the correlation are computed between a and b's columns.\n        Otherwise if 1 the correlations are computed between rows.\n\n    Returns\n    -------\n    cor : (N, J) or (M, K) nd.array\n        If axis == 0 then (N, J) matrix of correlations between a x b columns\n        else a (N, J) matrix of correlations between a x b rows.\n\n    See Also\n    --------\n    scipy.stats.spearmanr\n    \"\"\"\n    a, b = np.atleast_2d(a, b)\n    assert a.shape[axis] == b.shape[axis]\n    ar = np.apply_along_axis(stats.rankdata, axis, a)\n    br = np.apply_along_axis(stats.rankdata, axis, b)\n\n    return _corrcoef2(ar, br, axis=axis)\n\n\ndef _corrcoef2(a, b, axis=0):\n    \"\"\"\n    Compute all pairwise Pearson product-moment correlation coefficients\n    between rows or columns of a and b\n\n    Parameters\n    ----------\n    a : (N, M) numpy.ndarray\n        The input cases a.\n    b : (J, K) numpy.ndarray\n        The input cases b. In case of axis == 0: J must equal N;\n        otherwise if axis == 1 then K must equal M.\n    axis : int\n        If 0 the correlation are computed between a and b's columns.\n        Otherwise if 1 the correlations are computed between rows.\n\n    Returns\n    -------\n    cor : (N, J) or (M, K) nd.array\n        If axis == 0 then (N, J) matrix of correlations between a x b columns\n        else a (N, J) matrix of correlations between a x b rows.\n\n    See Also\n    --------\n    numpy.corrcoef\n    \"\"\"\n    a, b = np.atleast_2d(a, b)\n    if axis not in (0, 1):\n        raise ValueError(\"Invalid axis {} (only 0 or 1 accepted)\".format(axis))\n\n    mean_a = np.mean(a, axis=axis, keepdims=True)\n    mean_b = np.mean(b, axis=axis, keepdims=True)\n    assert a.shape[axis] == b.shape[axis]\n\n    n = a.shape[1 - axis]\n    m = b.shape[1 - axis]\n\n    a = a - mean_a\n    b = b - mean_b\n\n    if axis == 0:\n        C = a.T.dot(b)\n        assert C.shape == (n, m)\n    elif axis == 1:\n        C = a.dot(b.T)\n        assert C.shape == (n, m)\n\n    ss_a = np.sum(a ** 2, axis=axis, keepdims=True)\n    ss_b = np.sum(b ** 2, axis=axis, keepdims=True)\n\n    if axis == 0:\n        ss_a = ss_a.T\n    else:\n        ss_b = ss_b.T\n\n    assert ss_a.shape == (n, 1)\n    assert ss_b.shape == (1, m)\n    C /= np.sqrt(ss_a)\n    C /= np.sqrt(ss_b)\n    return C\n\n\nclass CorrelationDistance(Distance):\n    # pylint: disable=abstract-method\n    supports_missing = False\n\n\nclass SpearmanR(CorrelationDistance):\n    def fit(self, _):\n        return SpearmanModel(False, self.axis, self.impute)\n\n\nclass SpearmanRAbsolute(CorrelationDistance):\n    def fit(self, _):\n        return SpearmanModel(True, self.axis, self.impute)\n\n\nclass PearsonModel(CorrelationDistanceModel):\n    def compute_correlation(self, x1, x2):\n        if x2 is None:\n            c = np.corrcoef(x1, rowvar=self.axis == 1)\n            return np.atleast_2d(c)\n        else:\n            return _corrcoef2(x1, x2, axis=self.axis)\n\n\nclass PearsonR(CorrelationDistance):\n    def fit(self, _):\n        return PearsonModel(False, self.axis, self.impute)\n\n\nclass PearsonRAbsolute(CorrelationDistance):\n    def fit(self, _):\n        return PearsonModel(True, self.axis, self.impute)\n\n\nclass Mahalanobis(Distance):\n    supports_sparse = False\n    supports_missing = False\n\n    def fit(self, data):\n        \"\"\"Return a model with stored inverse covariance matrix\"\"\"\n        x = _orange_to_numpy(data)\n        if self.axis == 0:\n            x = x.T\n        try:\n            c = np.cov(x.T)\n        except:\n            raise MemoryError(\"Covariance matrix is too large.\")\n        try:\n            vi = np.linalg.inv(c)\n        except:\n            raise ValueError(\"Computation of inverse covariance matrix failed.\")\n        return MahalanobisModel(self.axis, self.impute, vi)\n\n\nclass MahalanobisModel(DistanceModel):\n    def __init__(self, axis, impute, vi):\n        super().__init__(axis, impute)\n        self.vi = vi\n\n    def __call__(self, e1, e2=None, impute=None):\n        # argument `impute` is here just for backward compatibility; don't use\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2):\n        if self.axis == 0:\n            x1 = x1.T\n            if x2 is not None:\n                x2 = x2.T\n        if x1.shape[1] != self.vi.shape[0] or \\\n                x2 is not None and x2.shape[1] != self.vi.shape[0]:\n            raise ValueError('Incorrect number of features.')\n        return skl_metrics.pairwise.pairwise_distances(\n            x1, x2, metric='mahalanobis', VI=self.vi)\n\n\n# TODO: Appears to have been used only in the Distances widget (where it had\n# to be handled as a special case and is now replaced with the above class)\n# and in tests. Remove?\nclass MahalanobisDistance:\n    \"\"\"\n    Obsolete class needed for backward compatibility.\n\n    Previous implementation of instances did not have a separate fitting phase,\n    except for MahalanobisDistance, which was implemented in a single class\n    but required first (explicitly) calling the method 'fit'. The backward\n    compatibility hack in :obj:`Distance` cannot handle such use, hence it\n    is provided in this class.\n    \"\"\"\n    def __new__(cls, data=None, axis=1, _='Mahalanobis'):\n        if data is None:\n            return cls\n        return Mahalanobis(axis=axis).fit(data)\n\nclass Hamming(Distance):\n    supports_sparse = False\n    supports_missing = False\n    supports_normalization = False\n    supports_discrete = True\n\n    def fit(self, data):\n        x = _orange_to_numpy(data)\n        if self.axis == 0:\n            return HammingColumnsModel(self.axis, self.impute, x)\n        else:\n            return HammingRowsModel(self.axis, self.impute, x)\n\nclass HammingColumnsModel(DistanceModel):\n    \"\"\"\n    Model for computation of Hamming distances between columns.\n    \"\"\"\n    def __init__(self, axis, impute, x):\n        super().__init__(axis, impute)\n        self.x = x\n\n    def __call__(self, e1, e2=None, impute=None):\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2=None):\n        return pairwise_distances(x1.T, metric='hamming')\n\nclass HammingRowsModel(DistanceModel):\n    \"\"\"\n    Model for computation of Hamming distances between rows.\n    \"\"\"\n    def __init__(self, axis, impute, x):\n        super().__init__(axis, impute)\n        self.x = x\n\n    def __call__(self, e1, e2=None, impute=None):\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2=None):\n        return pairwise_distances(x1, metric='hamming')\n",
            "header": {
                "file": {
                    "path": "Orange/distance/distance.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "cfd7fe43a",
                "new_commit_hash": "9dd1d7213",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/distance/distance.py"
            },
            "plus_file": {
                "path": "b/Orange/distance/distance.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 442,
                            "length": 8
                        },
                        "new_range": {
                            "start": 442,
                            "length": 11
                        },
                        "section": "class JaccardModel(FittedDistanceModel):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        for i in range(n):",
                                "type": "context"
                            },
                            {
                                "content": "            xi_ind = set(x1[i].indices)",
                                "type": "context"
                            },
                            {
                                "content": "            for j in range(i if symmetric else m):",
                                "type": "context"
                            },
                            {
                                "content": "                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\\",
                                "type": "deleted"
                            },
                            {
                                "content": "                           / len(set(x1[i].indices).union(x1[j].indices))",
                                "type": "deleted"
                            },
                            {
                                "content": "                union = len(xi_ind.union(x2[j].indices))",
                                "type": "added"
                            },
                            {
                                "content": "                if union:",
                                "type": "added"
                            },
                            {
                                "content": "                    jacc = 1 - len(xi_ind.intersection(x2[j].indices)) / union",
                                "type": "added"
                            },
                            {
                                "content": "                else:",
                                "type": "added"
                            },
                            {
                                "content": "                    jacc = 0",
                                "type": "added"
                            },
                            {
                                "content": "                matrix[i, j] = jacc",
                                "type": "context"
                            },
                            {
                                "content": "                if symmetric:",
                                "type": "context"
                            },
                            {
                                "content": "                    matrix[j, i] = jacc",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/distance/distance.py",
                            "type": "class",
                            "name": "JaccardModel",
                            "content": "class JaccardModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of cosine distances across rows and columns.\n    All non-zero values are treated as 1.\n    \"\"\"\n    def __init__(self, attributes, axis, impute, ps):\n        super().__init__(attributes, axis, impute)\n        self.ps = ps\n\n    def compute_distances(self, x1, x2):\n        if sp.issparse(x1):\n            return self._compute_sparse(x1, x2)\n        else:\n            return self._compute_dense(x1, x2)\n\n    def _compute_dense(self, x1, x2):\n        \"\"\"\n        The method uses a function implemented in Cython. Data (`x1` and `x2`)\n        is accompanied by two tables. One is a 2-d table in which elements of\n        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector\n        indicating rows (or column) with nan values.\n\n        The function in Cython uses a fast loop without any conditions to\n        compute distances between rows without missing values, and a slower\n        loop for those with missing values.\n        \"\"\"\n        # view is false positive, pylint: disable=no-member\n        nonzeros1 = np.not_equal(x1, 0).view(np.int8)\n        if self.axis == 1:\n            nans1 = _distance.any_nan_row(x1)\n            if x2 is None:\n                nonzeros2, nans2 = nonzeros1, nans1\n            else:\n                nonzeros2 = np.not_equal(x2, 0).view(np.int8)\n                nans2 = _distance.any_nan_row(x2)\n            return _distance.jaccard_rows(\n                nonzeros1, nonzeros2,\n                x1, x1 if x2 is None else x2,\n                nans1, nans2,\n                self.ps,\n                x2 is not None)\n        else:\n            nans1 = _distance.any_nan_row(x1.T)\n            return _distance.jaccard_cols(\n                nonzeros1, x1, nans1, self.ps)\n\n    @staticmethod\n    def _compute_sparse(x1, x2=None):\n        symmetric = x2 is None\n        if symmetric:\n            x2 = x1\n        x1 = sp.csr_matrix(x1)\n        x1.eliminate_zeros()\n        x2 = sp.csr_matrix(x2)\n        x2.eliminate_zeros()\n        n, m = x1.shape[0], x2.shape[0]\n        matrix = np.zeros((n, m))\n        for i in range(n):\n            xi_ind = set(x1[i].indices)\n            for j in range(i if symmetric else m):\n                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\\\n                           / len(set(x1[i].indices).union(x1[j].indices))\n                matrix[i, j] = jacc\n                if symmetric:\n                    matrix[j, i] = jacc\n        return matrix",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 385,
                            "end_lineno": 450,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/distance/distance.py",
                            "type": "method",
                            "name": "JaccardModel._compute_sparse",
                            "content": "class JaccardModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of cosine distances across rows and columns.\n    All non-zero values are treated as 1.\n    \"\"\"\n    def __init__(self, attributes, axis, impute, ps):\n        super().__init__(attributes, axis, impute)\n        self.ps = ps\n\n    def compute_distances(self, x1, x2):\n        if sp.issparse(x1):\n            return self._compute_sparse(x1, x2)\n        else:\n            return self._compute_dense(x1, x2)\n\n    def _compute_dense(self, x1, x2):\n        \"\"\"\n        The method uses a function implemented in Cython. Data (`x1` and `x2`)\n        is accompanied by two tables. One is a 2-d table in which elements of\n        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector\n        indicating rows (or column) with nan values.\n\n        The function in Cython uses a fast loop without any conditions to\n        compute distances between rows without missing values, and a slower\n        loop for those with missing values.\n        \"\"\"\n        # view is false positive, pylint: disable=no-member\n        nonzeros1 = np.not_equal(x1, 0).view(np.int8)\n        if self.axis == 1:\n            nans1 = _distance.any_nan_row(x1)\n            if x2 is None:\n                nonzeros2, nans2 = nonzeros1, nans1\n            else:\n                nonzeros2 = np.not_equal(x2, 0).view(np.int8)\n                nans2 = _distance.any_nan_row(x2)\n            return _distance.jaccard_rows(\n                nonzeros1, nonzeros2,\n                x1, x1 if x2 is None else x2,\n                nans1, nans2,\n                self.ps,\n                x2 is not None)\n        else:\n            nans1 = _distance.any_nan_row(x1.T)\n            return _distance.jaccard_cols(\n                nonzeros1, x1, nans1, self.ps)\n\n    @staticmethod\n    def _compute_sparse(x1, x2=None):\n        symmetric = x2 is None\n        if symmetric:\n            x2 = x1\n        x1 = sp.csr_matrix(x1)\n        x1.eliminate_zeros()\n        x2 = sp.csr_matrix(x2)\n        x2.eliminate_zeros()\n        n, m = x1.shape[0], x2.shape[0]\n        matrix = np.zeros((n, m))\n        for i in range(n):\n            xi_ind = set(x1[i].indices)\n            for j in range(i if symmetric else m):\n                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\\\n                           / len(set(x1[i].indices).union(x1[j].indices))\n                matrix[i, j] = jacc\n                if symmetric:\n                    matrix[j, i] = jacc\n        return matrix",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 432,
                            "end_lineno": 450,
                            "parent": {
                                "file_name": "Orange/distance/distance.py",
                                "type": "class",
                                "name": "JaccardModel",
                                "content": "class JaccardModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of cosine distances across rows and columns.\n    All non-zero values are treated as 1.\n    \"\"\"\n    def __init__(self, attributes, axis, impute, ps):\n        super().__init__(attributes, axis, impute)\n        self.ps = ps\n\n    def compute_distances(self, x1, x2):\n        if sp.issparse(x1):\n            return self._compute_sparse(x1, x2)\n        else:\n            return self._compute_dense(x1, x2)\n\n    def _compute_dense(self, x1, x2):\n        \"\"\"\n        The method uses a function implemented in Cython. Data (`x1` and `x2`)\n        is accompanied by two tables. One is a 2-d table in which elements of\n        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector\n        indicating rows (or column) with nan values.\n\n        The function in Cython uses a fast loop without any conditions to\n        compute distances between rows without missing values, and a slower\n        loop for those with missing values.\n        \"\"\"\n        # view is false positive, pylint: disable=no-member\n        nonzeros1 = np.not_equal(x1, 0).view(np.int8)\n        if self.axis == 1:\n            nans1 = _distance.any_nan_row(x1)\n            if x2 is None:\n                nonzeros2, nans2 = nonzeros1, nans1\n            else:\n                nonzeros2 = np.not_equal(x2, 0).view(np.int8)\n                nans2 = _distance.any_nan_row(x2)\n            return _distance.jaccard_rows(\n                nonzeros1, nonzeros2,\n                x1, x1 if x2 is None else x2,\n                nans1, nans2,\n                self.ps,\n                x2 is not None)\n        else:\n            nans1 = _distance.any_nan_row(x1.T)\n            return _distance.jaccard_cols(\n                nonzeros1, x1, nans1, self.ps)\n\n    @staticmethod\n    def _compute_sparse(x1, x2=None):\n        symmetric = x2 is None\n        if symmetric:\n            x2 = x1\n        x1 = sp.csr_matrix(x1)\n        x1.eliminate_zeros()\n        x2 = sp.csr_matrix(x2)\n        x2.eliminate_zeros()\n        n, m = x1.shape[0], x2.shape[0]\n        matrix = np.zeros((n, m))\n        for i in range(n):\n            xi_ind = set(x1[i].indices)\n            for j in range(i if symmetric else m):\n                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\\\n                           / len(set(x1[i].indices).union(x1[j].indices))\n                matrix[i, j] = jacc\n                if symmetric:\n                    matrix[j, i] = jacc\n        return matrix",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 385,
                                "end_lineno": 450,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import unittest\nfrom unittest.mock import patch\nfrom math import sqrt\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix\n\nfrom Orange.data import ContinuousVariable, DiscreteVariable, Domain, Table\nfrom Orange import distance\n\n\nclass CommonTests:\n    \"\"\"Tests applicable to all distance measures\"\"\"\n\n    def test_no_data(self):\n        \"\"\"distances return zero-dimensional matrices when no data\"\"\"\n        n = len(self.data)\n        np.testing.assert_almost_equal(\n            self.Distance(Table(self.domain)),\n            np.zeros((0, 0)))\n        np.testing.assert_almost_equal(\n            self.Distance(self.data, Table(self.domain)),\n            np.zeros((n, 0)))\n        np.testing.assert_almost_equal(\n            self.Distance(Table(self.domain), self.data),\n            np.zeros((0, n)))\n\n    def test_sparse(self):\n        \"\"\"Test sparse support in distances.\"\"\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[1, 0, 2], [-1, 5, 0], [0, 1, 1], [7, 0, 0]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n\n        if not self.Distance.supports_sparse:\n            self.assertRaises(TypeError, self.Distance, sparse_data)\n        else:\n            # check the result is the same for sparse and dense\n            dist_dense = self.Distance(dense_data)\n            dist_sparse = self.Distance(sparse_data)\n            np.testing.assert_allclose(dist_sparse, dist_dense)\n\n\nclass CommonFittedTests(CommonTests):\n    \"\"\"Tests applicable to all distances with fitting\"\"\"\n    def test_mismatching_attributes(self):\n        \"\"\"distances can't be computed if fit from other attributes\"\"\"\n        def new_table():\n            return Table.from_list(Domain([ContinuousVariable(\"a\")]), [[1]])\n\n        table1 = new_table()\n        model = self.Distance().fit(table1)\n        self.assertRaises(ValueError, model, new_table())\n        self.assertRaises(ValueError, model, table1, new_table())\n        self.assertRaises(ValueError, model, new_table(), table1)\n\n\nclass CommonNormalizedTests(CommonFittedTests):\n    \"\"\"Tests applicable to distances the have normalization\"\"\"\n\n    def test_zero_variance(self):\n        \"\"\"zero-variance columns have no effect on row distance\"\"\"\n        assert_almost_equal = np.testing.assert_almost_equal\n        normalized = self.Distance(axis=1, normalize=True)\n        nonnormalized = self.Distance(axis=1, normalize=False)\n\n        def is_same(d1, d2, fit1=None, fit2=None):\n            if fit1 is None:\n                fit1 = d1\n            if fit2 is None:\n                fit2 = d2\n            assert_almost_equal(normalized.fit(fit1)(d1),\n                                normalized.fit(fit2)(d2))\n            assert_almost_equal(nonnormalized.fit(fit1)(d1),\n                                nonnormalized.fit(fit2)(d2))\n\n        data = self.cont_data\n        n = len(data)\n        X = data.X\n        domain = Domain(data.domain.attributes + (ContinuousVariable(\"d\"),))\n        data_const = Table(domain, np.hstack((X, np.ones((n, 1)))))\n        data_nan = Table(domain, np.hstack((X, np.full((n, 1), np.nan))))\n        data_nan_1 = Table(domain, np.hstack((X, np.full((n, 1), np.nan))))\n        data_nan_1.X[0, -1] = 1\n        is_same(data, data_const)\n        is_same(data, data_nan)\n        is_same(data, data_nan_1)\n\n        # Test whether it's possible to fit with singular data and use the\n        # parameters on data where the same column is defined\n        is_same(data_nan, data_const, data_const)\n        is_same(data_const, data_const, data_nan)\n\n        self.assertRaises(ValueError, self.Distance,\n                          data_const, axis=0, normalize=True)\n        self.assertRaises(ValueError, self.Distance,\n                          data_nan, axis=0, normalize=True)\n        self.assertRaises(ValueError, self.Distance,\n                          data_nan_1, axis=0, normalize=True)\n\n    def test_mixed_cols(self):\n        \"\"\"distance over columns raises exception for discrete columns\"\"\"\n        self.assertRaises(ValueError, self.Distance, self.mixed_data, axis=0)\n        self.assertRaises(ValueError,\n                          self.Distance(axis=0).fit, self.mixed_data)\n\n\nclass FittedDistanceTest(unittest.TestCase):\n    @classmethod\n    def setUpClass(cls):\n        cls.attributes = (\n            ContinuousVariable(\"c1\"),\n            ContinuousVariable(\"c2\"),\n            ContinuousVariable(\"c3\"),\n            DiscreteVariable(\"d1\", values=[\"a\", \"b\"]),\n            DiscreteVariable(\"d2\", values=[\"a\", \"b\", \"c\", \"d\"]),\n            DiscreteVariable(\"d3\", values=[\"a\", \"b\", \"c\"]))\n        cls.domain = Domain(cls.attributes)\n        cls.cont_domain = Domain(cls.attributes[:3])\n        cls.disc_domain = Domain(cls.attributes[3:])\n\n    def setUp(self):\n        self.cont_data = Table.from_list(\n            self.cont_domain,\n            [[1, 3, 2],\n             [-1, 5, 0],\n             [1, 1, 1],\n             [7, 2, 3]])\n\n        self.cont_data2 = Table.from_list(\n            self.cont_domain,\n            [[2, 1, 3],\n             [1, 2, 2]]\n        )\n\n        self.disc_data = Table.from_list(\n            self.disc_domain,\n            [[0, 0, 0],\n             [0, 1, 1],\n             [1, 3, 1]]\n        )\n\n        self.disc_data4 = Table.from_list(\n            self.disc_domain,\n            [[0, 0, 0],\n             [0, 1, 1],\n             [0, 1, 1],\n             [1, 3, 1]]\n        )\n\n        self.mixed_data = self.data = Table.from_numpy(\n            self.domain, np.hstack((self.cont_data.X[:3], self.disc_data.X)))\n\n\n\n# Correct results in these tests were computed manually or with Excel;\n# these are not regression tests\nclass EuclideanDistanceTest(FittedDistanceTest, CommonNormalizedTests):\n    Distance = distance.Euclidean\n\n    def test_euclidean_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2, 3],\n                                              [2, 0, 2],\n                                              [3, 2, 0]])))\n\n        data.X[1, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]\n                            ])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2.5, 3],\n                                              [2.5, 0, 1.5],\n                                              [3, 1.5, 0]])))\n\n        data.X[0, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1, 0, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 1, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2, 2],\n                                              [2, 0, 1],\n                                              [2, 1, 0]])))\n\n        data = self.disc_data4\n        data.X[:2, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [3/4, 2/4, 1, 3/4],\n                             [3/4, 1/4, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 6/16, 1 - 10/16])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2.5, 2.5, 2.5],\n                                              [2.5, 0, 0.5, 1.5],\n                                              [2.5, 0.5, 0, 2],\n                                              [2.5, 1.5, 2, 0]])))\n\n    def test_euclidean_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            np.sqrt(np.array([[0, 12, 5, 38],\n                              [12, 0, 21, 82],\n                              [5, 21, 0, 41],\n                              [38, 82, 41, 0]])))\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 4.472135955, 2.236067977, 6.164414003],\n             [4.472135955, 0, 5.385164807, 6.480740698],\n             [2.236067977, 5.385164807, 0, 6.403124237],\n             [6.164414003, 6.480740698, 6.403124237, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 5.099019514, 4.795831523, 4.472135955],\n             [5.099019514, 0, 5.916079783, 6],\n             [4.795831523, 5.916079783, 0, 6.403124237],\n             [4.472135955, 6, 6.403124237, 0]])\n\n    def test_euclidean_cont_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [2, 2.75, 1.5])\n        assert_almost_equal(model.vars, [9, 2.1875, 1.25])\n        assert_almost_equal(model.dist_missing2_cont, [1, 1, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.654239383, 1.146423008, 1.621286967],\n             [1.654239383, 0, 2.068662631, 3.035242727],\n             [1.146423008, 2.068662631, 0, 1.956673562],\n             [1.621286967, 3.035242727, 1.956673562, 0]])\n\n        dist = distance.Euclidean(data, axis=1, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 1.654239383, 1.146423008, 1.621286967],\n             [1.654239383, 0, 2.068662631, 3.035242727],\n             [1.146423008, 2.068662631, 0, 1.956673562],\n             [1.621286967, 3.035242727, 1.956673562, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [3, 2.75, 1.5])\n        assert_almost_equal(model.vars, [8, 2.1875, 1.25])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.806733438, 1.146423008, 1.696635326],\n             [1.806733438, 0, 2.192519751, 2.675283697],\n             [1.146423008, 2.192519751, 0, 2.019547333],\n             [1.696635326, 2.675283697, 2.019547333, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [4, 2.75, 1.5])\n        assert_almost_equal(model.vars, [9, 2.1875, 1.25])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.874642823, 1.521277659, 1.276154939],\n             [1.874642823, 0, 2.248809209, 2.580143961],\n             [1.521277659, 2.248809209, 0, 1.956673562],\n             [1.276154939, 2.580143961, 1.956673562, 0]])\n\n    def test_euclidean_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 8.062257748, 4.242640687],\n             [8.062257748, 0, 5.196152423],\n             [4.242640687, 5.196152423, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 6.218252702, 4.242640687],\n             [6.218252702, 0, 2.581988897],\n             [4.242640687, 2.581988897, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 6.218252702, 5.830951895],\n             [6.218252702, 0, 2.581988897],\n             [5.830951895, 2.581988897, 0]])\n\n    def test_euclidean_cols_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2.455273959, 0.649839392],\n             [2.455273959, 0, 2.473176308],\n             [0.649839392, 2.473176308, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2, 0.649839392],\n             [2, 0, 1.704275472],\n             [0.649839392, 1.704275472, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2, 1.450046001],\n             [2, 0, 1.704275472],\n             [1.450046001, 1.704275472, 0]])\n\n    def test_euclidean_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n\n        assert_almost_equal(model.means, [1/3, 3, 1])\n        assert_almost_equal(model.vars, [8/9, 8/3, 2/3])\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_cont, [1, 1, 1])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.828427125, 2.121320344],\n             [2.828427125, 0, 2.828427125],\n             [2.121320344, 2.828427125, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        dist = distance.Euclidean(self.cont_data, self.cont_data2,\n                                  normalize=True)\n        assert_almost_equal(\n            dist,\n            [[1.17040218, 0.47809144],\n             [2.78516478, 1.96961039],\n             [1.28668394, 0.79282497],\n             [1.27179413, 1.54919334]])\n\n        model = distance.Euclidean(normalize=True).fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[1.17040218, 0.47809144],\n             [2.78516478, 1.96961039],\n             [1.28668394, 0.79282497],\n             [1.27179413, 1.54919334]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 0.827119692], [0.827119692, 0]])\n\n\nclass ManhattanDistanceTest(FittedDistanceTest, CommonNormalizedTests):\n    Distance = distance.Euclidean\n\n    # The data used for testing Euclidean distances unfortunately yields\n    # mads = 1, so we change it a bit\n    def setUp(self):\n        super().setUp()\n        self.cont_data = Table.from_list(\n            self.cont_domain,\n            [[1, 3, 2],\n             [-1, 6, 0],\n             [2, 7, 1],\n             [7, 1, 3]])\n\n    def test_manhattan_no_data(self):\n        np.testing.assert_almost_equal(\n            distance.Manhattan(Table(self.domain)),\n            np.zeros((0, 0)))\n        np.testing.assert_almost_equal(\n            distance.Manhattan(self.mixed_data, Table(self.domain)),\n            np.zeros((3, 0)))\n        np.testing.assert_almost_equal(\n            distance.Manhattan(Table(self.domain), self.mixed_data),\n            np.zeros((0, 3)))\n        self.assertRaises(\n            ValueError,\n            distance.Manhattan, Table(self.cont_domain), axis=0, normalize=True)\n\n    def test_manhattan_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2, 3],\n                             [2, 0, 2],\n                             [3, 2, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2.5, 3],\n                             [2.5, 0, 1.5],\n                             [3, 1.5, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1, 0, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 1, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2, 2],\n                             [2, 0, 1],\n                             [2, 1, 0]])\n\n        data = self.disc_data4\n        data.X[:2, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [3/4, 2/4, 1, 3/4],\n                             [3/4, 1/4, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 6/16, 1 - 10/16])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2.5, 2.5, 2.5],\n                             [2.5, 0, 0.5, 1.5],\n                             [2.5, 0.5, 0, 2],\n                             [2.5, 1.5, 2, 0]])\n\n    def test_manhattan_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 7, 6, 9],\n             [7, 0, 5, 16],\n             [6, 5, 0, 13],\n             [9, 16, 13, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 7, 6, 9],\n             [7, 0, 3, 14],\n             [6, 3, 0, 13],\n             [9, 14, 13, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 10, 10, 8],\n             [10, 0, 7, 13],\n             [10, 7, 0, 13],\n             [8, 13, 13, 0]])\n\n    def test_manhattan_cont_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [1.5, 4.5, 1.5])\n        assert_almost_equal(model.mads, [1.5, 2, 1])\n        assert_almost_equal(model.dist_missing2_cont, np.ones(3))\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.416666667, 1.833333333, 3],\n             [2.416666667, 0, 1.75, 5.416666667],\n             [1.833333333, 1.75, 0, 4.166666667],\n             [3, 5.416666667, 4.166666667, 0]])\n\n        dist = distance.Manhattan(data, axis=1, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2.416666667, 1.833333333, 3],\n             [2.416666667, 0, 1.75, 5.416666667],\n             [1.833333333, 1.75, 0, 4.166666667],\n             [3, 5.416666667, 4.166666667, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [2, 4.5, 1.5])\n        assert_almost_equal(model.mads, [1, 2, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.75, 2, 4],\n             [2.75, 0, 1.25, 5.75],\n             [2, 1.25, 0, 5],\n             [4, 5.75, 5, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [4.5, 4.5, 1.5])\n        assert_almost_equal(model.mads, [2.5, 2, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.75, 2.5, 2],\n             [2.75, 0, 1.75, 3.75],\n             [2.5, 1.75, 0, 3.5],\n             [2, 3.75, 3.5, 0]])\n\n    def test_manhattan_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 20, 7],\n             [20, 0, 15],\n             [7, 15, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 19, 7],\n             [19, 0, 14],\n             [7, 14, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 17, 9],\n             [17, 0, 14],\n             [9, 14, 0]])\n\n\n    def test_manhattan_cols_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 4.5833333, 2],\n             [4.5833333, 0, 4.25],\n             [2, 4.25, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 4.6666667, 2],\n             [4.6666667, 0, 4],\n             [2, 4, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 5.5, 4],\n             [5.5, 0, 4],\n             [4, 4, 0]])\n\n    def test_manhattan_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n\n        data.X[2, 0] = 2  # prevent mads[0] = 0\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [1, 3, 1])\n        assert_almost_equal(model.mads, [1, 2, 1])\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 4.5, 4.5],\n             [4.5, 0, 5],\n             [4.5, 5, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        dist = distance.Manhattan(self.cont_data, self.cont_data2,\n                                  normalize=True)\n        assert_almost_equal(\n            dist,\n            [[1.3333333, 0.25],\n             [3.75, 2.6666667],\n             [2.5, 2.0833333],\n             [1.6666667, 2.75]])\n\n        model = distance.Manhattan(normalize=True).fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[1.3333333, 0.25],\n             [3.75, 2.6666667],\n             [2.5, 2.0833333],\n             [1.6666667, 2.75]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 1.083333333], [1.083333333, 0]])\n\n    def test_manhattan_mixed_cols(self):\n        self.assertRaises(ValueError,\n                          distance.Manhattan, self.mixed_data, axis=0)\n        self.assertRaises(ValueError,\n                          distance.Manhattan(axis=0).fit, self.mixed_data)\n\n\nclass CosineDistanceTest(FittedDistanceTest, CommonFittedTests):\n    Distance = distance.Cosine\n\n    def test_no_data(self):\n        with patch(\"warnings.warn\") as warn:\n            super().test_no_data()\n            self.assertEqual(warn.call_args[0],\n                             (\"Mean of empty slice\", RuntimeWarning))\n\n    def test_cosine_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        data.X = np.array([[1, 0, 0],\n                           [0, 1, 1],\n                           [1, 3, 0]], dtype=float)\n\n        model = distance.Cosine().fit(data)\n        assert_almost_equal(model.means, [2 / 3, 2 / 3, 1 / 3])\n\n        dist = model(data)\n        assert_almost_equal(dist, 1 - np.array([[1, 0, 1 / sqrt(2)],\n                                                [0, 1, 0.5],\n                                                [1 / sqrt(2), 0.5, 1]]))\n\n        data.X[1, 1] = np.nan\n        model = distance.Cosine().fit(data)\n        assert_almost_equal(model.means, [2 / 3, 1 / 2, 1 / 3])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            1 - np.array([[1, 0, 1 / sqrt(2)],\n                          [0, 1, 0.5 / sqrt(1.25) / sqrt(2)],\n                          [1 / sqrt(2), 0.5 / sqrt(1.25) / sqrt(2), 1]]))\n\n        data.X = np.array([[1, 0, 0],\n                           [0, np.nan, 1],\n                           [1, np.nan, 1],\n                           [1, 3, 1]])\n        model = distance.Cosine().fit(data)\n        dist = model(data)\n        assert_almost_equal(model.means, [0.75, 0.5, 0.75])\n        assert_almost_equal(dist, [[0, 1, 0.333333333, 0.422649731],\n                                   [1, 0, 0.254644008, 0.225403331],\n                                   [0.333333333, 0.254644008, 0, 0.037749551],\n                                   [0.422649731, 0.225403331, 0.037749551, 0]])\n\n    def test_cosine_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.266200614, 0.0741799, 0.355097978],\n             [0.266200614, 0, 0.547089186, 0.925279678],\n             [0.0741799, 0.547089186, 0, 0.12011731],\n             [0.355097978, 0.925279678, 0.12011731, 0]]\n        )\n\n        data.X[1, 0] = np.nan\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.174971353, 0.0741799, 0.355097978],\n             [0.174971353, 0, 0.207881966, 0.324809395],\n             [0.0741799, 0.207881966, 0, 0.12011731],\n             [0.355097978, 0.324809395, 0.12011731, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.100977075, 0.035098719, 0.056666739],\n             [0.100977075, 0, 0.188497329, 0.246304671],\n             [0.035098719, 0.188497329, 0, 0.12011731],\n             [0.056666739, 0.246304671, 0.12011731, 0]])\n\n    def test_cosine_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n        data.X = np.array([[1, 3, 2, 1, 0, 0],\n                           [-1, 5, 0, 0, 1, 1],\n                           [1, 1, 1, 1, 3, 0]], dtype=float)\n\n        model = distance.Cosine(axis=1).fit(data)\n        assert_almost_equal(model.means, [1/3, 3, 1, 2/3, 2/3, 1/3])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 0.316869949, 0.191709623],\n             [0.316869949, 0, 0.577422873],\n             [0.191709623, 0.577422873, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        self.cont_data.X[1, 0] = np.nan\n        self.cont_data2.X[1, 0] = np.nan\n\n        dist = distance.Cosine(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[0.2142857, 0.1573352],\n             [0.4958158, 0.2097042],\n             [0.0741799, 0.0198039],\n             [0.1514447, 0.0451363]])\n\n        model = distance.Cosine().fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[0.2142857, 0.1573352],\n             [0.4958158, 0.2097042],\n             [0.0741799, 0.0198039],\n             [0.1514447, 0.0451363]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 0.092514787], [0.092514787, 0]])\n\n    def test_cosine_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.711324865, 0.11050082],\n             [0.711324865, 0, 0.44365136],\n             [0.11050082, 0.44365136, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.47702364, 0.11050082],\n             [0.47702364, 0, 0.181076975],\n             [0.11050082, 0.181076975, 0]])\n\n        data.X[1, 0] = np.nan\n        data.X[1, 2] = 2\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.269703257, 0.087129071],\n             [0.269703257, 0, 0.055555556],\n             [0.087129071, 0.055555556, 0]])\n\n\nclass JaccardDistanceTest(unittest.TestCase, CommonFittedTests):\n    Distance = distance.Jaccard\n\n    def setUp(self):\n        self.domain = Domain([DiscreteVariable(c) for c in \"abc\"])\n        self.data = Table(\n            self.domain,\n            [[0, 1, 1],\n             [1, 1, 1],\n             [1, 0, 1],\n             [1, 0, 0]])\n\n    def test_jaccard_rows(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 2/3, 1/3, 0],\n                          [2/3, 1, 2/3, 1/3],\n                          [1/3, 2/3, 1, 1/2],\n                          [0, 1/3, 1/2, 1]]))\n\n        X = self.data.X\n        X[1, 0] = X[2, 0] = X[3, 1] = np.nan\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, np.array([0.5, 2/3, 0.75]))\n\n        # pylint: disable=bad-whitespace\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[      1,        2 / 2.5,        1 / 2.5,        2/3 / 3],\n                          [2 / 2.5,              1,    1.25 / 2.75,  (1/2+2/3) / 3],\n                          [1 / 2.5,    1.25 / 2.75,              1,  0.5 / (2+2/3)],\n                          [2/3 / 3,  (1/2+2/3) / 3,  0.5 / (2+2/3),            1]]))\n\n    def test_jaccard_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 1/4, 1/2],\n                          [1/4, 1, 2/3],\n                          [1/2, 2/3, 1]]))\n\n        self.data.X = np.array([[0, 1, 1],\n                                [np.nan, np.nan, 1],\n                                [np.nan, 0, 1],\n                                [1, 1, 0]])\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.5, 2/3, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 0.4, 0.25],\n                          [0.4, 1, 5/12],\n                          [0.25, 5/12, 1]]))\n\nclass HammingDistanceTest(FittedDistanceTest):\n    Distance = distance.Hamming\n\n    def test_hamming_col(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        dist = distance.Hamming(data, axis=0)\n\n        assert_almost_equal(\n            dist,\n            [[0, 2/3, 1/3],\n             [2/3, 0, 1/3],\n             [1/3, 1/3, 0]])\n\n    def test_hamming_row(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        dist = distance.Hamming(data)\n\n        assert_almost_equal(\n            dist,\n            [[0, 2/3, 1],\n             [2/3, 0, 2/3],\n             [1, 2/3, 0]]\n        )\n\nif __name__ == \"__main__\":\n    unittest.main()\n",
            "new_file_content": "import unittest\nfrom unittest.mock import patch\nfrom math import sqrt\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix\n\nfrom Orange.data import ContinuousVariable, DiscreteVariable, Domain, Table\nfrom Orange import distance\n\n\nclass CommonTests:\n    \"\"\"Tests applicable to all distance measures\"\"\"\n\n    def test_no_data(self):\n        \"\"\"distances return zero-dimensional matrices when no data\"\"\"\n        n = len(self.data)\n        np.testing.assert_almost_equal(\n            self.Distance(Table(self.domain)),\n            np.zeros((0, 0)))\n        np.testing.assert_almost_equal(\n            self.Distance(self.data, Table(self.domain)),\n            np.zeros((n, 0)))\n        np.testing.assert_almost_equal(\n            self.Distance(Table(self.domain), self.data),\n            np.zeros((0, n)))\n\n    def test_sparse(self):\n        \"\"\"Test sparse support in distances.\"\"\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[1, 0, 2], [-1, 5, 0], [0, 1, 1], [7, 0, 0]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n\n        if not self.Distance.supports_sparse:\n            self.assertRaises(TypeError, self.Distance, sparse_data)\n        else:\n            # check the result is the same for sparse and dense\n            dist_dense = self.Distance(dense_data)\n            dist_sparse = self.Distance(sparse_data)\n            np.testing.assert_allclose(dist_sparse, dist_dense)\n\n\nclass CommonFittedTests(CommonTests):\n    \"\"\"Tests applicable to all distances with fitting\"\"\"\n    def test_mismatching_attributes(self):\n        \"\"\"distances can't be computed if fit from other attributes\"\"\"\n        def new_table():\n            return Table.from_list(Domain([ContinuousVariable(\"a\")]), [[1]])\n\n        table1 = new_table()\n        model = self.Distance().fit(table1)\n        self.assertRaises(ValueError, model, new_table())\n        self.assertRaises(ValueError, model, table1, new_table())\n        self.assertRaises(ValueError, model, new_table(), table1)\n\n\nclass CommonNormalizedTests(CommonFittedTests):\n    \"\"\"Tests applicable to distances the have normalization\"\"\"\n\n    def test_zero_variance(self):\n        \"\"\"zero-variance columns have no effect on row distance\"\"\"\n        assert_almost_equal = np.testing.assert_almost_equal\n        normalized = self.Distance(axis=1, normalize=True)\n        nonnormalized = self.Distance(axis=1, normalize=False)\n\n        def is_same(d1, d2, fit1=None, fit2=None):\n            if fit1 is None:\n                fit1 = d1\n            if fit2 is None:\n                fit2 = d2\n            assert_almost_equal(normalized.fit(fit1)(d1),\n                                normalized.fit(fit2)(d2))\n            assert_almost_equal(nonnormalized.fit(fit1)(d1),\n                                nonnormalized.fit(fit2)(d2))\n\n        data = self.cont_data\n        n = len(data)\n        X = data.X\n        domain = Domain(data.domain.attributes + (ContinuousVariable(\"d\"),))\n        data_const = Table(domain, np.hstack((X, np.ones((n, 1)))))\n        data_nan = Table(domain, np.hstack((X, np.full((n, 1), np.nan))))\n        data_nan_1 = Table(domain, np.hstack((X, np.full((n, 1), np.nan))))\n        data_nan_1.X[0, -1] = 1\n        is_same(data, data_const)\n        is_same(data, data_nan)\n        is_same(data, data_nan_1)\n\n        # Test whether it's possible to fit with singular data and use the\n        # parameters on data where the same column is defined\n        is_same(data_nan, data_const, data_const)\n        is_same(data_const, data_const, data_nan)\n\n        self.assertRaises(ValueError, self.Distance,\n                          data_const, axis=0, normalize=True)\n        self.assertRaises(ValueError, self.Distance,\n                          data_nan, axis=0, normalize=True)\n        self.assertRaises(ValueError, self.Distance,\n                          data_nan_1, axis=0, normalize=True)\n\n    def test_mixed_cols(self):\n        \"\"\"distance over columns raises exception for discrete columns\"\"\"\n        self.assertRaises(ValueError, self.Distance, self.mixed_data, axis=0)\n        self.assertRaises(ValueError,\n                          self.Distance(axis=0).fit, self.mixed_data)\n\n\nclass FittedDistanceTest(unittest.TestCase):\n    @classmethod\n    def setUpClass(cls):\n        cls.attributes = (\n            ContinuousVariable(\"c1\"),\n            ContinuousVariable(\"c2\"),\n            ContinuousVariable(\"c3\"),\n            DiscreteVariable(\"d1\", values=[\"a\", \"b\"]),\n            DiscreteVariable(\"d2\", values=[\"a\", \"b\", \"c\", \"d\"]),\n            DiscreteVariable(\"d3\", values=[\"a\", \"b\", \"c\"]))\n        cls.domain = Domain(cls.attributes)\n        cls.cont_domain = Domain(cls.attributes[:3])\n        cls.disc_domain = Domain(cls.attributes[3:])\n\n    def setUp(self):\n        self.cont_data = Table.from_list(\n            self.cont_domain,\n            [[1, 3, 2],\n             [-1, 5, 0],\n             [1, 1, 1],\n             [7, 2, 3]])\n\n        self.cont_data2 = Table.from_list(\n            self.cont_domain,\n            [[2, 1, 3],\n             [1, 2, 2]]\n        )\n\n        self.disc_data = Table.from_list(\n            self.disc_domain,\n            [[0, 0, 0],\n             [0, 1, 1],\n             [1, 3, 1]]\n        )\n\n        self.disc_data4 = Table.from_list(\n            self.disc_domain,\n            [[0, 0, 0],\n             [0, 1, 1],\n             [0, 1, 1],\n             [1, 3, 1]]\n        )\n\n        self.mixed_data = self.data = Table.from_numpy(\n            self.domain, np.hstack((self.cont_data.X[:3], self.disc_data.X)))\n\n\n\n# Correct results in these tests were computed manually or with Excel;\n# these are not regression tests\nclass EuclideanDistanceTest(FittedDistanceTest, CommonNormalizedTests):\n    Distance = distance.Euclidean\n\n    def test_euclidean_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2, 3],\n                                              [2, 0, 2],\n                                              [3, 2, 0]])))\n\n        data.X[1, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]\n                            ])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2.5, 3],\n                                              [2.5, 0, 1.5],\n                                              [3, 1.5, 0]])))\n\n        data.X[0, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1, 0, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 1, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2, 2],\n                                              [2, 0, 1],\n                                              [2, 1, 0]])))\n\n        data = self.disc_data4\n        data.X[:2, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [3/4, 2/4, 1, 3/4],\n                             [3/4, 1/4, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 6/16, 1 - 10/16])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2.5, 2.5, 2.5],\n                                              [2.5, 0, 0.5, 1.5],\n                                              [2.5, 0.5, 0, 2],\n                                              [2.5, 1.5, 2, 0]])))\n\n    def test_euclidean_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            np.sqrt(np.array([[0, 12, 5, 38],\n                              [12, 0, 21, 82],\n                              [5, 21, 0, 41],\n                              [38, 82, 41, 0]])))\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 4.472135955, 2.236067977, 6.164414003],\n             [4.472135955, 0, 5.385164807, 6.480740698],\n             [2.236067977, 5.385164807, 0, 6.403124237],\n             [6.164414003, 6.480740698, 6.403124237, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 5.099019514, 4.795831523, 4.472135955],\n             [5.099019514, 0, 5.916079783, 6],\n             [4.795831523, 5.916079783, 0, 6.403124237],\n             [4.472135955, 6, 6.403124237, 0]])\n\n    def test_euclidean_cont_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [2, 2.75, 1.5])\n        assert_almost_equal(model.vars, [9, 2.1875, 1.25])\n        assert_almost_equal(model.dist_missing2_cont, [1, 1, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.654239383, 1.146423008, 1.621286967],\n             [1.654239383, 0, 2.068662631, 3.035242727],\n             [1.146423008, 2.068662631, 0, 1.956673562],\n             [1.621286967, 3.035242727, 1.956673562, 0]])\n\n        dist = distance.Euclidean(data, axis=1, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 1.654239383, 1.146423008, 1.621286967],\n             [1.654239383, 0, 2.068662631, 3.035242727],\n             [1.146423008, 2.068662631, 0, 1.956673562],\n             [1.621286967, 3.035242727, 1.956673562, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [3, 2.75, 1.5])\n        assert_almost_equal(model.vars, [8, 2.1875, 1.25])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.806733438, 1.146423008, 1.696635326],\n             [1.806733438, 0, 2.192519751, 2.675283697],\n             [1.146423008, 2.192519751, 0, 2.019547333],\n             [1.696635326, 2.675283697, 2.019547333, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [4, 2.75, 1.5])\n        assert_almost_equal(model.vars, [9, 2.1875, 1.25])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.874642823, 1.521277659, 1.276154939],\n             [1.874642823, 0, 2.248809209, 2.580143961],\n             [1.521277659, 2.248809209, 0, 1.956673562],\n             [1.276154939, 2.580143961, 1.956673562, 0]])\n\n    def test_euclidean_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 8.062257748, 4.242640687],\n             [8.062257748, 0, 5.196152423],\n             [4.242640687, 5.196152423, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 6.218252702, 4.242640687],\n             [6.218252702, 0, 2.581988897],\n             [4.242640687, 2.581988897, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 6.218252702, 5.830951895],\n             [6.218252702, 0, 2.581988897],\n             [5.830951895, 2.581988897, 0]])\n\n    def test_euclidean_cols_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2.455273959, 0.649839392],\n             [2.455273959, 0, 2.473176308],\n             [0.649839392, 2.473176308, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2, 0.649839392],\n             [2, 0, 1.704275472],\n             [0.649839392, 1.704275472, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2, 1.450046001],\n             [2, 0, 1.704275472],\n             [1.450046001, 1.704275472, 0]])\n\n    def test_euclidean_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n\n        assert_almost_equal(model.means, [1/3, 3, 1])\n        assert_almost_equal(model.vars, [8/9, 8/3, 2/3])\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_cont, [1, 1, 1])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.828427125, 2.121320344],\n             [2.828427125, 0, 2.828427125],\n             [2.121320344, 2.828427125, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        dist = distance.Euclidean(self.cont_data, self.cont_data2,\n                                  normalize=True)\n        assert_almost_equal(\n            dist,\n            [[1.17040218, 0.47809144],\n             [2.78516478, 1.96961039],\n             [1.28668394, 0.79282497],\n             [1.27179413, 1.54919334]])\n\n        model = distance.Euclidean(normalize=True).fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[1.17040218, 0.47809144],\n             [2.78516478, 1.96961039],\n             [1.28668394, 0.79282497],\n             [1.27179413, 1.54919334]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 0.827119692], [0.827119692, 0]])\n\n\nclass ManhattanDistanceTest(FittedDistanceTest, CommonNormalizedTests):\n    Distance = distance.Euclidean\n\n    # The data used for testing Euclidean distances unfortunately yields\n    # mads = 1, so we change it a bit\n    def setUp(self):\n        super().setUp()\n        self.cont_data = Table.from_list(\n            self.cont_domain,\n            [[1, 3, 2],\n             [-1, 6, 0],\n             [2, 7, 1],\n             [7, 1, 3]])\n\n    def test_manhattan_no_data(self):\n        np.testing.assert_almost_equal(\n            distance.Manhattan(Table(self.domain)),\n            np.zeros((0, 0)))\n        np.testing.assert_almost_equal(\n            distance.Manhattan(self.mixed_data, Table(self.domain)),\n            np.zeros((3, 0)))\n        np.testing.assert_almost_equal(\n            distance.Manhattan(Table(self.domain), self.mixed_data),\n            np.zeros((0, 3)))\n        self.assertRaises(\n            ValueError,\n            distance.Manhattan, Table(self.cont_domain), axis=0, normalize=True)\n\n    def test_manhattan_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2, 3],\n                             [2, 0, 2],\n                             [3, 2, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2.5, 3],\n                             [2.5, 0, 1.5],\n                             [3, 1.5, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1, 0, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 1, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2, 2],\n                             [2, 0, 1],\n                             [2, 1, 0]])\n\n        data = self.disc_data4\n        data.X[:2, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [3/4, 2/4, 1, 3/4],\n                             [3/4, 1/4, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 6/16, 1 - 10/16])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2.5, 2.5, 2.5],\n                             [2.5, 0, 0.5, 1.5],\n                             [2.5, 0.5, 0, 2],\n                             [2.5, 1.5, 2, 0]])\n\n    def test_manhattan_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 7, 6, 9],\n             [7, 0, 5, 16],\n             [6, 5, 0, 13],\n             [9, 16, 13, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 7, 6, 9],\n             [7, 0, 3, 14],\n             [6, 3, 0, 13],\n             [9, 14, 13, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 10, 10, 8],\n             [10, 0, 7, 13],\n             [10, 7, 0, 13],\n             [8, 13, 13, 0]])\n\n    def test_manhattan_cont_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [1.5, 4.5, 1.5])\n        assert_almost_equal(model.mads, [1.5, 2, 1])\n        assert_almost_equal(model.dist_missing2_cont, np.ones(3))\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.416666667, 1.833333333, 3],\n             [2.416666667, 0, 1.75, 5.416666667],\n             [1.833333333, 1.75, 0, 4.166666667],\n             [3, 5.416666667, 4.166666667, 0]])\n\n        dist = distance.Manhattan(data, axis=1, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2.416666667, 1.833333333, 3],\n             [2.416666667, 0, 1.75, 5.416666667],\n             [1.833333333, 1.75, 0, 4.166666667],\n             [3, 5.416666667, 4.166666667, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [2, 4.5, 1.5])\n        assert_almost_equal(model.mads, [1, 2, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.75, 2, 4],\n             [2.75, 0, 1.25, 5.75],\n             [2, 1.25, 0, 5],\n             [4, 5.75, 5, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [4.5, 4.5, 1.5])\n        assert_almost_equal(model.mads, [2.5, 2, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.75, 2.5, 2],\n             [2.75, 0, 1.75, 3.75],\n             [2.5, 1.75, 0, 3.5],\n             [2, 3.75, 3.5, 0]])\n\n    def test_manhattan_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 20, 7],\n             [20, 0, 15],\n             [7, 15, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 19, 7],\n             [19, 0, 14],\n             [7, 14, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 17, 9],\n             [17, 0, 14],\n             [9, 14, 0]])\n\n\n    def test_manhattan_cols_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 4.5833333, 2],\n             [4.5833333, 0, 4.25],\n             [2, 4.25, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 4.6666667, 2],\n             [4.6666667, 0, 4],\n             [2, 4, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 5.5, 4],\n             [5.5, 0, 4],\n             [4, 4, 0]])\n\n    def test_manhattan_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n\n        data.X[2, 0] = 2  # prevent mads[0] = 0\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [1, 3, 1])\n        assert_almost_equal(model.mads, [1, 2, 1])\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 4.5, 4.5],\n             [4.5, 0, 5],\n             [4.5, 5, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        dist = distance.Manhattan(self.cont_data, self.cont_data2,\n                                  normalize=True)\n        assert_almost_equal(\n            dist,\n            [[1.3333333, 0.25],\n             [3.75, 2.6666667],\n             [2.5, 2.0833333],\n             [1.6666667, 2.75]])\n\n        model = distance.Manhattan(normalize=True).fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[1.3333333, 0.25],\n             [3.75, 2.6666667],\n             [2.5, 2.0833333],\n             [1.6666667, 2.75]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 1.083333333], [1.083333333, 0]])\n\n    def test_manhattan_mixed_cols(self):\n        self.assertRaises(ValueError,\n                          distance.Manhattan, self.mixed_data, axis=0)\n        self.assertRaises(ValueError,\n                          distance.Manhattan(axis=0).fit, self.mixed_data)\n\n\nclass CosineDistanceTest(FittedDistanceTest, CommonFittedTests):\n    Distance = distance.Cosine\n\n    def test_no_data(self):\n        with patch(\"warnings.warn\") as warn:\n            super().test_no_data()\n            self.assertEqual(warn.call_args[0],\n                             (\"Mean of empty slice\", RuntimeWarning))\n\n    def test_cosine_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        data.X = np.array([[1, 0, 0],\n                           [0, 1, 1],\n                           [1, 3, 0]], dtype=float)\n\n        model = distance.Cosine().fit(data)\n        assert_almost_equal(model.means, [2 / 3, 2 / 3, 1 / 3])\n\n        dist = model(data)\n        assert_almost_equal(dist, 1 - np.array([[1, 0, 1 / sqrt(2)],\n                                                [0, 1, 0.5],\n                                                [1 / sqrt(2), 0.5, 1]]))\n\n        data.X[1, 1] = np.nan\n        model = distance.Cosine().fit(data)\n        assert_almost_equal(model.means, [2 / 3, 1 / 2, 1 / 3])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            1 - np.array([[1, 0, 1 / sqrt(2)],\n                          [0, 1, 0.5 / sqrt(1.25) / sqrt(2)],\n                          [1 / sqrt(2), 0.5 / sqrt(1.25) / sqrt(2), 1]]))\n\n        data.X = np.array([[1, 0, 0],\n                           [0, np.nan, 1],\n                           [1, np.nan, 1],\n                           [1, 3, 1]])\n        model = distance.Cosine().fit(data)\n        dist = model(data)\n        assert_almost_equal(model.means, [0.75, 0.5, 0.75])\n        assert_almost_equal(dist, [[0, 1, 0.333333333, 0.422649731],\n                                   [1, 0, 0.254644008, 0.225403331],\n                                   [0.333333333, 0.254644008, 0, 0.037749551],\n                                   [0.422649731, 0.225403331, 0.037749551, 0]])\n\n    def test_cosine_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.266200614, 0.0741799, 0.355097978],\n             [0.266200614, 0, 0.547089186, 0.925279678],\n             [0.0741799, 0.547089186, 0, 0.12011731],\n             [0.355097978, 0.925279678, 0.12011731, 0]]\n        )\n\n        data.X[1, 0] = np.nan\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.174971353, 0.0741799, 0.355097978],\n             [0.174971353, 0, 0.207881966, 0.324809395],\n             [0.0741799, 0.207881966, 0, 0.12011731],\n             [0.355097978, 0.324809395, 0.12011731, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.100977075, 0.035098719, 0.056666739],\n             [0.100977075, 0, 0.188497329, 0.246304671],\n             [0.035098719, 0.188497329, 0, 0.12011731],\n             [0.056666739, 0.246304671, 0.12011731, 0]])\n\n    def test_cosine_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n        data.X = np.array([[1, 3, 2, 1, 0, 0],\n                           [-1, 5, 0, 0, 1, 1],\n                           [1, 1, 1, 1, 3, 0]], dtype=float)\n\n        model = distance.Cosine(axis=1).fit(data)\n        assert_almost_equal(model.means, [1/3, 3, 1, 2/3, 2/3, 1/3])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 0.316869949, 0.191709623],\n             [0.316869949, 0, 0.577422873],\n             [0.191709623, 0.577422873, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        self.cont_data.X[1, 0] = np.nan\n        self.cont_data2.X[1, 0] = np.nan\n\n        dist = distance.Cosine(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[0.2142857, 0.1573352],\n             [0.4958158, 0.2097042],\n             [0.0741799, 0.0198039],\n             [0.1514447, 0.0451363]])\n\n        model = distance.Cosine().fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[0.2142857, 0.1573352],\n             [0.4958158, 0.2097042],\n             [0.0741799, 0.0198039],\n             [0.1514447, 0.0451363]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 0.092514787], [0.092514787, 0]])\n\n    def test_cosine_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.711324865, 0.11050082],\n             [0.711324865, 0, 0.44365136],\n             [0.11050082, 0.44365136, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.47702364, 0.11050082],\n             [0.47702364, 0, 0.181076975],\n             [0.11050082, 0.181076975, 0]])\n\n        data.X[1, 0] = np.nan\n        data.X[1, 2] = 2\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.269703257, 0.087129071],\n             [0.269703257, 0, 0.055555556],\n             [0.087129071, 0.055555556, 0]])\n\n\nclass JaccardDistanceTest(unittest.TestCase, CommonFittedTests):\n    Distance = distance.Jaccard\n\n    def setUp(self):\n        self.domain = Domain([DiscreteVariable(c) for c in \"abc\"])\n        self.data = Table(\n            self.domain,\n            [[0, 1, 1],\n             [1, 1, 1],\n             [1, 0, 1],\n             [1, 0, 0]])\n\n    def test_jaccard_rows(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 2/3, 1/3, 0],\n                          [2/3, 1, 2/3, 1/3],\n                          [1/3, 2/3, 1, 1/2],\n                          [0, 1/3, 1/2, 1]]))\n\n        X = self.data.X\n        X[1, 0] = X[2, 0] = X[3, 1] = np.nan\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, np.array([0.5, 2/3, 0.75]))\n\n        # pylint: disable=bad-whitespace\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[      1,        2 / 2.5,        1 / 2.5,        2/3 / 3],\n                          [2 / 2.5,              1,    1.25 / 2.75,  (1/2+2/3) / 3],\n                          [1 / 2.5,    1.25 / 2.75,              1,  0.5 / (2+2/3)],\n                          [2/3 / 3,  (1/2+2/3) / 3,  0.5 / (2+2/3),            1]]))\n\n    def test_jaccard_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 1/4, 1/2],\n                          [1/4, 1, 2/3],\n                          [1/2, 2/3, 1]]))\n\n        self.data.X = np.array([[0, 1, 1],\n                                [np.nan, np.nan, 1],\n                                [np.nan, 0, 1],\n                                [1, 1, 0]])\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.5, 2/3, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 0.4, 0.25],\n                          [0.4, 1, 5/12],\n                          [0.25, 5/12, 1]]))\n\n    def test_zero_instances(self):\n        \"Test all zero instances\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[0, 0, 0], [0, 0, 0], [0, 0, 1]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n        dist_dense = self.Distance(dense_data)\n        dist_sparse = self.Distance(sparse_data)\n\n        self.assertEqual(dist_dense[0][1], 0)\n        self.assertEqual(dist_sparse[0][1], 0)\n        self.assertEqual(dist_dense[0][2], 1)\n        self.assertEqual(dist_sparse[0][2], 1)\n\nclass HammingDistanceTest(FittedDistanceTest):\n    Distance = distance.Hamming\n\n    def test_hamming_col(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        dist = distance.Hamming(data, axis=0)\n\n        assert_almost_equal(\n            dist,\n            [[0, 2/3, 1/3],\n             [2/3, 0, 1/3],\n             [1/3, 1/3, 0]])\n\n    def test_hamming_row(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        dist = distance.Hamming(data)\n\n        assert_almost_equal(\n            dist,\n            [[0, 2/3, 1],\n             [2/3, 0, 2/3],\n             [1, 2/3, 0]]\n        )\n\nif __name__ == \"__main__\":\n    unittest.main()\n",
            "header": {
                "file": {
                    "path": "Orange/distance/tests/test_distance.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "e056619fb",
                "new_commit_hash": "5295014e8",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/distance/tests/test_distance.py"
            },
            "plus_file": {
                "path": "b/Orange/distance/tests/test_distance.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 892,
                            "length": 6
                        },
                        "new_range": {
                            "start": 892,
                            "length": 20
                        },
                        "section": "class JaccardDistanceTest(unittest.TestCase, CommonFittedTests):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                          [0.4, 1, 5/12],",
                                "type": "context"
                            },
                            {
                                "content": "                          [0.25, 5/12, 1]]))",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_zero_instances(self):",
                                "type": "added"
                            },
                            {
                                "content": "        \"Test all zero instances\"",
                                "type": "added"
                            },
                            {
                                "content": "        domain = Domain([ContinuousVariable(c) for c in \"abc\"])",
                                "type": "added"
                            },
                            {
                                "content": "        dense_data = Table.from_list(",
                                "type": "added"
                            },
                            {
                                "content": "            domain, [[0, 0, 0], [0, 0, 0], [0, 0, 1]])",
                                "type": "added"
                            },
                            {
                                "content": "        sparse_data = Table(domain, csr_matrix(dense_data.X))",
                                "type": "added"
                            },
                            {
                                "content": "        dist_dense = self.Distance(dense_data)",
                                "type": "added"
                            },
                            {
                                "content": "        dist_sparse = self.Distance(sparse_data)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(dist_dense[0][1], 0)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(dist_sparse[0][1], 0)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(dist_dense[0][2], 1)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(dist_sparse[0][2], 1)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "class HammingDistanceTest(FittedDistanceTest):",
                                "type": "context"
                            },
                            {
                                "content": "    Distance = distance.Hamming",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/distance/tests/test_distance.py",
                            "type": "class",
                            "name": "JaccardDistanceTest",
                            "content": "class JaccardDistanceTest(unittest.TestCase, CommonFittedTests):\n    Distance = distance.Jaccard\n\n    def setUp(self):\n        self.domain = Domain([DiscreteVariable(c) for c in \"abc\"])\n        self.data = Table(\n            self.domain,\n            [[0, 1, 1],\n             [1, 1, 1],\n             [1, 0, 1],\n             [1, 0, 0]])\n\n    def test_jaccard_rows(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 2/3, 1/3, 0],\n                          [2/3, 1, 2/3, 1/3],\n                          [1/3, 2/3, 1, 1/2],\n                          [0, 1/3, 1/2, 1]]))\n\n        X = self.data.X\n        X[1, 0] = X[2, 0] = X[3, 1] = np.nan\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, np.array([0.5, 2/3, 0.75]))\n\n        # pylint: disable=bad-whitespace\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[      1,        2 / 2.5,        1 / 2.5,        2/3 / 3],\n                          [2 / 2.5,              1,    1.25 / 2.75,  (1/2+2/3) / 3],\n                          [1 / 2.5,    1.25 / 2.75,              1,  0.5 / (2+2/3)],\n                          [2/3 / 3,  (1/2+2/3) / 3,  0.5 / (2+2/3),            1]]))\n\n    def test_jaccard_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 1/4, 1/2],\n                          [1/4, 1, 2/3],\n                          [1/2, 2/3, 1]]))\n\n        self.data.X = np.array([[0, 1, 1],\n                                [np.nan, np.nan, 1],\n                                [np.nan, 0, 1],\n                                [1, 1, 0]])\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.5, 2/3, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 0.4, 0.25],\n                          [0.4, 1, 5/12],\n                          [0.25, 5/12, 1]]))\n\n    def test_zero_instances(self):\n        \"Test all zero instances\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[0, 0, 0], [0, 0, 0], [0, 0, 1]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n        dist_dense = self.Distance(dense_data)\n        dist_sparse = self.Distance(sparse_data)\n\n        self.assertEqual(dist_dense[0][1], 0)\n        self.assertEqual(dist_sparse[0][1], 0)\n        self.assertEqual(dist_dense[0][2], 1)\n        self.assertEqual(dist_sparse[0][2], 1)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 836,
                            "end_lineno": 907,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "Orange/distance/tests/test_distance.py",
                            "type": "method",
                            "name": "JaccardDistanceTest.test_zero_instances",
                            "content": "class JaccardDistanceTest(unittest.TestCase, CommonFittedTests):\n    Distance = distance.Jaccard\n\n    def setUp(self):\n        self.domain = Domain([DiscreteVariable(c) for c in \"abc\"])\n        self.data = Table(\n            self.domain,\n            [[0, 1, 1],\n             [1, 1, 1],\n             [1, 0, 1],\n             [1, 0, 0]])\n\n    def test_jaccard_rows(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 2/3, 1/3, 0],\n                          [2/3, 1, 2/3, 1/3],\n                          [1/3, 2/3, 1, 1/2],\n                          [0, 1/3, 1/2, 1]]))\n\n        X = self.data.X\n        X[1, 0] = X[2, 0] = X[3, 1] = np.nan\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, np.array([0.5, 2/3, 0.75]))\n\n        # pylint: disable=bad-whitespace\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[      1,        2 / 2.5,        1 / 2.5,        2/3 / 3],\n                          [2 / 2.5,              1,    1.25 / 2.75,  (1/2+2/3) / 3],\n                          [1 / 2.5,    1.25 / 2.75,              1,  0.5 / (2+2/3)],\n                          [2/3 / 3,  (1/2+2/3) / 3,  0.5 / (2+2/3),            1]]))\n\n    def test_jaccard_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 1/4, 1/2],\n                          [1/4, 1, 2/3],\n                          [1/2, 2/3, 1]]))\n\n        self.data.X = np.array([[0, 1, 1],\n                                [np.nan, np.nan, 1],\n                                [np.nan, 0, 1],\n                                [1, 1, 0]])\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.5, 2/3, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 0.4, 0.25],\n                          [0.4, 1, 5/12],\n                          [0.25, 5/12, 1]]))\n\n    def test_zero_instances(self):\n        \"Test all zero instances\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[0, 0, 0], [0, 0, 0], [0, 0, 1]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n        dist_dense = self.Distance(dense_data)\n        dist_sparse = self.Distance(sparse_data)\n\n        self.assertEqual(dist_dense[0][1], 0)\n        self.assertEqual(dist_sparse[0][1], 0)\n        self.assertEqual(dist_dense[0][2], 1)\n        self.assertEqual(dist_sparse[0][2], 1)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 895,
                            "end_lineno": 907,
                            "parent": {
                                "file_name": "Orange/distance/tests/test_distance.py",
                                "type": "class",
                                "name": "JaccardDistanceTest",
                                "content": "class JaccardDistanceTest(unittest.TestCase, CommonFittedTests):\n    Distance = distance.Jaccard\n\n    def setUp(self):\n        self.domain = Domain([DiscreteVariable(c) for c in \"abc\"])\n        self.data = Table(\n            self.domain,\n            [[0, 1, 1],\n             [1, 1, 1],\n             [1, 0, 1],\n             [1, 0, 0]])\n\n    def test_jaccard_rows(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 2/3, 1/3, 0],\n                          [2/3, 1, 2/3, 1/3],\n                          [1/3, 2/3, 1, 1/2],\n                          [0, 1/3, 1/2, 1]]))\n\n        X = self.data.X\n        X[1, 0] = X[2, 0] = X[3, 1] = np.nan\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, np.array([0.5, 2/3, 0.75]))\n\n        # pylint: disable=bad-whitespace\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[      1,        2 / 2.5,        1 / 2.5,        2/3 / 3],\n                          [2 / 2.5,              1,    1.25 / 2.75,  (1/2+2/3) / 3],\n                          [1 / 2.5,    1.25 / 2.75,              1,  0.5 / (2+2/3)],\n                          [2/3 / 3,  (1/2+2/3) / 3,  0.5 / (2+2/3),            1]]))\n\n    def test_jaccard_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 1/4, 1/2],\n                          [1/4, 1, 2/3],\n                          [1/2, 2/3, 1]]))\n\n        self.data.X = np.array([[0, 1, 1],\n                                [np.nan, np.nan, 1],\n                                [np.nan, 0, 1],\n                                [1, 1, 0]])\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.5, 2/3, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 0.4, 0.25],\n                          [0.4, 1, 5/12],\n                          [0.25, 5/12, 1]]))\n\n    def test_zero_instances(self):\n        \"Test all zero instances\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[0, 0, 0], [0, 0, 0], [0, 0, 1]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n        dist_dense = self.Distance(dense_data)\n        dist_sparse = self.Distance(sparse_data)\n\n        self.assertEqual(dist_dense[0][1], 0)\n        self.assertEqual(dist_sparse[0][1], 0)\n        self.assertEqual(dist_dense[0][2], 1)\n        self.assertEqual(dist_sparse[0][2], 1)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 836,
                                "end_lineno": 907,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "1a9c4b531e63bbdf5777895ed406c5441453dd69^",
    "new_commit_hash": "1a9c4b531e63bbdf5777895ed406c5441453dd69",
    "commit_message": "Merge pull request #3683 from ajdapretnar/jaccard-zero-division\n\n[WIP] distance.py: fix zero division in Jaccard",
    "commit_date": "2019-03-19T18:32:56+01:00",
    "metadata": {}
}
{
    "repo_name": "orange3",
    "new_commit_hash": "1a9c4b531e63bbdf5777895ed406c5441453dd69",
    "test_file_codes": [
        "import unittest\nfrom unittest.mock import patch\nfrom math import sqrt\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix\n\nfrom Orange.data import ContinuousVariable, DiscreteVariable, Domain, Table\nfrom Orange import distance\n\n\nclass CommonTests:\n    \"\"\"Tests applicable to all distance measures\"\"\"\n\n    def test_no_data(self):\n        \"\"\"distances return zero-dimensional matrices when no data\"\"\"\n        n = len(self.data)\n        np.testing.assert_almost_equal(\n            self.Distance(Table(self.domain)),\n            np.zeros((0, 0)))\n        np.testing.assert_almost_equal(\n            self.Distance(self.data, Table(self.domain)),\n            np.zeros((n, 0)))\n        np.testing.assert_almost_equal(\n            self.Distance(Table(self.domain), self.data),\n            np.zeros((0, n)))\n\n    def test_sparse(self):\n        \"\"\"Test sparse support in distances.\"\"\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[1, 0, 2], [-1, 5, 0], [0, 1, 1], [7, 0, 0]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n\n        if not self.Distance.supports_sparse:\n            self.assertRaises(TypeError, self.Distance, sparse_data)\n        else:\n            # check the result is the same for sparse and dense\n            dist_dense = self.Distance(dense_data)\n            dist_sparse = self.Distance(sparse_data)\n            np.testing.assert_allclose(dist_sparse, dist_dense)\n\n\nclass CommonFittedTests(CommonTests):\n    \"\"\"Tests applicable to all distances with fitting\"\"\"\n    def test_mismatching_attributes(self):\n        \"\"\"distances can't be computed if fit from other attributes\"\"\"\n        def new_table():\n            return Table.from_list(Domain([ContinuousVariable(\"a\")]), [[1]])\n\n        table1 = new_table()\n        model = self.Distance().fit(table1)\n        self.assertRaises(ValueError, model, new_table())\n        self.assertRaises(ValueError, model, table1, new_table())\n        self.assertRaises(ValueError, model, new_table(), table1)\n\n\nclass CommonNormalizedTests(CommonFittedTests):\n    \"\"\"Tests applicable to distances the have normalization\"\"\"\n\n    def test_zero_variance(self):\n        \"\"\"zero-variance columns have no effect on row distance\"\"\"\n        assert_almost_equal = np.testing.assert_almost_equal\n        normalized = self.Distance(axis=1, normalize=True)\n        nonnormalized = self.Distance(axis=1, normalize=False)\n\n        def is_same(d1, d2, fit1=None, fit2=None):\n            if fit1 is None:\n                fit1 = d1\n            if fit2 is None:\n                fit2 = d2\n            assert_almost_equal(normalized.fit(fit1)(d1),\n                                normalized.fit(fit2)(d2))\n            assert_almost_equal(nonnormalized.fit(fit1)(d1),\n                                nonnormalized.fit(fit2)(d2))\n\n        data = self.cont_data\n        n = len(data)\n        X = data.X\n        domain = Domain(data.domain.attributes + (ContinuousVariable(\"d\"),))\n        data_const = Table(domain, np.hstack((X, np.ones((n, 1)))))\n        data_nan = Table(domain, np.hstack((X, np.full((n, 1), np.nan))))\n        data_nan_1 = Table(domain, np.hstack((X, np.full((n, 1), np.nan))))\n        data_nan_1.X[0, -1] = 1\n        is_same(data, data_const)\n        is_same(data, data_nan)\n        is_same(data, data_nan_1)\n\n        # Test whether it's possible to fit with singular data and use the\n        # parameters on data where the same column is defined\n        is_same(data_nan, data_const, data_const)\n        is_same(data_const, data_const, data_nan)\n\n        self.assertRaises(ValueError, self.Distance,\n                          data_const, axis=0, normalize=True)\n        self.assertRaises(ValueError, self.Distance,\n                          data_nan, axis=0, normalize=True)\n        self.assertRaises(ValueError, self.Distance,\n                          data_nan_1, axis=0, normalize=True)\n\n    def test_mixed_cols(self):\n        \"\"\"distance over columns raises exception for discrete columns\"\"\"\n        self.assertRaises(ValueError, self.Distance, self.mixed_data, axis=0)\n        self.assertRaises(ValueError,\n                          self.Distance(axis=0).fit, self.mixed_data)\n\n\nclass FittedDistanceTest(unittest.TestCase):\n    @classmethod\n    def setUpClass(cls):\n        cls.attributes = (\n            ContinuousVariable(\"c1\"),\n            ContinuousVariable(\"c2\"),\n            ContinuousVariable(\"c3\"),\n            DiscreteVariable(\"d1\", values=[\"a\", \"b\"]),\n            DiscreteVariable(\"d2\", values=[\"a\", \"b\", \"c\", \"d\"]),\n            DiscreteVariable(\"d3\", values=[\"a\", \"b\", \"c\"]))\n        cls.domain = Domain(cls.attributes)\n        cls.cont_domain = Domain(cls.attributes[:3])\n        cls.disc_domain = Domain(cls.attributes[3:])\n\n    def setUp(self):\n        self.cont_data = Table.from_list(\n            self.cont_domain,\n            [[1, 3, 2],\n             [-1, 5, 0],\n             [1, 1, 1],\n             [7, 2, 3]])\n\n        self.cont_data2 = Table.from_list(\n            self.cont_domain,\n            [[2, 1, 3],\n             [1, 2, 2]]\n        )\n\n        self.disc_data = Table.from_list(\n            self.disc_domain,\n            [[0, 0, 0],\n             [0, 1, 1],\n             [1, 3, 1]]\n        )\n\n        self.disc_data4 = Table.from_list(\n            self.disc_domain,\n            [[0, 0, 0],\n             [0, 1, 1],\n             [0, 1, 1],\n             [1, 3, 1]]\n        )\n\n        self.mixed_data = self.data = Table.from_numpy(\n            self.domain, np.hstack((self.cont_data.X[:3], self.disc_data.X)))\n\n\n\n# Correct results in these tests were computed manually or with Excel;\n# these are not regression tests\nclass EuclideanDistanceTest(FittedDistanceTest, CommonNormalizedTests):\n    Distance = distance.Euclidean\n\n    def test_euclidean_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2, 3],\n                                              [2, 0, 2],\n                                              [3, 2, 0]])))\n\n        data.X[1, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]\n                            ])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2.5, 3],\n                                              [2.5, 0, 1.5],\n                                              [3, 1.5, 0]])))\n\n        data.X[0, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1, 0, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 1, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2, 2],\n                                              [2, 0, 1],\n                                              [2, 1, 0]])))\n\n        data = self.disc_data4\n        data.X[:2, 0] = np.nan\n        model = distance.Euclidean().fit(data)\n\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [3/4, 2/4, 1, 3/4],\n                             [3/4, 1/4, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 6/16, 1 - 10/16])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            np.sqrt(np.array([[0, 2.5, 2.5, 2.5],\n                                              [2.5, 0, 0.5, 1.5],\n                                              [2.5, 0.5, 0, 2],\n                                              [2.5, 1.5, 2, 0]])))\n\n    def test_euclidean_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            np.sqrt(np.array([[0, 12, 5, 38],\n                              [12, 0, 21, 82],\n                              [5, 21, 0, 41],\n                              [38, 82, 41, 0]])))\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 4.472135955, 2.236067977, 6.164414003],\n             [4.472135955, 0, 5.385164807, 6.480740698],\n             [2.236067977, 5.385164807, 0, 6.403124237],\n             [6.164414003, 6.480740698, 6.403124237, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Euclidean(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 5.099019514, 4.795831523, 4.472135955],\n             [5.099019514, 0, 5.916079783, 6],\n             [4.795831523, 5.916079783, 0, 6.403124237],\n             [4.472135955, 6, 6.403124237, 0]])\n\n    def test_euclidean_cont_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [2, 2.75, 1.5])\n        assert_almost_equal(model.vars, [9, 2.1875, 1.25])\n        assert_almost_equal(model.dist_missing2_cont, [1, 1, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.654239383, 1.146423008, 1.621286967],\n             [1.654239383, 0, 2.068662631, 3.035242727],\n             [1.146423008, 2.068662631, 0, 1.956673562],\n             [1.621286967, 3.035242727, 1.956673562, 0]])\n\n        dist = distance.Euclidean(data, axis=1, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 1.654239383, 1.146423008, 1.621286967],\n             [1.654239383, 0, 2.068662631, 3.035242727],\n             [1.146423008, 2.068662631, 0, 1.956673562],\n             [1.621286967, 3.035242727, 1.956673562, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [3, 2.75, 1.5])\n        assert_almost_equal(model.vars, [8, 2.1875, 1.25])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.806733438, 1.146423008, 1.696635326],\n             [1.806733438, 0, 2.192519751, 2.675283697],\n             [1.146423008, 2.192519751, 0, 2.019547333],\n             [1.696635326, 2.675283697, 2.019547333, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.means, [4, 2.75, 1.5])\n        assert_almost_equal(model.vars, [9, 2.1875, 1.25])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 1.874642823, 1.521277659, 1.276154939],\n             [1.874642823, 0, 2.248809209, 2.580143961],\n             [1.521277659, 2.248809209, 0, 1.956673562],\n             [1.276154939, 2.580143961, 1.956673562, 0]])\n\n    def test_euclidean_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 8.062257748, 4.242640687],\n             [8.062257748, 0, 5.196152423],\n             [4.242640687, 5.196152423, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 6.218252702, 4.242640687],\n             [6.218252702, 0, 2.581988897],\n             [4.242640687, 2.581988897, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 6.218252702, 5.830951895],\n             [6.218252702, 0, 2.581988897],\n             [5.830951895, 2.581988897, 0]])\n\n    def test_euclidean_cols_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2.455273959, 0.649839392],\n             [2.455273959, 0, 2.473176308],\n             [0.649839392, 2.473176308, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2, 0.649839392],\n             [2, 0, 1.704275472],\n             [0.649839392, 1.704275472, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Euclidean(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2, 1.450046001],\n             [2, 0, 1.704275472],\n             [1.450046001, 1.704275472, 0]])\n\n    def test_euclidean_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n\n        model = distance.Euclidean(axis=1, normalize=True).fit(data)\n\n        assert_almost_equal(model.means, [1/3, 3, 1])\n        assert_almost_equal(model.vars, [8/9, 8/3, 2/3])\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_cont, [1, 1, 1])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.828427125, 2.121320344],\n             [2.828427125, 0, 2.828427125],\n             [2.121320344, 2.828427125, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        dist = distance.Euclidean(self.cont_data, self.cont_data2,\n                                  normalize=True)\n        assert_almost_equal(\n            dist,\n            [[1.17040218, 0.47809144],\n             [2.78516478, 1.96961039],\n             [1.28668394, 0.79282497],\n             [1.27179413, 1.54919334]])\n\n        model = distance.Euclidean(normalize=True).fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[1.17040218, 0.47809144],\n             [2.78516478, 1.96961039],\n             [1.28668394, 0.79282497],\n             [1.27179413, 1.54919334]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 0.827119692], [0.827119692, 0]])\n\n\nclass ManhattanDistanceTest(FittedDistanceTest, CommonNormalizedTests):\n    Distance = distance.Euclidean\n\n    # The data used for testing Euclidean distances unfortunately yields\n    # mads = 1, so we change it a bit\n    def setUp(self):\n        super().setUp()\n        self.cont_data = Table.from_list(\n            self.cont_domain,\n            [[1, 3, 2],\n             [-1, 6, 0],\n             [2, 7, 1],\n             [7, 1, 3]])\n\n    def test_manhattan_no_data(self):\n        np.testing.assert_almost_equal(\n            distance.Manhattan(Table(self.domain)),\n            np.zeros((0, 0)))\n        np.testing.assert_almost_equal(\n            distance.Manhattan(self.mixed_data, Table(self.domain)),\n            np.zeros((3, 0)))\n        np.testing.assert_almost_equal(\n            distance.Manhattan(Table(self.domain), self.mixed_data),\n            np.zeros((0, 3)))\n        self.assertRaises(\n            ValueError,\n            distance.Manhattan, Table(self.cont_domain), axis=0, normalize=True)\n\n    def test_manhattan_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2, 3],\n                             [2, 0, 2],\n                             [3, 2, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2.5, 3],\n                             [2.5, 0, 1.5],\n                             [3, 1.5, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1, 0, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 1, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2, 2],\n                             [2, 0, 1],\n                             [2, 1, 0]])\n\n        data = self.disc_data4\n        data.X[:2, 0] = np.nan\n        model = distance.Manhattan().fit(data)\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/2, 1/2, 1, 1],\n                             [3/4, 2/4, 1, 3/4],\n                             [3/4, 1/4, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 2/4, 1 - 6/16, 1 - 10/16])\n\n        dist = model(data)\n        assert_almost_equal(dist,\n                            [[0, 2.5, 2.5, 2.5],\n                             [2.5, 0, 0.5, 1.5],\n                             [2.5, 0.5, 0, 2],\n                             [2.5, 1.5, 2, 0]])\n\n    def test_manhattan_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 7, 6, 9],\n             [7, 0, 5, 16],\n             [6, 5, 0, 13],\n             [9, 16, 13, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 7, 6, 9],\n             [7, 0, 3, 14],\n             [6, 3, 0, 13],\n             [9, 14, 13, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Manhattan(data, axis=1, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 10, 10, 8],\n             [10, 0, 7, 13],\n             [10, 7, 0, 13],\n             [8, 13, 13, 0]])\n\n    def test_manhattan_cont_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [1.5, 4.5, 1.5])\n        assert_almost_equal(model.mads, [1.5, 2, 1])\n        assert_almost_equal(model.dist_missing2_cont, np.ones(3))\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.416666667, 1.833333333, 3],\n             [2.416666667, 0, 1.75, 5.416666667],\n             [1.833333333, 1.75, 0, 4.166666667],\n             [3, 5.416666667, 4.166666667, 0]])\n\n        dist = distance.Manhattan(data, axis=1, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 2.416666667, 1.833333333, 3],\n             [2.416666667, 0, 1.75, 5.416666667],\n             [1.833333333, 1.75, 0, 4.166666667],\n             [3, 5.416666667, 4.166666667, 0]])\n\n        data.X[1, 0] = np.nan\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [2, 4.5, 1.5])\n        assert_almost_equal(model.mads, [1, 2, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.75, 2, 4],\n             [2.75, 0, 1.25, 5.75],\n             [2, 1.25, 0, 5],\n             [4, 5.75, 5, 0]])\n\n        data.X[0, 0] = np.nan\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [4.5, 4.5, 1.5])\n        assert_almost_equal(model.mads, [2.5, 2, 1])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 2.75, 2.5, 2],\n             [2.75, 0, 1.75, 3.75],\n             [2.5, 1.75, 0, 3.5],\n             [2, 3.75, 3.5, 0]])\n\n    def test_manhattan_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 20, 7],\n             [20, 0, 15],\n             [7, 15, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 19, 7],\n             [19, 0, 14],\n             [7, 14, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 17, 9],\n             [17, 0, 14],\n             [9, 14, 0]])\n\n\n    def test_manhattan_cols_normalized(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 4.5833333, 2],\n             [4.5833333, 0, 4.25],\n             [2, 4.25, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 4.6666667, 2],\n             [4.6666667, 0, 4],\n             [2, 4, 0]])\n\n        data.X[1, 0] = np.nan\n        dist = distance.Manhattan(data, axis=0, normalize=True)\n        assert_almost_equal(\n            dist,\n            [[0, 5.5, 4],\n             [5.5, 0, 4],\n             [4, 4, 0]])\n\n    def test_manhattan_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n\n        data.X[2, 0] = 2  # prevent mads[0] = 0\n        model = distance.Manhattan(axis=1, normalize=True).fit(data)\n        assert_almost_equal(model.medians, [1, 3, 1])\n        assert_almost_equal(model.mads, [1, 2, 1])\n        assert_almost_equal(model.dist_missing_disc,\n                            [[1/3, 2/3, 1, 1],\n                             [2/3, 2/3, 1, 2/3],\n                             [2/3, 1/3, 1, 1]])\n        assert_almost_equal(model.dist_missing2_disc,\n                            [1 - 5/9, 1 - 3/9, 1 - 5/9])\n\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 4.5, 4.5],\n             [4.5, 0, 5],\n             [4.5, 5, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        dist = distance.Manhattan(self.cont_data, self.cont_data2,\n                                  normalize=True)\n        assert_almost_equal(\n            dist,\n            [[1.3333333, 0.25],\n             [3.75, 2.6666667],\n             [2.5, 2.0833333],\n             [1.6666667, 2.75]])\n\n        model = distance.Manhattan(normalize=True).fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[1.3333333, 0.25],\n             [3.75, 2.6666667],\n             [2.5, 2.0833333],\n             [1.6666667, 2.75]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 1.083333333], [1.083333333, 0]])\n\n    def test_manhattan_mixed_cols(self):\n        self.assertRaises(ValueError,\n                          distance.Manhattan, self.mixed_data, axis=0)\n        self.assertRaises(ValueError,\n                          distance.Manhattan(axis=0).fit, self.mixed_data)\n\n\nclass CosineDistanceTest(FittedDistanceTest, CommonFittedTests):\n    Distance = distance.Cosine\n\n    def test_no_data(self):\n        with patch(\"warnings.warn\") as warn:\n            super().test_no_data()\n            self.assertEqual(warn.call_args[0],\n                             (\"Mean of empty slice\", RuntimeWarning))\n\n    def test_cosine_disc(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        data.X = np.array([[1, 0, 0],\n                           [0, 1, 1],\n                           [1, 3, 0]], dtype=float)\n\n        model = distance.Cosine().fit(data)\n        assert_almost_equal(model.means, [2 / 3, 2 / 3, 1 / 3])\n\n        dist = model(data)\n        assert_almost_equal(dist, 1 - np.array([[1, 0, 1 / sqrt(2)],\n                                                [0, 1, 0.5],\n                                                [1 / sqrt(2), 0.5, 1]]))\n\n        data.X[1, 1] = np.nan\n        model = distance.Cosine().fit(data)\n        assert_almost_equal(model.means, [2 / 3, 1 / 2, 1 / 3])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            1 - np.array([[1, 0, 1 / sqrt(2)],\n                          [0, 1, 0.5 / sqrt(1.25) / sqrt(2)],\n                          [1 / sqrt(2), 0.5 / sqrt(1.25) / sqrt(2), 1]]))\n\n        data.X = np.array([[1, 0, 0],\n                           [0, np.nan, 1],\n                           [1, np.nan, 1],\n                           [1, 3, 1]])\n        model = distance.Cosine().fit(data)\n        dist = model(data)\n        assert_almost_equal(model.means, [0.75, 0.5, 0.75])\n        assert_almost_equal(dist, [[0, 1, 0.333333333, 0.422649731],\n                                   [1, 0, 0.254644008, 0.225403331],\n                                   [0.333333333, 0.254644008, 0, 0.037749551],\n                                   [0.422649731, 0.225403331, 0.037749551, 0]])\n\n    def test_cosine_cont(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.266200614, 0.0741799, 0.355097978],\n             [0.266200614, 0, 0.547089186, 0.925279678],\n             [0.0741799, 0.547089186, 0, 0.12011731],\n             [0.355097978, 0.925279678, 0.12011731, 0]]\n        )\n\n        data.X[1, 0] = np.nan\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.174971353, 0.0741799, 0.355097978],\n             [0.174971353, 0, 0.207881966, 0.324809395],\n             [0.0741799, 0.207881966, 0, 0.12011731],\n             [0.355097978, 0.324809395, 0.12011731, 0]])\n\n        data.X[0, 0] = np.nan\n        dist = distance.Cosine(data, axis=1)\n        assert_almost_equal(\n            dist,\n            [[0, 0.100977075, 0.035098719, 0.056666739],\n             [0.100977075, 0, 0.188497329, 0.246304671],\n             [0.035098719, 0.188497329, 0, 0.12011731],\n             [0.056666739, 0.246304671, 0.12011731, 0]])\n\n    def test_cosine_mixed(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.mixed_data\n        data.X = np.array([[1, 3, 2, 1, 0, 0],\n                           [-1, 5, 0, 0, 1, 1],\n                           [1, 1, 1, 1, 3, 0]], dtype=float)\n\n        model = distance.Cosine(axis=1).fit(data)\n        assert_almost_equal(model.means, [1/3, 3, 1, 2/3, 2/3, 1/3])\n        dist = model(data)\n        assert_almost_equal(\n            dist,\n            [[0, 0.316869949, 0.191709623],\n             [0.316869949, 0, 0.577422873],\n             [0.191709623, 0.577422873, 0]])\n\n    def test_two_tables(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        self.cont_data.X[1, 0] = np.nan\n        self.cont_data2.X[1, 0] = np.nan\n\n        dist = distance.Cosine(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[0.2142857, 0.1573352],\n             [0.4958158, 0.2097042],\n             [0.0741799, 0.0198039],\n             [0.1514447, 0.0451363]])\n\n        model = distance.Cosine().fit(self.cont_data)\n        dist = model(self.cont_data, self.cont_data2)\n        assert_almost_equal(\n            dist,\n            [[0.2142857, 0.1573352],\n             [0.4958158, 0.2097042],\n             [0.0741799, 0.0198039],\n             [0.1514447, 0.0451363]])\n\n        dist = model(self.cont_data2)\n        assert_almost_equal(dist, [[0, 0.092514787], [0.092514787, 0]])\n\n    def test_cosine_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.cont_data\n\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.711324865, 0.11050082],\n             [0.711324865, 0, 0.44365136],\n             [0.11050082, 0.44365136, 0]])\n\n        data.X[1, 1] = np.nan\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.47702364, 0.11050082],\n             [0.47702364, 0, 0.181076975],\n             [0.11050082, 0.181076975, 0]])\n\n        data.X[1, 0] = np.nan\n        data.X[1, 2] = 2\n        dist = distance.Cosine(data, axis=0, normalize=False)\n        assert_almost_equal(\n            dist,\n            [[0, 0.269703257, 0.087129071],\n             [0.269703257, 0, 0.055555556],\n             [0.087129071, 0.055555556, 0]])\n\n\nclass JaccardDistanceTest(unittest.TestCase, CommonFittedTests):\n    Distance = distance.Jaccard\n\n    def setUp(self):\n        self.domain = Domain([DiscreteVariable(c) for c in \"abc\"])\n        self.data = Table(\n            self.domain,\n            [[0, 1, 1],\n             [1, 1, 1],\n             [1, 0, 1],\n             [1, 0, 0]])\n\n    def test_jaccard_rows(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 2/3, 1/3, 0],\n                          [2/3, 1, 2/3, 1/3],\n                          [1/3, 2/3, 1, 1/2],\n                          [0, 1/3, 1/2, 1]]))\n\n        X = self.data.X\n        X[1, 0] = X[2, 0] = X[3, 1] = np.nan\n        model = distance.Jaccard().fit(self.data)\n        assert_almost_equal(model.ps, np.array([0.5, 2/3, 0.75]))\n\n        # pylint: disable=bad-whitespace\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[      1,        2 / 2.5,        1 / 2.5,        2/3 / 3],\n                          [2 / 2.5,              1,    1.25 / 2.75,  (1/2+2/3) / 3],\n                          [1 / 2.5,    1.25 / 2.75,              1,  0.5 / (2+2/3)],\n                          [2/3 / 3,  (1/2+2/3) / 3,  0.5 / (2+2/3),            1]]))\n\n    def test_jaccard_cols(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.75, 0.5, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 1/4, 1/2],\n                          [1/4, 1, 2/3],\n                          [1/2, 2/3, 1]]))\n\n        self.data.X = np.array([[0, 1, 1],\n                                [np.nan, np.nan, 1],\n                                [np.nan, 0, 1],\n                                [1, 1, 0]])\n        model = distance.Jaccard(axis=0).fit(self.data)\n        assert_almost_equal(model.ps, [0.5, 2/3, 0.75])\n        assert_almost_equal(\n            model(self.data),\n            1 - np.array([[1, 0.4, 0.25],\n                          [0.4, 1, 5/12],\n                          [0.25, 5/12, 1]]))\n\n    def test_zero_instances(self):\n        \"Test all zero instances\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[0, 0, 0], [0, 0, 0], [0, 0, 1]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n        dist_dense = self.Distance(dense_data)\n        dist_sparse = self.Distance(sparse_data)\n\n        self.assertEqual(dist_dense[0][1], 0)\n        self.assertEqual(dist_sparse[0][1], 0)\n        self.assertEqual(dist_dense[0][2], 1)\n        self.assertEqual(dist_sparse[0][2], 1)\n\nclass HammingDistanceTest(FittedDistanceTest):\n    Distance = distance.Hamming\n\n    def test_hamming_col(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        dist = distance.Hamming(data, axis=0)\n\n        assert_almost_equal(\n            dist,\n            [[0, 2/3, 1/3],\n             [2/3, 0, 1/3],\n             [1/3, 1/3, 0]])\n\n    def test_hamming_row(self):\n        assert_almost_equal = np.testing.assert_almost_equal\n        data = self.disc_data\n        dist = distance.Hamming(data)\n\n        assert_almost_equal(\n            dist,\n            [[0, 2/3, 1],\n             [2/3, 0, 2/3],\n             [1, 2/3, 0]]\n        )\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Orange installation attempts...\nAttempting installation with Python 3.7...\nWarning: 'keywords' should be a list, got type 'tuple'\nWarning: 'classifiers' should be a list, got type 'tuple'\nWarning: 'keywords' should be a list, got type 'tuple'\nWarning: 'classifiers' should be a list, got type 'tuple'\nrunning build_ext\nrunning build_src\nbuild_src\nbuilding extension \"Orange.classification._simple_tree\" sources\nbuilding extension \"Orange.classification._tree_scorers\" sources\nbuilding extension \"Orange.data._valuecount\" sources\nbuilding extension \"Orange.data._contingency\" sources\nbuilding extension \"Orange.data._io\" sources\nbuilding extension \"Orange.data._variable\" sources\nbuilding extension \"Orange.distance._distance\" sources\nbuilding extension \"Orange.preprocess._discretize\" sources\nbuilding extension \"Orange.preprocess._relieff\" sources\nbuilding extension \"Orange.widgets.utils._grid_density\" sources\nbuild_src: building npy-pkg config files\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmp2sszd5g9/tmp\ncreating /tmp/tmp2sszd5g9/tmp/tmp2sszd5g9\ncompile options: '-MMD -MF /tmp/tmp2sszd5g9/file.c.d -c'\ncc: /tmp/tmp2sszd5g9/file.c\ncustomize UnixCCompiler using build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmpbdstm7se/tmp\ncreating /tmp/tmpbdstm7se/tmp/tmpbdstm7se\ncompile options: '-MMD -MF /tmp/tmpbdstm7se/file.c.d -c'\ncc: /tmp/tmpbdstm7se/file.c\ncustomize UnixCCompiler using build_ext\nbuilding 'Orange.classification._simple_tree' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange\ncreating build/temp.linux-x86_64-3.7/Orange/classification\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/classification/_simple_tree.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_simple_tree.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.classification._tree_scorers' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/classification/_tree_scorers.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_tree_scorers.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._valuecount' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/data\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_valuecount.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_valuecount.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._contingency' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_contingency.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_contingency.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._io' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_io.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_io.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_io.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._variable' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_variable.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_variable.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.distance._distance' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/distance\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/distance/_distance.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/distance/_distance.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._discretize' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/preprocess\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/preprocess/_discretize.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_discretize.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._relieff' extension\ncompiling C++ sources\nC compiler: c++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\nc++: Orange/preprocess/_relieff.cpp\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_relieff.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.widgets.utils._grid_density' extension\ncompiling C++ sources\nC compiler: c++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/widgets\ncreating build/temp.linux-x86_64-3.7/Orange/widgets/utils\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\nc++: Orange/widgets/utils/_grid_density.cpp\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so\nWarning: 'keywords' should be a list, got type 'tuple'\nWarning: 'classifiers' should be a list, got type 'tuple'\nWarning: 'keywords' should be a list, got type 'tuple'\nWarning: 'classifiers' should be a list, got type 'tuple'\nrunning develop\nrunning build_scripts\nrunning egg_info\nrunning build_src\nbuild_src\nbuilding extension \"Orange.classification._simple_tree\" sources\nbuilding extension \"Orange.classification._tree_scorers\" sources\nbuilding extension \"Orange.data._valuecount\" sources\nbuilding extension \"Orange.data._contingency\" sources\nbuilding extension \"Orange.data._io\" sources\nbuilding extension \"Orange.data._variable\" sources\nbuilding extension \"Orange.distance._distance\" sources\nbuilding extension \"Orange.preprocess._discretize\" sources\nbuilding extension \"Orange.preprocess._relieff\" sources\nbuilding extension \"Orange.widgets.utils._grid_density\" sources\nbuild_src: building npy-pkg config files\ncreating Orange3.egg-info\nwriting Orange3.egg-info/PKG-INFO\nwriting dependency_links to Orange3.egg-info/dependency_links.txt\nwriting entry points to Orange3.egg-info/entry_points.txt\nwriting requirements to Orange3.egg-info/requires.txt\nwriting top-level names to Orange3.egg-info/top_level.txt\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest template 'MANIFEST.in'\nwarning: no files found matching 'README*' under directory 'Orange'\nwarning: no files found matching 'LICENSE' under directory 'Orange'\nwarning: no files found matching '*.basket' under directory 'Orange/datasets'\nwarning: no files found matching '*.html' under directory 'Orange/canvas'\nwarning: no files found matching '*.css' under directory 'Orange/widgets'\nwarning: no files found matching 'COPYING'\nadding license file 'LICENSE'\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nrunning build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmpy0uuw0e9/tmp\ncreating /tmp/tmpy0uuw0e9/tmp/tmpy0uuw0e9\ncompile options: '-MMD -MF /tmp/tmpy0uuw0e9/file.c.d -c'\ncc: /tmp/tmpy0uuw0e9/file.c\ncustomize UnixCCompiler using build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmpqu_gz_lu/tmp\ncreating /tmp/tmpqu_gz_lu/tmp/tmpqu_gz_lu\ncompile options: '-MMD -MF /tmp/tmpqu_gz_lu/file.c.d -c'\ncc: /tmp/tmpqu_gz_lu/file.c\ncustomize UnixCCompiler using build_ext\nCreating /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/Orange3.egg-link (link to .)\nAdding Orange3 3.21.0.dev0+1a9c4b5 to easy-install.pth file\nInstalling orange-canvas script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69\nProcessing dependencies for Orange3==3.21.0.dev0+1a9c4b5\nSearching for XlsxWriter==3.2.0\nBest match: XlsxWriter 3.2.0\nAdding XlsxWriter 3.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for xlrd==2.0.1\nBest match: xlrd 2.0.1\nAdding xlrd 2.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for setuptools==59.8.0\nBest match: setuptools 59.8.0\nAdding setuptools 59.8.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for serverfiles==0.3.1\nBest match: serverfiles 0.3.1\nAdding serverfiles 0.3.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for scipy==1.7.3\nBest match: scipy 1.7.3\nAdding scipy 1.7.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for scikit-learn==1.0.2\nBest match: scikit-learn 1.0.2\nAdding scikit-learn 1.0.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for requests==2.31.0\nBest match: requests 2.31.0\nAdding requests 2.31.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for python-louvain==0.16\nBest match: python-louvain 0.16\nAdding python-louvain 0.16 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for pyqtgraph==0.12.4\nBest match: pyqtgraph 0.12.4\nAdding pyqtgraph 0.12.4 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for pip==24.0\nBest match: pip 24.0\nAdding pip 24.0 to easy-install.pth file\nInstalling pip script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\nInstalling pip3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\nInstalling pip3.10 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for openTSNE==1.0.1\nBest match: openTSNE 1.0.1\nAdding openTSNE 1.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for numpy==1.17.5\nBest match: numpy 1.17.5\nAdding numpy 1.17.5 to easy-install.pth file\nInstalling f2py script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\nInstalling f2py3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\nInstalling f2py3.7 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for networkx==2.6.3\nBest match: networkx 2.6.3\nAdding networkx 2.6.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for matplotlib==3.5.3\nBest match: matplotlib 3.5.3\nAdding matplotlib 3.5.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for keyrings.alt==4.2.0\nBest match: keyrings.alt 4.2.0\nAdding keyrings.alt 4.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for keyring==24.1.1\nBest match: keyring 24.1.1\nAdding keyring 24.1.1 to easy-install.pth file\nInstalling keyring script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for joblib==1.3.2\nBest match: joblib 1.3.2\nAdding joblib 1.3.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for docutils==0.20.1\nBest match: docutils 0.20.1\nAdding docutils 0.20.1 to easy-install.pth file\nInstalling docutils script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for chardet==5.2.0\nBest match: chardet 5.2.0\nAdding chardet 5.2.0 to easy-install.pth file\nInstalling chardetect script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for Bottleneck==1.4.0\nBest match: Bottleneck 1.4.0\nAdding Bottleneck 1.4.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for AnyQt==0.2.0\nBest match: AnyQt 0.2.0\nAdding AnyQt 0.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for threadpoolctl==3.1.0\nBest match: threadpoolctl 3.1.0\nAdding threadpoolctl 3.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for charset-normalizer==3.4.1\nBest match: charset-normalizer 3.4.1\nAdding charset-normalizer 3.4.1 to easy-install.pth file\nInstalling normalizer script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for certifi==2024.12.14\nBest match: certifi 2024.12.14\nAdding certifi 2024.12.14 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for idna==3.10\nBest match: idna 3.10\nAdding idna 3.10 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for urllib3==2.0.7\nBest match: urllib3 2.0.7\nAdding urllib3 2.0.7 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for fonttools==4.38.0\nBest match: fonttools 4.38.0\nAdding fonttools 4.38.0 to easy-install.pth file\nInstalling fonttools script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\nInstalling pyftmerge script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\nInstalling pyftsubset script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\nInstalling ttx script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for Pillow==9.5.0\nBest match: Pillow 9.5.0\nAdding Pillow 9.5.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for cycler==0.11.0\nBest match: cycler 0.11.0\nAdding cycler 0.11.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for packaging==24.0\nBest match: packaging 24.0\nAdding packaging 24.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for python-dateutil==2.9.0.post0\nBest match: python-dateutil 2.9.0.post0\nAdding python-dateutil 2.9.0.post0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for kiwisolver==1.4.5\nBest match: kiwisolver 1.4.5\nAdding kiwisolver 1.4.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for pyparsing==3.1.4\nBest match: pyparsing 3.1.4\nAdding pyparsing 3.1.4 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for jaraco.classes==3.2.3\nBest match: jaraco.classes 3.2.3\nAdding jaraco.classes 3.2.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for importlib-metadata==6.7.0\nBest match: importlib-metadata 6.7.0\nAdding importlib-metadata 6.7.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for importlib-resources==5.12.0\nBest match: importlib-resources 5.12.0\nAdding importlib-resources 5.12.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for jeepney==0.8.0\nBest match: jeepney 0.8.0\nAdding jeepney 0.8.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for SecretStorage==3.3.3\nBest match: SecretStorage 3.3.3\nAdding SecretStorage 3.3.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for six==1.17.0\nBest match: six 1.17.0\nAdding six 1.17.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for typing-extensions==4.7.1\nBest match: typing-extensions 4.7.1\nAdding typing-extensions 4.7.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for more-itertools==9.1.0\nBest match: more-itertools 9.1.0\nAdding more-itertools 9.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for zipp==3.15.0\nBest match: zipp 3.15.0\nAdding zipp 3.15.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for cryptography==44.0.0\nBest match: cryptography 44.0.0\nAdding cryptography 44.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for cffi==1.15.1\nBest match: cffi 1.15.1\nAdding cffi 1.15.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nSearching for pycparser==2.21\nBest match: pycparser 2.21\nAdding pycparser 2.21 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages\nFinished processing dependencies for Orange3==3.21.0.dev0+1a9c4b5\nVerifying Orange installation...\n✅ Orange installation successful!\nSuccessfully installed orange using Python 3.7\n",
    "setup_res_stderr": "Using CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 18 packages in 131ms\nPrepared 18 packages in 48ms\nInstalled 18 packages in 456ms\n + cython==0.29.37\n + exceptiongroup==1.2.2\n + importlib-metadata==6.7.0\n + iniconfig==2.0.0\n + numpy==1.17.5\n + packaging==24.0\n + pluggy==1.2.0\n + pyqt5==5.15.10\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.13.0\n + pyqtwebengine==5.15.6\n + pyqtwebengine-qt5==5.15.16\n + pytest==7.4.4\n + setuptools==59.8.0\n + tomli==2.0.1\n + typing-extensions==4.7.1\n + wheel==0.42.0\n + zipp==3.15.0\nResolved 33 packages in 141ms\nInstalled 28 packages in 592ms\n + bottleneck==1.4.0\n + certifi==2024.12.14\n + cffi==1.15.1\n + chardet==5.2.0\n + charset-normalizer==3.4.1\n + cryptography==44.0.0\n + idna==3.10\n + importlib-resources==5.12.0\n + jaraco-classes==3.2.3\n + jeepney==0.8.0\n + joblib==1.3.2\n + keyring==24.1.1\n + keyrings-alt==4.2.0\n + more-itertools==9.1.0\n + networkx==2.6.3\n + opentsne==1.0.1\n + pip==24.0\n + pycparser==2.21\n + python-louvain==0.16\n + requests==2.31.0\n + scikit-learn==1.0.2\n + scipy==1.7.3\n + secretstorage==3.3.3\n + serverfiles==0.3.1\n + threadpoolctl==3.1.0\n + urllib3==2.0.7\n + xlrd==2.0.1\n + xlsxwriter==3.2.0\nResolved 14 packages in 102ms\nInstalled 11 packages in 25ms\n + anyqt==0.2.0\n + cycler==0.11.0\n + docutils==0.20.1\n + fonttools==4.38.0\n + kiwisolver==1.4.5\n + matplotlib==3.5.3\n + pillow==9.5.0\n + pyparsing==3.1.4\n + pyqtgraph==0.12.4\n + python-dateutil==2.9.0.post0\n + six==1.17.0\nResolved 2 packages in 4ms\nInstalled 2 packages in 18ms\n + psycopg2==2.9.9\n + pymssql==2.3.2\nResolved 5 packages in 21ms\nInstalled 2 packages in 106ms\n + pandas==1.3.5\n + pytz==2024.2\nAudited 2 packages in 33ms\nOrange/classification/_simple_tree.c: In function ‘gain_ratio_c’:\nOrange/classification/_simple_tree.c:63:9: warning: implicit declaration of function ‘qsort_r’; did you mean ‘qsort’? [-Wimplicit-function-declaration]\n   63 |         qsort_r(base, nel, size, compar, thunk)\n      |         ^~~~~~~\nOrange/classification/_simple_tree.c:147:9: note: in expansion of macro ‘QSORT_R_FUNC’\n  147 |         QSORT_R_FUNC(examples, size, sizeof(struct Example), (void*) &compar_attr, compar_examples);\n      |         ^~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/classification/_tree_scorers.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_2find_threshold_entropy’:\nOrange/classification/_tree_scorers.c:3115:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 3115 |   __pyx_t_7 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_6find_threshold_MSE’:\nOrange/classification/_tree_scorers.c:4619:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 4619 |   __pyx_t_1 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_8find_binarization_MSE’:\nOrange/classification/_tree_scorers.c:5396:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5396 |           for (__pyx_t_22 = 0; __pyx_t_22 < __pyx_t_21; __pyx_t_22+=1) {\n      |                                           ^\nOrange/classification/_tree_scorers.c:5517:39: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5517 |           __pyx_t_27 = ((__pyx_v_left >= __pyx_v_min_leaf) != 0);\n      |                                       ^~\nOrange/classification/_tree_scorers.c:5523:53: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5523 |           __pyx_t_27 = (((__pyx_v_N - __pyx_v_left) >= __pyx_v_min_leaf) != 0);\n      |                                                     ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_14compute_predictions_csr’:\nOrange/classification/_tree_scorers.c:7051:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7051 |         for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_16compute_predictions_csc’:\nOrange/classification/_tree_scorers.c:7741:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7741 |         for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c:7801:143: warning: comparison of integer expressions of different signedness: ‘__pyx_t_5numpy_int32_t’ {aka ‘int’} and ‘unsigned int’ [-Wsign-compare]\n 7801 |               __pyx_t_17 = (((*((__pyx_t_5numpy_int32_t *) ( /* dim=0 */ (__pyx_v_indices.data + __pyx_t_18 * __pyx_v_indices.strides[0]) ))) != __pyx_v_i) != 0);\n      |                                                                                                                                               ^~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_valuecount.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_contingency.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/data/_io.c: In function ‘__pyx_pf_6Orange_4data_3_io_sparse_read_float.constprop’:\nOrange/data/_io.c:3881:24: warning: ‘__pyx_v_decs’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3881 |           __pyx_v_decs = (__pyx_v_decs / 10.0);\n      |           ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:4070:24: warning: ‘__pyx_v_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4070 |           __pyx_t_10 = PyFloat_FromDouble(__pyx_v_value); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 221, __pyx_L5_error)\n      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:480:40: warning: ‘__pyx_v_attr_index’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n  480 |   #define PyInt_FromLong               PyLong_FromLong\n      |                                        ^~~~~~~~~~~~~~~\nOrange/data/_io.c:1301:7: note: ‘__pyx_v_attr_index’ was declared here\n 1301 |   int __pyx_v_attr_index;\n      |       ^~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:2935:25: warning: ‘__pyx_v_atomp’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 2935 |           __pyx_v_atomp = (__pyx_v_atomp + 1);\n      |           ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/distance/_distance.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_discretize.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_relieff.cpp:581:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/setuptools/command/easy_install.py:159: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.\n  EasyInstallDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69/.venv/lib/python3.7/site-packages/setuptools/command/egg_info.py:628: SetuptoolsDeprecationWarning: Custom 'build_py' does not implement 'get_data_files_without_manifest'.\nPlease extend command classes from setuptools instead of distutils.\n  SetuptoolsDeprecationWarning\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69\ncollected 42 items\n\nr2e_tests/test_1.py ..........................................           [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cols\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cols_normalized\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cont\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cont_normalized\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_disc\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_mixed\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_mixed_cols\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_two_tables\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_zero_variance\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cols\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cols_normalized\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cont\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cont_normalized\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_disc\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_mixed\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_mixed_cols\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_no_data\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_mixed_cols\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_two_tables\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_zero_variance\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_cols\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_cont\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_disc\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_mixed\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_two_tables\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_jaccard_cols\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_jaccard_rows\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_zero_instances\nPASSED r2e_tests/test_1.py::HammingDistanceTest::test_hamming_col\nPASSED r2e_tests/test_1.py::HammingDistanceTest::test_hamming_row\n============================== 42 passed in 1.50s ==============================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_1a9c4b531e63bbdf5777895ed406c5441453dd69\ncollected 42 items\n\nr2e_tests/test_1.py .......................................F..           [100%]\n\n=================================== FAILURES ===================================\n___________________ JaccardDistanceTest.test_zero_instances ____________________\n\nself = <r2e_tests.test_1.JaccardDistanceTest testMethod=test_zero_instances>\n\n    def test_zero_instances(self):\n        \"Test all zero instances\"\n        domain = Domain([ContinuousVariable(c) for c in \"abc\"])\n        dense_data = Table.from_list(\n            domain, [[0, 0, 0], [0, 0, 0], [0, 0, 1]])\n        sparse_data = Table(domain, csr_matrix(dense_data.X))\n        dist_dense = self.Distance(dense_data)\n>       dist_sparse = self.Distance(sparse_data)\n\nr2e_tests/test_1.py:902: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nOrange/distance/base.py:188: in __new__\n    return model(e1, e2)\nOrange/distance/base.py:307: in __call__\n    return super().__call__(e1, e2)\nOrange/distance/base.py:267: in __call__\n    dist = self.compute_distances(x1, x2)\nOrange/distance/distance.py:396: in compute_distances\n    return self._compute_sparse(x1, x2)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nx1 = <3x3 sparse matrix of type '<class 'numpy.float64'>'\n\twith 1 stored elements in Compressed Sparse Row format>\nx2 = <3x3 sparse matrix of type '<class 'numpy.float64'>'\n\twith 1 stored elements in Compressed Sparse Row format>\n\n    @staticmethod\n    def _compute_sparse(x1, x2=None):\n        symmetric = x2 is None\n        if symmetric:\n            x2 = x1\n        x1 = sp.csr_matrix(x1)\n        x1.eliminate_zeros()\n        x2 = sp.csr_matrix(x2)\n        x2.eliminate_zeros()\n        n, m = x1.shape[0], x2.shape[0]\n        matrix = np.zeros((n, m))\n        for i in range(n):\n            xi_ind = set(x1[i].indices)\n            for j in range(i if symmetric else m):\n                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\\\n>                          / len(set(x1[i].indices).union(x1[j].indices))\nE               ZeroDivisionError: division by zero\n\nOrange/distance/distance.py:446: ZeroDivisionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cols\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cols_normalized\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cont\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_cont_normalized\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_disc\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_euclidean_mixed\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_mixed_cols\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_two_tables\nPASSED r2e_tests/test_1.py::EuclideanDistanceTest::test_zero_variance\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cols\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cols_normalized\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cont\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_cont_normalized\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_disc\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_mixed\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_mixed_cols\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_manhattan_no_data\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_mixed_cols\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_two_tables\nPASSED r2e_tests/test_1.py::ManhattanDistanceTest::test_zero_variance\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_cols\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_cont\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_disc\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_cosine_mixed\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::CosineDistanceTest::test_two_tables\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_jaccard_cols\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_jaccard_rows\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_mismatching_attributes\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_no_data\nPASSED r2e_tests/test_1.py::JaccardDistanceTest::test_sparse\nPASSED r2e_tests/test_1.py::HammingDistanceTest::test_hamming_col\nPASSED r2e_tests/test_1.py::HammingDistanceTest::test_hamming_row\nFAILED r2e_tests/test_1.py::JaccardDistanceTest::test_zero_instances - ZeroDi...\n========================= 1 failed, 41 passed in 1.43s =========================\n",
    "old_commit_res_stderr": ""
}
Orange/distance/distance.py Orange/distance/tests/test_distance.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Jaccard distance computation raises ZeroDivisionError for instances with no active features

**Description:**
When calculating the Jaccard distance between instances that have no active features (i.e., all feature values are zero), the computation results in a division by zero error.

**Example:**
```python
from Orange.distance import Jaccard
from Orange.data import Table, Domain
from Orange.data.variable import ContinuousVariable
from scipy.sparse import csr_matrix

# Define the domain with continuous variables
domain = Domain([ContinuousVariable(c) for c in "abc"])

# Create dense data with instances having no overlapping features
dense_data = Table.from_list(domain, [
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 1]
])

# Convert dense data to sparse format
sparse_data = Table(domain, csr_matrix(dense_data.X))

# Initialize Jaccard distance
jaccard = Jaccard(dense_data)

# Attempt to compute distance between two instances with no active features
distance = jaccard[0][1]  # This raises ZeroDivisionError
```

**Expected Behavior:**
When computing the Jaccard distance between instances with no active features, the distance should be defined as 0 to indicate no dissimilarity, rather than causing an error.

**Actual Behavior:**
A `ZeroDivisionError` is raised during the distance computation when both instances have no active features, preventing the calculation from completing successfully.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/distance/distance.py
import warnings
from unittest.mock import patch

import numpy as np
from scipy import stats
from scipy import sparse as sp
import sklearn.metrics as skl_metrics
from sklearn.utils.extmath import row_norms, safe_sparse_dot
from sklearn.metrics import pairwise_distances

from Orange.distance import _distance
from Orange.statistics import util

from .base import (Distance, DistanceModel, FittedDistance, FittedDistanceModel,
                   SklDistance, _orange_to_numpy)


class EuclideanRowsModel(FittedDistanceModel):
    """
    Model for computation of Euclidean distances between rows.

    Means are used as offsets for normalization, and two deviations are
    used for scaling.
    """
    def __init__(self, attributes, impute, normalize,
                 continuous, discrete,
                 means, stdvars, dist_missing2_cont,
                 dist_missing_disc, dist_missing2_disc):
        super().__init__(attributes, 1, impute)
        self.normalize = normalize
        self.continuous = continuous
        self.discrete = discrete
        self.means = means
        self.vars = stdvars
        self.dist_missing2_cont = dist_missing2_cont
        self.dist_missing_disc = dist_missing_disc
        self.dist_missing2_disc = dist_missing2_disc

    def compute_distances(self, x1, x2=None):
        """
        The method
        - extracts normalized continuous attributes and then uses `row_norms`
          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2
          (the trick from sklearn);
        - calls a function in Cython that recomputes the distances between pairs
          of rows that yielded nan
        - calls a function in Cython that adds the contributions of discrete
          columns
        """
        if self.continuous.any():
            data1, data2 = self.continuous_columns(
                x1, x2, self.means, np.sqrt(2 * self.vars))

            # adapted from sklearn.metric.euclidean_distances
            xx = row_norms(data1, squared=True)[:, np.newaxis]
            if x2 is not None:
                yy = row_norms(data2, squared=True)[np.newaxis, :]
            else:
                yy = xx.T
            distances = safe_sparse_dot(data1, data2.T, dense_output=True)
            distances *= -2
            distances += xx
            distances += yy
            with np.errstate(invalid="ignore"):  # Nans are fixed below
                np.maximum(distances, 0, out=distances)
            if x2 is None:
                distances.flat[::distances.shape[0] + 1] = 0.0
            fixer = _distance.fix_euclidean_rows_normalized if self.normalize \
                else _distance.fix_euclidean_rows
            fixer(distances, data1, data2,
                  self.means, self.vars, self.dist_missing2_cont,
                  x2 is not None)
        else:
            distances = np.zeros((x1.shape[0],
                                  (x2 if x2 is not None else x1).shape[0]))

        if np.any(self.discrete):
            data1, data2 = self.discrete_columns(x1, x2)
            _distance.euclidean_rows_discrete(
                distances, data1, data2, self.dist_missing_disc,
                self.dist_missing2_disc, x2 is not None)

        if x2 is None:
            _distance.lower_to_symmetric(distances)
        return np.sqrt(distances)


class EuclideanColumnsModel(FittedDistanceModel):
    """
    Model for computation of Euclidean distances between columns.

    Means are used as offsets for normalization, and two deviations are
    used for scaling.
    """
    def __init__(self, attributes, impute, normalize, means, stdvars):
        super().__init__(attributes, 0, impute)
        self.normalize = normalize
        self.means = means
        self.vars = stdvars

    def compute_distances(self, x1, x2=None):
        """
        The method
        - extracts normalized continuous attributes and then uses `row_norms`
          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2
          (the trick from sklearn);
        - calls a function in Cython that adds the contributions of discrete
          columns
        """
        if self.normalize:
            x1 = x1 - self.means
            x1 /= np.sqrt(2 * self.vars)

        # adapted from sklearn.metric.euclidean_distances
        xx = row_norms(x1.T, squared=True)[:, np.newaxis]
        distances = safe_sparse_dot(x1.T, x1, dense_output=True)
        distances *= -2
        distances += xx
        distances += xx.T
        with np.errstate(invalid="ignore"):  # Nans are fixed below
            np.maximum(distances, 0, out=distances)
        distances.flat[::distances.shape[0] + 1] = 0.0

        fixer = _distance.fix_euclidean_cols_normalized if self.normalize \
            else _distance.fix_euclidean_cols
        fixer(distances, x1, self.means, self.vars)
        return np.sqrt(distances)


class Euclidean(FittedDistance):
    supports_sparse = True  # via fallback
    supports_discrete = True
    supports_normalization = True
    fallback = SklDistance('euclidean')
    rows_model_type = EuclideanRowsModel

    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):
        # pylint: disable=arguments-differ
        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)

    def get_continuous_stats(self, column):
        """
        Return mean, variance and distance betwwen pairs of missing values
        for the given columns. The method is called by inherited `fit_rows`
        to construct a row-distance model
        """
        mean = util.nanmean(column)
        var = util.nanvar(column)
        if self.normalize:
            if var == 0:
                return None
            dist_missing2_cont = 1
        else:
            dist_missing2_cont = 2 * var
            if np.isnan(dist_missing2_cont):
                dist_missing2_cont = 0
        return mean, var, dist_missing2_cont

    def fit_cols(self, attributes, x, n_vals):
        """
        Return `EuclideanColumnsModel` with stored means and variances
        for normalization and imputation.
        """
        def nowarn(msg, cat, *args, **kwargs):
            if cat is RuntimeWarning and msg in (
                    "Mean of empty slice", "Degrees of freedom <= 0 for slice"):
                if self.normalize:
                    raise ValueError("some columns have no defined values")
            else:
                orig_warn(msg, cat, *args, **kwargs)

        self.check_no_discrete(n_vals)
        # catch_warnings resets the registry for "once", while avoiding this
        # warning would be annoying and slow, hence patching
        orig_warn = warnings.warn
        with patch("warnings.warn", new=nowarn):
            means = np.nanmean(x, axis=0)
            stdvars = np.nanvar(x, axis=0)
        if self.normalize and not stdvars.all():
            raise ValueError("some columns are constant")
        return EuclideanColumnsModel(
            attributes, self.impute, self.normalize, means, stdvars)


class ManhattanRowsModel(FittedDistanceModel):
    """
    Model for computation of Euclidean distances between rows.

    Means are used as offsets for normalization, and two deviations are
    used for scaling.
    """
    def __init__(self, attributes, impute, normalize,
                 continuous, discrete,
                 medians, mads, dist_missing2_cont,
                 dist_missing_disc, dist_missing2_disc):
        super().__init__(attributes, 1, impute)
        self.normalize = normalize
        self.continuous = continuous
        self.discrete = discrete
        self.medians = medians
        self.mads = mads
        self.dist_missing2_cont = dist_missing2_cont
        self.dist_missing_disc = dist_missing_disc
        self.dist_missing2_disc = dist_missing2_disc

    def compute_distances(self, x1, x2):
        """
        The method
        - extracts normalized continuous attributes and computes distances
          ignoring the possibility of nans
        - recomputes the distances between pairs of rows that yielded nans
        - adds the contributions of discrete columns using the same function as
          the Euclidean distance
        """
        if self.continuous.any():
            data1, data2 = self.continuous_columns(
                x1, x2, self.medians, 2 * self.mads)
            distances = _distance.manhattan_rows_cont(
                data1, data2, x2 is not None)
            if self.normalize:
                _distance.fix_manhattan_rows_normalized(
                    distances, data1, data2, x2 is not None)
            else:
                _distance.fix_manhattan_rows(
                    distances, data1, data2,
                    self.medians, self.mads, self.dist_missing2_cont,
                    x2 is not None)
        else:
            distances = np.zeros((x1.shape[0],
                                  (x2 if x2 is not None else x1).shape[0]))

        if np.any(self.discrete):
            data1, data2 = self.discrete_columns(x1, x2)
            # For discrete attributes, Euclidean is same as Manhattan
            _distance.euclidean_rows_discrete(
                distances, data1, data2, self.dist_missing_disc,
                self.dist_missing2_disc, x2 is not None)

        if x2 is None:
            _distance.lower_to_symmetric(distances)
        return distances


class ManhattanColumnsModel(FittedDistanceModel):
    """
    Model for computation of Manhattan distances between columns.

    Medians are used as offsets for normalization, and two MADS are
    used for scaling.
    """

    def __init__(self, attributes, impute, normalize, medians, mads):
        super().__init__(attributes, 0, impute)
        self.normalize = normalize
        self.medians = medians
        self.mads = mads

    def compute_distances(self, x1, x2=None):
        if self.normalize:
            x1 = x1 - self.medians
            x1 /= 2
            x1 /= self.mads
        return _distance.manhattan_cols(x1, self.medians, self.mads, self.normalize)


class Manhattan(FittedDistance):
    supports_sparse = True  # via fallback
    supports_discrete = True
    supports_normalization = True
    fallback = SklDistance('manhattan')
    rows_model_type = ManhattanRowsModel

    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):
        # pylint: disable=arguments-differ
        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)

    def get_continuous_stats(self, column):
        """
        Return median, MAD and distance betwwen pairs of missing values
        for the given columns. The method is called by inherited `fit_rows`
        to construct a row-distance model
        """
        median = np.nanmedian(column)
        mad = np.nanmedian(np.abs(column - median))
        if self.normalize:
            if mad == 0:
                return None
            dist_missing2_cont = 1
        else:
            dist_missing2_cont = 2 * mad
            if np.isnan(dist_missing2_cont):
                dist_missing2_cont = 0
        return median, mad, dist_missing2_cont

    def fit_cols(self, attributes, x, n_vals):
        """
        Return `ManhattanColumnsModel` with stored medians and MADs
        for normalization and imputation.
        """
        self.check_no_discrete(n_vals)
        if x.size == 0:
            medians = np.zeros(len(x))
            mads = np.zeros(len(x))
        else:
            medians = np.nanmedian(x, axis=0)
            mads = np.nanmedian(np.abs(x - medians), axis=0)
        if self.normalize and (np.isnan(mads).any() or not mads.all()):
            raise ValueError(
                "some columns have zero absolute distance from median, "
                "or no values")
        return ManhattanColumnsModel(
            attributes, self.impute, self.normalize, medians, mads)


class Cosine(FittedDistance):
    supports_sparse = True  # via fallback
    supports_discrete = False
    fallback = SklDistance('cosine')

    @staticmethod
    def discrete_to_indicators(x, discrete):
        """Change non-zero values of discrete attributes to 1."""
        if discrete.any():
            x = x.copy()
            for col, disc in enumerate(discrete):
                if disc:
                    x[:, col].clip(0, 1, out=x[:, col])
        return x

    def fit_rows(self, attributes, x, n_vals):
        """Return a model for cosine distances with stored means for imputation
        """
        discrete = n_vals > 0
        x = self.discrete_to_indicators(x, discrete)
        means = util.nanmean(x, axis=0)
        means = np.nan_to_num(means)
        return self.CosineModel(attributes, self.axis, self.impute,
                                discrete, means)

    fit_cols = fit_rows

    def get_continuous_stats(self, column):
        # Implement an unneeded abstract method to silence pylint
        return None

    class CosineModel(FittedDistanceModel):
        """Model for computation of cosine distances across rows and columns.
        All non-zero discrete values are treated as 1."""
        def __init__(self, attributes, axis, impute, discrete, means):
            super().__init__(attributes, axis, impute)
            self.discrete = discrete
            self.means = means

        def compute_distances(self, x1, x2):
            """
            The method imputes the missing values as means and calls
            safe_sparse_dot. Imputation simplifies computation at a cost of
            (theoretically) slightly wrong distance between pairs of missing
             values.
            """

            def prepare_data(x):
                if self.discrete.any():
                    data = Cosine.discrete_to_indicators(x, self.discrete)
                else:
                    data = x.copy()
                for col, mean in enumerate(self.means):
                    column = data[:, col]
                    column[np.isnan(column)] = mean
                if self.axis == 0:
                    data = data.T
                data /= row_norms(data)[:, np.newaxis]
                return data

            data1 = prepare_data(x1)
            data2 = data1 if x2 is None else prepare_data(x2)
            dist = safe_sparse_dot(data1, data2.T)
            np.clip(dist, -1, 1, out=dist)
            if x2 is None:
                diag = np.diag_indices_from(dist)
                dist[diag] = np.where(np.isnan(dist[diag]), np.nan, 1.0)
            return 1 - dist


class JaccardModel(FittedDistanceModel):
    """
    Model for computation of cosine distances across rows and columns.
    All non-zero values are treated as 1.
    """
    def __init__(self, attributes, axis, impute, ps):
        super().__init__(attributes, axis, impute)
        self.ps = ps

    def compute_distances(self, x1, x2):
        if sp.issparse(x1):
            return self._compute_sparse(x1, x2)
        else:
            return self._compute_dense(x1, x2)

    def _compute_dense(self, x1, x2):
        """
        The method uses a function implemented in Cython. Data (`x1` and `x2`)
        is accompanied by two tables. One is a 2-d table in which elements of
        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector
        indicating rows (or column) with nan values.

        The function in Cython uses a fast loop without any conditions to
        compute distances between rows without missing values, and a slower
        loop for those with missing values.
        """
        # view is false positive, pylint: disable=no-member
        nonzeros1 = np.not_equal(x1, 0).view(np.int8)
        if self.axis == 1:
            nans1 = _distance.any_nan_row(x1)
            if x2 is None:
                nonzeros2, nans2 = nonzeros1, nans1
            else:
                nonzeros2 = np.not_equal(x2, 0).view(np.int8)
                nans2 = _distance.any_nan_row(x2)
            return _distance.jaccard_rows(
                nonzeros1, nonzeros2,
                x1, x1 if x2 is None else x2,
                nans1, nans2,
                self.ps,
                x2 is not None)
        else:
            nans1 = _distance.any_nan_row(x1.T)
            return _distance.jaccard_cols(
                nonzeros1, x1, nans1, self.ps)

    @staticmethod
    def _compute_sparse(x1, x2=None):
        symmetric = x2 is None
        if symmetric:
            x2 = x1
        x1 = sp.csr_matrix(x1)
        x1.eliminate_zeros()
        x2 = sp.csr_matrix(x2)
        x2.eliminate_zeros()
        n, m = x1.shape[0], x2.shape[0]
        matrix = np.zeros((n, m))
        for i in range(n):
            xi_ind = set(x1[i].indices)
            for j in range(i if symmetric else m):
                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\
                           / len(set(x1[i].indices).union(x1[j].indices))
                matrix[i, j] = jacc
                if symmetric:
                    matrix[j, i] = jacc
        return matrix


class Jaccard(FittedDistance):
    supports_sparse = True
    supports_discrete = True
    ModelType = JaccardModel

    def fit_rows(self, attributes, x, n_vals):
        """
        Return a model for computation of Jaccard values. The model stores
        frequencies of non-zero values per each column.
        """
        if sp.issparse(x):
            ps = x.getnnz(axis=0)
        else:
            ps = np.fromiter(
                (_distance.p_nonzero(x[:, col]) for col in range(len(n_vals))),
                dtype=np.double, count=len(n_vals))
        return JaccardModel(attributes, self.axis, self.impute, ps)

    fit_cols = fit_rows

    def get_continuous_stats(self, column):
        # Implement an unneeded abstract method to silence pylint
        return None


class CorrelationDistanceModel(DistanceModel):
    """Helper class for normal and absolute Pearson and Spearman correlation"""
    def __init__(self, absolute, axis=1, impute=False):
        super().__init__(axis, impute)
        self.absolute = absolute

    def compute_distances(self, x1, x2):
        rho = self.compute_correlation(x1, x2)
        if self.absolute:
            return (1. - np.abs(rho)) / 2.
        else:
            return (1. - rho) / 2.

    def compute_correlation(self, x1, x2):
        raise NotImplementedError()


class SpearmanModel(CorrelationDistanceModel):
    def compute_correlation(self, x1, x2):
        if x2 is None:
            n1 = x1.shape[1 - self.axis]
            if n1 == 1:
                rho = 1.0
            elif n1 == 2:
                # Special case to properly fill degenerate self correlations
                # (nan, inf on the diagonals)
                rho = stats.spearmanr(x1, x1, axis=self.axis)[0]
                assert rho.shape == (4, 4)
                rho = rho[:2, :2].copy()
            else:
                # scalar if n1 == 1
                rho = stats.spearmanr(x1, axis=self.axis)[0]
            return np.atleast_2d(rho)
        else:
            return _spearmanr2(x1, x2, axis=self.axis)


def _spearmanr2(a, b, axis=0):
    """
    Compute all pairwise spearman rank moment correlations between rows
    or columns of a and b

    Parameters
    ----------
    a : (N, M) numpy.ndarray
        The input cases a.
    b : (J, K) numpy.ndarray
        The input cases b. In case of axis == 0: J must equal N;
        otherwise if axis == 1 then K must equal M.
    axis : int
        If 0 the correlation are computed between a and b's columns.
        Otherwise if 1 the correlations are computed between rows.

    Returns
    -------
    cor : (N, J) or (M, K) nd.array
        If axis == 0 then (N, J) matrix of correlations between a x b columns
        else a (N, J) matrix of correlations between a x b rows.

    See Also
    --------
    scipy.stats.spearmanr
    """
    a, b = np.atleast_2d(a, b)
    assert a.shape[axis] == b.shape[axis]
    ar = np.apply_along_axis(stats.rankdata, axis, a)
    br = np.apply_along_axis(stats.rankdata, axis, b)

    return _corrcoef2(ar, br, axis=axis)


def _corrcoef2(a, b, axis=0):
    """
    Compute all pairwise Pearson product-moment correlation coefficients
    between rows or columns of a and b

    Parameters
    ----------
    a : (N, M) numpy.ndarray
        The input cases a.
    b : (J, K) numpy.ndarray
        The input cases b. In case of axis == 0: J must equal N;
        otherwise if axis == 1 then K must equal M.
    axis : int
        If 0 the correlation are computed between a and b's columns.
        Otherwise if 1 the correlations are computed between rows.

    Returns
    -------
    cor : (N, J) or (M, K) nd.array
        If axis == 0 then (N, J) matrix of correlations between a x b columns
        else a (N, J) matrix of correlations between a x b rows.

    See Also
    --------
    numpy.corrcoef
    """
    a, b = np.atleast_2d(a, b)
    if axis not in (0, 1):
        raise ValueError("Invalid axis {} (only 0 or 1 accepted)".format(axis))

    mean_a = np.mean(a, axis=axis, keepdims=True)
    mean_b = np.mean(b, axis=axis, keepdims=True)
    assert a.shape[axis] == b.shape[axis]

    n = a.shape[1 - axis]
    m = b.shape[1 - axis]

    a = a - mean_a
    b = b - mean_b

    if axis == 0:
        C = a.T.dot(b)
        assert C.shape == (n, m)
    elif axis == 1:
        C = a.dot(b.T)
        assert C.shape == (n, m)

    ss_a = np.sum(a ** 2, axis=axis, keepdims=True)
    ss_b = np.sum(b ** 2, axis=axis, keepdims=True)

    if axis == 0:
        ss_a = ss_a.T
    else:
        ss_b = ss_b.T

    assert ss_a.shape == (n, 1)
    assert ss_b.shape == (1, m)
    C /= np.sqrt(ss_a)
    C /= np.sqrt(ss_b)
    return C


class CorrelationDistance(Distance):
    # pylint: disable=abstract-method
    supports_missing = False


class SpearmanR(CorrelationDistance):
    def fit(self, _):
        return SpearmanModel(False, self.axis, self.impute)


class SpearmanRAbsolute(CorrelationDistance):
    def fit(self, _):
        return SpearmanModel(True, self.axis, self.impute)


class PearsonModel(CorrelationDistanceModel):
    def compute_correlation(self, x1, x2):
        if x2 is None:
            c = np.corrcoef(x1, rowvar=self.axis == 1)
            return np.atleast_2d(c)
        else:
            return _corrcoef2(x1, x2, axis=self.axis)


class PearsonR(CorrelationDistance):
    def fit(self, _):
        return PearsonModel(False, self.axis, self.impute)


class PearsonRAbsolute(CorrelationDistance):
    def fit(self, _):
        return PearsonModel(True, self.axis, self.impute)


class Mahalanobis(Distance):
    supports_sparse = False
    supports_missing = False

    def fit(self, data):
        """Return a model with stored inverse covariance matrix"""
        x = _orange_to_numpy(data)
        if self.axis == 0:
            x = x.T
        try:
            c = np.cov(x.T)
        except:
            raise MemoryError("Covariance matrix is too large.")
        try:
            vi = np.linalg.inv(c)
        except:
            raise ValueError("Computation of inverse covariance matrix failed.")
        return MahalanobisModel(self.axis, self.impute, vi)


class MahalanobisModel(DistanceModel):
    def __init__(self, axis, impute, vi):
        super().__init__(axis, impute)
        self.vi = vi

    def __call__(self, e1, e2=None, impute=None):
        # argument `impute` is here just for backward compatibility; don't use
        if impute is not None:
            self.impute = impute
        return super().__call__(e1, e2)

    def compute_distances(self, x1, x2):
        if self.axis == 0:
            x1 = x1.T
            if x2 is not None:
                x2 = x2.T
        if x1.shape[1] != self.vi.shape[0] or \
                x2 is not None and x2.shape[1] != self.vi.shape[0]:
            raise ValueError('Incorrect number of features.')
        return skl_metrics.pairwise.pairwise_distances(
            x1, x2, metric='mahalanobis', VI=self.vi)


# TODO: Appears to have been used only in the Distances widget (where it had
# to be handled as a special case and is now replaced with the above class)
# and in tests. Remove?
class MahalanobisDistance:
    """
    Obsolete class needed for backward compatibility.

    Previous implementation of instances did not have a separate fitting phase,
    except for MahalanobisDistance, which was implemented in a single class
    but required first (explicitly) calling the method 'fit'. The backward
    compatibility hack in :obj:`Distance` cannot handle such use, hence it
    is provided in this class.
    """
    def __new__(cls, data=None, axis=1, _='Mahalanobis'):
        if data is None:
            return cls
        return Mahalanobis(axis=axis).fit(data)

class Hamming(Distance):
    supports_sparse = False
    supports_missing = False
    supports_normalization = False
    supports_discrete = True

    def fit(self, data):
        x = _orange_to_numpy(data)
        if self.axis == 0:
            return HammingColumnsModel(self.axis, self.impute, x)
        else:
            return HammingRowsModel(self.axis, self.impute, x)

class HammingColumnsModel(DistanceModel):
    """
    Model for computation of Hamming distances between columns.
    """
    def __init__(self, axis, impute, x):
        super().__init__(axis, impute)
        self.x = x

    def __call__(self, e1, e2=None, impute=None):
        if impute is not None:
            self.impute = impute
        return super().__call__(e1, e2)

    def compute_distances(self, x1, x2=None):
        return pairwise_distances(x1.T, metric='hamming')

class HammingRowsModel(DistanceModel):
    """
    Model for computation of Hamming distances between rows.
    """
    def __init__(self, axis, impute, x):
        super().__init__(axis, impute)
        self.x = x

    def __call__(self, e1, e2=None, impute=None):
        if impute is not None:
            self.impute = impute
        return super().__call__(e1, e2)

    def compute_distances(self, x1, x2=None):
        return pairwise_distances(x1, metric='hamming')

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Jaccard distance computation raises ZeroDivisionError for instances with no active features

**Description:**
When calculating the Jaccard distance between instances that have no active features (i.e., all feature values are zero), the computation results in a division by zero error.

**Example:**
```python
from Orange.distance import Jaccard
from Orange.data import Table, Domain
from Orange.data.variable import ContinuousVariable
from scipy.sparse import csr_matrix

# Define the domain with continuous variables
domain = Domain([ContinuousVariable(c) for c in "abc"])

# Create dense data with instances having no overlapping features
dense_data = Table.from_list(domain, [
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 1]
])

# Convert dense data to sparse format
sparse_data = Table(domain, csr_matrix(dense_data.X))

# Initialize Jaccard distance
jaccard = Jaccard(dense_data)

# Attempt to compute distance between two instances with no active features
distance = jaccard[0][1]  # This raises ZeroDivisionError
```

**Expected Behavior:**
When computing the Jaccard distance between instances with no active features, the distance should be defined as 0 to indicate no dissimilarity, rather than causing an error.

**Actual Behavior:**
A `ZeroDivisionError` is raised during the distance computation when both instances have no active features, preventing the calculation from completing successfully.

[/ISSUE]
{
    "EuclideanDistanceTest.test_euclidean_cols": "PASSED",
    "EuclideanDistanceTest.test_euclidean_cols_normalized": "PASSED",
    "EuclideanDistanceTest.test_euclidean_cont": "PASSED",
    "EuclideanDistanceTest.test_euclidean_cont_normalized": "PASSED",
    "EuclideanDistanceTest.test_euclidean_disc": "PASSED",
    "EuclideanDistanceTest.test_euclidean_mixed": "PASSED",
    "EuclideanDistanceTest.test_mismatching_attributes": "PASSED",
    "EuclideanDistanceTest.test_mixed_cols": "PASSED",
    "EuclideanDistanceTest.test_no_data": "PASSED",
    "EuclideanDistanceTest.test_sparse": "PASSED",
    "EuclideanDistanceTest.test_two_tables": "PASSED",
    "EuclideanDistanceTest.test_zero_variance": "PASSED",
    "ManhattanDistanceTest.test_manhattan_cols": "PASSED",
    "ManhattanDistanceTest.test_manhattan_cols_normalized": "PASSED",
    "ManhattanDistanceTest.test_manhattan_cont": "PASSED",
    "ManhattanDistanceTest.test_manhattan_cont_normalized": "PASSED",
    "ManhattanDistanceTest.test_manhattan_disc": "PASSED",
    "ManhattanDistanceTest.test_manhattan_mixed": "PASSED",
    "ManhattanDistanceTest.test_manhattan_mixed_cols": "PASSED",
    "ManhattanDistanceTest.test_manhattan_no_data": "PASSED",
    "ManhattanDistanceTest.test_mismatching_attributes": "PASSED",
    "ManhattanDistanceTest.test_mixed_cols": "PASSED",
    "ManhattanDistanceTest.test_no_data": "PASSED",
    "ManhattanDistanceTest.test_sparse": "PASSED",
    "ManhattanDistanceTest.test_two_tables": "PASSED",
    "ManhattanDistanceTest.test_zero_variance": "PASSED",
    "CosineDistanceTest.test_cosine_cols": "PASSED",
    "CosineDistanceTest.test_cosine_cont": "PASSED",
    "CosineDistanceTest.test_cosine_disc": "PASSED",
    "CosineDistanceTest.test_cosine_mixed": "PASSED",
    "CosineDistanceTest.test_mismatching_attributes": "PASSED",
    "CosineDistanceTest.test_no_data": "PASSED",
    "CosineDistanceTest.test_sparse": "PASSED",
    "CosineDistanceTest.test_two_tables": "PASSED",
    "JaccardDistanceTest.test_jaccard_cols": "PASSED",
    "JaccardDistanceTest.test_jaccard_rows": "PASSED",
    "JaccardDistanceTest.test_mismatching_attributes": "PASSED",
    "JaccardDistanceTest.test_no_data": "PASSED",
    "JaccardDistanceTest.test_sparse": "PASSED",
    "JaccardDistanceTest.test_zero_instances": "PASSED",
    "HammingDistanceTest.test_hamming_col": "PASSED",
    "HammingDistanceTest.test_hamming_row": "PASSED"
}
diff --git a/Orange/distance/distance.py b/Orange/distance/distance.py
index cfd7fe43a..9dd1d7213 100644
--- a/Orange/distance/distance.py
+++ b/Orange/distance/distance.py
@@ -442,8 +442,11 @@ class JaccardModel(FittedDistanceModel):
         for i in range(n):
             xi_ind = set(x1[i].indices)
             for j in range(i if symmetric else m):
-                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\
-                           / len(set(x1[i].indices).union(x1[j].indices))
+                union = len(xi_ind.union(x2[j].indices))
+                if union:
+                    jacc = 1 - len(xi_ind.intersection(x2[j].indices)) / union
+                else:
+                    jacc = 0
                 matrix[i, j] = jacc
                 if symmetric:
                     matrix[j, i] = jacc

{"Orange/distance/distance.py": "import warnings\nfrom unittest.mock import patch\n\nimport numpy as np\nfrom scipy import stats\nfrom scipy import sparse as sp\nimport sklearn.metrics as skl_metrics\nfrom sklearn.utils.extmath import row_norms, safe_sparse_dot\nfrom sklearn.metrics import pairwise_distances\n\nfrom Orange.distance import _distance\nfrom Orange.statistics import util\n\nfrom .base import (Distance, DistanceModel, FittedDistance, FittedDistanceModel,\n                   SklDistance, _orange_to_numpy)\n\n\nclass EuclideanRowsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between rows.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize,\n                 continuous, discrete,\n                 means, stdvars, dist_missing2_cont,\n                 dist_missing_disc, dist_missing2_disc):\n        super().__init__(attributes, 1, impute)\n        self.normalize = normalize\n        self.continuous = continuous\n        self.discrete = discrete\n        self.means = means\n        self.vars = stdvars\n        self.dist_missing2_cont = dist_missing2_cont\n        self.dist_missing_disc = dist_missing_disc\n        self.dist_missing2_disc = dist_missing2_disc\n\n    def compute_distances(self, x1, x2=None):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and then uses `row_norms`\n          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2\n          (the trick from sklearn);\n        - calls a function in Cython that recomputes the distances between pairs\n          of rows that yielded nan\n        - calls a function in Cython that adds the contributions of discrete\n          columns\n        \"\"\"\n        if self.continuous.any():\n            data1, data2 = self.continuous_columns(\n                x1, x2, self.means, np.sqrt(2 * self.vars))\n\n            # adapted from sklearn.metric.euclidean_distances\n            xx = row_norms(data1, squared=True)[:, np.newaxis]\n            if x2 is not None:\n                yy = row_norms(data2, squared=True)[np.newaxis, :]\n            else:\n                yy = xx.T\n            distances = safe_sparse_dot(data1, data2.T, dense_output=True)\n            distances *= -2\n            distances += xx\n            distances += yy\n            with np.errstate(invalid=\"ignore\"):  # Nans are fixed below\n                np.maximum(distances, 0, out=distances)\n            if x2 is None:\n                distances.flat[::distances.shape[0] + 1] = 0.0\n            fixer = _distance.fix_euclidean_rows_normalized if self.normalize \\\n                else _distance.fix_euclidean_rows\n            fixer(distances, data1, data2,\n                  self.means, self.vars, self.dist_missing2_cont,\n                  x2 is not None)\n        else:\n            distances = np.zeros((x1.shape[0],\n                                  (x2 if x2 is not None else x1).shape[0]))\n\n        if np.any(self.discrete):\n            data1, data2 = self.discrete_columns(x1, x2)\n            _distance.euclidean_rows_discrete(\n                distances, data1, data2, self.dist_missing_disc,\n                self.dist_missing2_disc, x2 is not None)\n\n        if x2 is None:\n            _distance.lower_to_symmetric(distances)\n        return np.sqrt(distances)\n\n\nclass EuclideanColumnsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between columns.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize, means, stdvars):\n        super().__init__(attributes, 0, impute)\n        self.normalize = normalize\n        self.means = means\n        self.vars = stdvars\n\n    def compute_distances(self, x1, x2=None):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and then uses `row_norms`\n          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2\n          (the trick from sklearn);\n        - calls a function in Cython that adds the contributions of discrete\n          columns\n        \"\"\"\n        if self.normalize:\n            x1 = x1 - self.means\n            x1 /= np.sqrt(2 * self.vars)\n\n        # adapted from sklearn.metric.euclidean_distances\n        xx = row_norms(x1.T, squared=True)[:, np.newaxis]\n        distances = safe_sparse_dot(x1.T, x1, dense_output=True)\n        distances *= -2\n        distances += xx\n        distances += xx.T\n        with np.errstate(invalid=\"ignore\"):  # Nans are fixed below\n            np.maximum(distances, 0, out=distances)\n        distances.flat[::distances.shape[0] + 1] = 0.0\n\n        fixer = _distance.fix_euclidean_cols_normalized if self.normalize \\\n            else _distance.fix_euclidean_cols\n        fixer(distances, x1, self.means, self.vars)\n        return np.sqrt(distances)\n\n\nclass Euclidean(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = True\n    supports_normalization = True\n    fallback = SklDistance('euclidean')\n    rows_model_type = EuclideanRowsModel\n\n    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):\n        # pylint: disable=arguments-differ\n        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)\n\n    def get_continuous_stats(self, column):\n        \"\"\"\n        Return mean, variance and distance betwwen pairs of missing values\n        for the given columns. The method is called by inherited `fit_rows`\n        to construct a row-distance model\n        \"\"\"\n        mean = util.nanmean(column)\n        var = util.nanvar(column)\n        if self.normalize:\n            if var == 0:\n                return None\n            dist_missing2_cont = 1\n        else:\n            dist_missing2_cont = 2 * var\n            if np.isnan(dist_missing2_cont):\n                dist_missing2_cont = 0\n        return mean, var, dist_missing2_cont\n\n    def fit_cols(self, attributes, x, n_vals):\n        \"\"\"\n        Return `EuclideanColumnsModel` with stored means and variances\n        for normalization and imputation.\n        \"\"\"\n        def nowarn(msg, cat, *args, **kwargs):\n            if cat is RuntimeWarning and msg in (\n                    \"Mean of empty slice\", \"Degrees of freedom <= 0 for slice\"):\n                if self.normalize:\n                    raise ValueError(\"some columns have no defined values\")\n            else:\n                orig_warn(msg, cat, *args, **kwargs)\n\n        self.check_no_discrete(n_vals)\n        # catch_warnings resets the registry for \"once\", while avoiding this\n        # warning would be annoying and slow, hence patching\n        orig_warn = warnings.warn\n        with patch(\"warnings.warn\", new=nowarn):\n            means = np.nanmean(x, axis=0)\n            stdvars = np.nanvar(x, axis=0)\n        if self.normalize and not stdvars.all():\n            raise ValueError(\"some columns are constant\")\n        return EuclideanColumnsModel(\n            attributes, self.impute, self.normalize, means, stdvars)\n\n\nclass ManhattanRowsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Euclidean distances between rows.\n\n    Means are used as offsets for normalization, and two deviations are\n    used for scaling.\n    \"\"\"\n    def __init__(self, attributes, impute, normalize,\n                 continuous, discrete,\n                 medians, mads, dist_missing2_cont,\n                 dist_missing_disc, dist_missing2_disc):\n        super().__init__(attributes, 1, impute)\n        self.normalize = normalize\n        self.continuous = continuous\n        self.discrete = discrete\n        self.medians = medians\n        self.mads = mads\n        self.dist_missing2_cont = dist_missing2_cont\n        self.dist_missing_disc = dist_missing_disc\n        self.dist_missing2_disc = dist_missing2_disc\n\n    def compute_distances(self, x1, x2):\n        \"\"\"\n        The method\n        - extracts normalized continuous attributes and computes distances\n          ignoring the possibility of nans\n        - recomputes the distances between pairs of rows that yielded nans\n        - adds the contributions of discrete columns using the same function as\n          the Euclidean distance\n        \"\"\"\n        if self.continuous.any():\n            data1, data2 = self.continuous_columns(\n                x1, x2, self.medians, 2 * self.mads)\n            distances = _distance.manhattan_rows_cont(\n                data1, data2, x2 is not None)\n            if self.normalize:\n                _distance.fix_manhattan_rows_normalized(\n                    distances, data1, data2, x2 is not None)\n            else:\n                _distance.fix_manhattan_rows(\n                    distances, data1, data2,\n                    self.medians, self.mads, self.dist_missing2_cont,\n                    x2 is not None)\n        else:\n            distances = np.zeros((x1.shape[0],\n                                  (x2 if x2 is not None else x1).shape[0]))\n\n        if np.any(self.discrete):\n            data1, data2 = self.discrete_columns(x1, x2)\n            # For discrete attributes, Euclidean is same as Manhattan\n            _distance.euclidean_rows_discrete(\n                distances, data1, data2, self.dist_missing_disc,\n                self.dist_missing2_disc, x2 is not None)\n\n        if x2 is None:\n            _distance.lower_to_symmetric(distances)\n        return distances\n\n\nclass ManhattanColumnsModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of Manhattan distances between columns.\n\n    Medians are used as offsets for normalization, and two MADS are\n    used for scaling.\n    \"\"\"\n\n    def __init__(self, attributes, impute, normalize, medians, mads):\n        super().__init__(attributes, 0, impute)\n        self.normalize = normalize\n        self.medians = medians\n        self.mads = mads\n\n    def compute_distances(self, x1, x2=None):\n        if self.normalize:\n            x1 = x1 - self.medians\n            x1 /= 2\n            x1 /= self.mads\n        return _distance.manhattan_cols(x1, self.medians, self.mads, self.normalize)\n\n\nclass Manhattan(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = True\n    supports_normalization = True\n    fallback = SklDistance('manhattan')\n    rows_model_type = ManhattanRowsModel\n\n    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):\n        # pylint: disable=arguments-differ\n        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)\n\n    def get_continuous_stats(self, column):\n        \"\"\"\n        Return median, MAD and distance betwwen pairs of missing values\n        for the given columns. The method is called by inherited `fit_rows`\n        to construct a row-distance model\n        \"\"\"\n        median = np.nanmedian(column)\n        mad = np.nanmedian(np.abs(column - median))\n        if self.normalize:\n            if mad == 0:\n                return None\n            dist_missing2_cont = 1\n        else:\n            dist_missing2_cont = 2 * mad\n            if np.isnan(dist_missing2_cont):\n                dist_missing2_cont = 0\n        return median, mad, dist_missing2_cont\n\n    def fit_cols(self, attributes, x, n_vals):\n        \"\"\"\n        Return `ManhattanColumnsModel` with stored medians and MADs\n        for normalization and imputation.\n        \"\"\"\n        self.check_no_discrete(n_vals)\n        if x.size == 0:\n            medians = np.zeros(len(x))\n            mads = np.zeros(len(x))\n        else:\n            medians = np.nanmedian(x, axis=0)\n            mads = np.nanmedian(np.abs(x - medians), axis=0)\n        if self.normalize and (np.isnan(mads).any() or not mads.all()):\n            raise ValueError(\n                \"some columns have zero absolute distance from median, \"\n                \"or no values\")\n        return ManhattanColumnsModel(\n            attributes, self.impute, self.normalize, medians, mads)\n\n\nclass Cosine(FittedDistance):\n    supports_sparse = True  # via fallback\n    supports_discrete = False\n    fallback = SklDistance('cosine')\n\n    @staticmethod\n    def discrete_to_indicators(x, discrete):\n        \"\"\"Change non-zero values of discrete attributes to 1.\"\"\"\n        if discrete.any():\n            x = x.copy()\n            for col, disc in enumerate(discrete):\n                if disc:\n                    x[:, col].clip(0, 1, out=x[:, col])\n        return x\n\n    def fit_rows(self, attributes, x, n_vals):\n        \"\"\"Return a model for cosine distances with stored means for imputation\n        \"\"\"\n        discrete = n_vals > 0\n        x = self.discrete_to_indicators(x, discrete)\n        means = util.nanmean(x, axis=0)\n        means = np.nan_to_num(means)\n        return self.CosineModel(attributes, self.axis, self.impute,\n                                discrete, means)\n\n    fit_cols = fit_rows\n\n    def get_continuous_stats(self, column):\n        # Implement an unneeded abstract method to silence pylint\n        return None\n\n    class CosineModel(FittedDistanceModel):\n        \"\"\"Model for computation of cosine distances across rows and columns.\n        All non-zero discrete values are treated as 1.\"\"\"\n        def __init__(self, attributes, axis, impute, discrete, means):\n            super().__init__(attributes, axis, impute)\n            self.discrete = discrete\n            self.means = means\n\n        def compute_distances(self, x1, x2):\n            \"\"\"\n            The method imputes the missing values as means and calls\n            safe_sparse_dot. Imputation simplifies computation at a cost of\n            (theoretically) slightly wrong distance between pairs of missing\n             values.\n            \"\"\"\n\n            def prepare_data(x):\n                if self.discrete.any():\n                    data = Cosine.discrete_to_indicators(x, self.discrete)\n                else:\n                    data = x.copy()\n                for col, mean in enumerate(self.means):\n                    column = data[:, col]\n                    column[np.isnan(column)] = mean\n                if self.axis == 0:\n                    data = data.T\n                data /= row_norms(data)[:, np.newaxis]\n                return data\n\n            data1 = prepare_data(x1)\n            data2 = data1 if x2 is None else prepare_data(x2)\n            dist = safe_sparse_dot(data1, data2.T)\n            np.clip(dist, -1, 1, out=dist)\n            if x2 is None:\n                diag = np.diag_indices_from(dist)\n                dist[diag] = np.where(np.isnan(dist[diag]), np.nan, 1.0)\n            return 1 - dist\n\n\nclass JaccardModel(FittedDistanceModel):\n    \"\"\"\n    Model for computation of cosine distances across rows and columns.\n    All non-zero values are treated as 1.\n    \"\"\"\n    def __init__(self, attributes, axis, impute, ps):\n        super().__init__(attributes, axis, impute)\n        self.ps = ps\n\n    def compute_distances(self, x1, x2):\n        if sp.issparse(x1):\n            return self._compute_sparse(x1, x2)\n        else:\n            return self._compute_dense(x1, x2)\n\n    def _compute_dense(self, x1, x2):\n        \"\"\"\n        The method uses a function implemented in Cython. Data (`x1` and `x2`)\n        is accompanied by two tables. One is a 2-d table in which elements of\n        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector\n        indicating rows (or column) with nan values.\n\n        The function in Cython uses a fast loop without any conditions to\n        compute distances between rows without missing values, and a slower\n        loop for those with missing values.\n        \"\"\"\n        # view is false positive, pylint: disable=no-member\n        nonzeros1 = np.not_equal(x1, 0).view(np.int8)\n        if self.axis == 1:\n            nans1 = _distance.any_nan_row(x1)\n            if x2 is None:\n                nonzeros2, nans2 = nonzeros1, nans1\n            else:\n                nonzeros2 = np.not_equal(x2, 0).view(np.int8)\n                nans2 = _distance.any_nan_row(x2)\n            return _distance.jaccard_rows(\n                nonzeros1, nonzeros2,\n                x1, x1 if x2 is None else x2,\n                nans1, nans2,\n                self.ps,\n                x2 is not None)\n        else:\n            nans1 = _distance.any_nan_row(x1.T)\n            return _distance.jaccard_cols(\n                nonzeros1, x1, nans1, self.ps)\n\n    @staticmethod\n    def _compute_sparse(x1, x2=None):\n        symmetric = x2 is None\n        if symmetric:\n            x2 = x1\n        x1 = sp.csr_matrix(x1)\n        x1.eliminate_zeros()\n        x2 = sp.csr_matrix(x2)\n        x2.eliminate_zeros()\n        n, m = x1.shape[0], x2.shape[0]\n        matrix = np.zeros((n, m))\n        for i in range(n):\n            xi_ind = set(x1[i].indices)\n            for j in range(i if symmetric else m):\n                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\\\n                           / len(set(x1[i].indices).union(x1[j].indices))\n                matrix[i, j] = jacc\n                if symmetric:\n                    matrix[j, i] = jacc\n        return matrix\n\n\nclass Jaccard(FittedDistance):\n    supports_sparse = True\n    supports_discrete = True\n    ModelType = JaccardModel\n\n    def fit_rows(self, attributes, x, n_vals):\n        \"\"\"\n        Return a model for computation of Jaccard values. The model stores\n        frequencies of non-zero values per each column.\n        \"\"\"\n        if sp.issparse(x):\n            ps = x.getnnz(axis=0)\n        else:\n            ps = np.fromiter(\n                (_distance.p_nonzero(x[:, col]) for col in range(len(n_vals))),\n                dtype=np.double, count=len(n_vals))\n        return JaccardModel(attributes, self.axis, self.impute, ps)\n\n    fit_cols = fit_rows\n\n    def get_continuous_stats(self, column):\n        # Implement an unneeded abstract method to silence pylint\n        return None\n\n\nclass CorrelationDistanceModel(DistanceModel):\n    \"\"\"Helper class for normal and absolute Pearson and Spearman correlation\"\"\"\n    def __init__(self, absolute, axis=1, impute=False):\n        super().__init__(axis, impute)\n        self.absolute = absolute\n\n    def compute_distances(self, x1, x2):\n        rho = self.compute_correlation(x1, x2)\n        if self.absolute:\n            return (1. - np.abs(rho)) / 2.\n        else:\n            return (1. - rho) / 2.\n\n    def compute_correlation(self, x1, x2):\n        raise NotImplementedError()\n\n\nclass SpearmanModel(CorrelationDistanceModel):\n    def compute_correlation(self, x1, x2):\n        if x2 is None:\n            n1 = x1.shape[1 - self.axis]\n            if n1 == 1:\n                rho = 1.0\n            elif n1 == 2:\n                # Special case to properly fill degenerate self correlations\n                # (nan, inf on the diagonals)\n                rho = stats.spearmanr(x1, x1, axis=self.axis)[0]\n                assert rho.shape == (4, 4)\n                rho = rho[:2, :2].copy()\n            else:\n                # scalar if n1 == 1\n                rho = stats.spearmanr(x1, axis=self.axis)[0]\n            return np.atleast_2d(rho)\n        else:\n            return _spearmanr2(x1, x2, axis=self.axis)\n\n\ndef _spearmanr2(a, b, axis=0):\n    \"\"\"\n    Compute all pairwise spearman rank moment correlations between rows\n    or columns of a and b\n\n    Parameters\n    ----------\n    a : (N, M) numpy.ndarray\n        The input cases a.\n    b : (J, K) numpy.ndarray\n        The input cases b. In case of axis == 0: J must equal N;\n        otherwise if axis == 1 then K must equal M.\n    axis : int\n        If 0 the correlation are computed between a and b's columns.\n        Otherwise if 1 the correlations are computed between rows.\n\n    Returns\n    -------\n    cor : (N, J) or (M, K) nd.array\n        If axis == 0 then (N, J) matrix of correlations between a x b columns\n        else a (N, J) matrix of correlations between a x b rows.\n\n    See Also\n    --------\n    scipy.stats.spearmanr\n    \"\"\"\n    a, b = np.atleast_2d(a, b)\n    assert a.shape[axis] == b.shape[axis]\n    ar = np.apply_along_axis(stats.rankdata, axis, a)\n    br = np.apply_along_axis(stats.rankdata, axis, b)\n\n    return _corrcoef2(ar, br, axis=axis)\n\n\ndef _corrcoef2(a, b, axis=0):\n    \"\"\"\n    Compute all pairwise Pearson product-moment correlation coefficients\n    between rows or columns of a and b\n\n    Parameters\n    ----------\n    a : (N, M) numpy.ndarray\n        The input cases a.\n    b : (J, K) numpy.ndarray\n        The input cases b. In case of axis == 0: J must equal N;\n        otherwise if axis == 1 then K must equal M.\n    axis : int\n        If 0 the correlation are computed between a and b's columns.\n        Otherwise if 1 the correlations are computed between rows.\n\n    Returns\n    -------\n    cor : (N, J) or (M, K) nd.array\n        If axis == 0 then (N, J) matrix of correlations between a x b columns\n        else a (N, J) matrix of correlations between a x b rows.\n\n    See Also\n    --------\n    numpy.corrcoef\n    \"\"\"\n    a, b = np.atleast_2d(a, b)\n    if axis not in (0, 1):\n        raise ValueError(\"Invalid axis {} (only 0 or 1 accepted)\".format(axis))\n\n    mean_a = np.mean(a, axis=axis, keepdims=True)\n    mean_b = np.mean(b, axis=axis, keepdims=True)\n    assert a.shape[axis] == b.shape[axis]\n\n    n = a.shape[1 - axis]\n    m = b.shape[1 - axis]\n\n    a = a - mean_a\n    b = b - mean_b\n\n    if axis == 0:\n        C = a.T.dot(b)\n        assert C.shape == (n, m)\n    elif axis == 1:\n        C = a.dot(b.T)\n        assert C.shape == (n, m)\n\n    ss_a = np.sum(a ** 2, axis=axis, keepdims=True)\n    ss_b = np.sum(b ** 2, axis=axis, keepdims=True)\n\n    if axis == 0:\n        ss_a = ss_a.T\n    else:\n        ss_b = ss_b.T\n\n    assert ss_a.shape == (n, 1)\n    assert ss_b.shape == (1, m)\n    C /= np.sqrt(ss_a)\n    C /= np.sqrt(ss_b)\n    return C\n\n\nclass CorrelationDistance(Distance):\n    # pylint: disable=abstract-method\n    supports_missing = False\n\n\nclass SpearmanR(CorrelationDistance):\n    def fit(self, _):\n        return SpearmanModel(False, self.axis, self.impute)\n\n\nclass SpearmanRAbsolute(CorrelationDistance):\n    def fit(self, _):\n        return SpearmanModel(True, self.axis, self.impute)\n\n\nclass PearsonModel(CorrelationDistanceModel):\n    def compute_correlation(self, x1, x2):\n        if x2 is None:\n            c = np.corrcoef(x1, rowvar=self.axis == 1)\n            return np.atleast_2d(c)\n        else:\n            return _corrcoef2(x1, x2, axis=self.axis)\n\n\nclass PearsonR(CorrelationDistance):\n    def fit(self, _):\n        return PearsonModel(False, self.axis, self.impute)\n\n\nclass PearsonRAbsolute(CorrelationDistance):\n    def fit(self, _):\n        return PearsonModel(True, self.axis, self.impute)\n\n\nclass Mahalanobis(Distance):\n    supports_sparse = False\n    supports_missing = False\n\n    def fit(self, data):\n        \"\"\"Return a model with stored inverse covariance matrix\"\"\"\n        x = _orange_to_numpy(data)\n        if self.axis == 0:\n            x = x.T\n        try:\n            c = np.cov(x.T)\n        except:\n            raise MemoryError(\"Covariance matrix is too large.\")\n        try:\n            vi = np.linalg.inv(c)\n        except:\n            raise ValueError(\"Computation of inverse covariance matrix failed.\")\n        return MahalanobisModel(self.axis, self.impute, vi)\n\n\nclass MahalanobisModel(DistanceModel):\n    def __init__(self, axis, impute, vi):\n        super().__init__(axis, impute)\n        self.vi = vi\n\n    def __call__(self, e1, e2=None, impute=None):\n        # argument `impute` is here just for backward compatibility; don't use\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2):\n        if self.axis == 0:\n            x1 = x1.T\n            if x2 is not None:\n                x2 = x2.T\n        if x1.shape[1] != self.vi.shape[0] or \\\n                x2 is not None and x2.shape[1] != self.vi.shape[0]:\n            raise ValueError('Incorrect number of features.')\n        return skl_metrics.pairwise.pairwise_distances(\n            x1, x2, metric='mahalanobis', VI=self.vi)\n\n\n# TODO: Appears to have been used only in the Distances widget (where it had\n# to be handled as a special case and is now replaced with the above class)\n# and in tests. Remove?\nclass MahalanobisDistance:\n    \"\"\"\n    Obsolete class needed for backward compatibility.\n\n    Previous implementation of instances did not have a separate fitting phase,\n    except for MahalanobisDistance, which was implemented in a single class\n    but required first (explicitly) calling the method 'fit'. The backward\n    compatibility hack in :obj:`Distance` cannot handle such use, hence it\n    is provided in this class.\n    \"\"\"\n    def __new__(cls, data=None, axis=1, _='Mahalanobis'):\n        if data is None:\n            return cls\n        return Mahalanobis(axis=axis).fit(data)\n\nclass Hamming(Distance):\n    supports_sparse = False\n    supports_missing = False\n    supports_normalization = False\n    supports_discrete = True\n\n    def fit(self, data):\n        x = _orange_to_numpy(data)\n        if self.axis == 0:\n            return HammingColumnsModel(self.axis, self.impute, x)\n        else:\n            return HammingRowsModel(self.axis, self.impute, x)\n\nclass HammingColumnsModel(DistanceModel):\n    \"\"\"\n    Model for computation of Hamming distances between columns.\n    \"\"\"\n    def __init__(self, axis, impute, x):\n        super().__init__(axis, impute)\n        self.x = x\n\n    def __call__(self, e1, e2=None, impute=None):\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2=None):\n        return pairwise_distances(x1.T, metric='hamming')\n\nclass HammingRowsModel(DistanceModel):\n    \"\"\"\n    Model for computation of Hamming distances between rows.\n    \"\"\"\n    def __init__(self, axis, impute, x):\n        super().__init__(axis, impute)\n        self.x = x\n\n    def __call__(self, e1, e2=None, impute=None):\n        if impute is not None:\n            self.impute = impute\n        return super().__call__(e1, e2)\n\n    def compute_distances(self, x1, x2=None):\n        return pairwise_distances(x1, metric='hamming')\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Jaccard distance computation raises ZeroDivisionError for instances with no active features

**Description:**
When calculating the Jaccard distance between instances that have no active features (i.e., all feature values are zero), the computation results in a division by zero error.

**Example:**
```python
from Orange.distance import Jaccard
from Orange.data import Table, Domain
from Orange.data.variable import ContinuousVariable
from scipy.sparse import csr_matrix

# Define the domain with continuous variables
domain = Domain([ContinuousVariable(c) for c in "abc"])

# Create dense data with instances having no overlapping features
dense_data = Table.from_list(domain, [
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 1]
])

# Convert dense data to sparse format
sparse_data = Table(domain, csr_matrix(dense_data.X))

# Initialize Jaccard distance
jaccard = Jaccard(dense_data)

# Attempt to compute distance between two instances with no active features
distance = jaccard[0][1]  # This raises ZeroDivisionError
```

**Expected Behavior:**
When computing the Jaccard distance between instances with no active features, the distance should be defined as 0 to indicate no dissimilarity, rather than causing an error.

**Actual Behavior:**
A `ZeroDivisionError` is raised during the distance computation when both instances have no active features, preventing the calculation from completing successfully.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/distance/distance.py
import warnings
from unittest.mock import patch

import numpy as np
from scipy import stats
from scipy import sparse as sp
import sklearn.metrics as skl_metrics
from sklearn.utils.extmath import row_norms, safe_sparse_dot
from sklearn.metrics import pairwise_distances

from Orange.distance import _distance
from Orange.statistics import util

from .base import (Distance, DistanceModel, FittedDistance, FittedDistanceModel,
                   SklDistance, _orange_to_numpy)


class EuclideanRowsModel(FittedDistanceModel):
    """
    Model for computation of Euclidean distances between rows.

    Means are used as offsets for normalization, and two deviations are
    used for scaling.
    """
    def __init__(self, attributes, impute, normalize,
                 continuous, discrete,
                 means, stdvars, dist_missing2_cont,
                 dist_missing_disc, dist_missing2_disc):
        super().__init__(attributes, 1, impute)
        self.normalize = normalize
        self.continuous = continuous
        self.discrete = discrete
        self.means = means
        self.vars = stdvars
        self.dist_missing2_cont = dist_missing2_cont
        self.dist_missing_disc = dist_missing_disc
        self.dist_missing2_disc = dist_missing2_disc

    def compute_distances(self, x1, x2=None):
        """
        The method
        - extracts normalized continuous attributes and then uses `row_norms`
          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2
          (the trick from sklearn);
        - calls a function in Cython that recomputes the distances between pairs
          of rows that yielded nan
        - calls a function in Cython that adds the contributions of discrete
          columns
        """
        if self.continuous.any():
            data1, data2 = self.continuous_columns(
                x1, x2, self.means, np.sqrt(2 * self.vars))

            # adapted from sklearn.metric.euclidean_distances
            xx = row_norms(data1, squared=True)[:, np.newaxis]
            if x2 is not None:
                yy = row_norms(data2, squared=True)[np.newaxis, :]
            else:
                yy = xx.T
            distances = safe_sparse_dot(data1, data2.T, dense_output=True)
            distances *= -2
            distances += xx
            distances += yy
            with np.errstate(invalid="ignore"):  # Nans are fixed below
                np.maximum(distances, 0, out=distances)
            if x2 is None:
                distances.flat[::distances.shape[0] + 1] = 0.0
            fixer = _distance.fix_euclidean_rows_normalized if self.normalize \
                else _distance.fix_euclidean_rows
            fixer(distances, data1, data2,
                  self.means, self.vars, self.dist_missing2_cont,
                  x2 is not None)
        else:
            distances = np.zeros((x1.shape[0],
                                  (x2 if x2 is not None else x1).shape[0]))

        if np.any(self.discrete):
            data1, data2 = self.discrete_columns(x1, x2)
            _distance.euclidean_rows_discrete(
                distances, data1, data2, self.dist_missing_disc,
                self.dist_missing2_disc, x2 is not None)

        if x2 is None:
            _distance.lower_to_symmetric(distances)
        return np.sqrt(distances)


class EuclideanColumnsModel(FittedDistanceModel):
    """
    Model for computation of Euclidean distances between columns.

    Means are used as offsets for normalization, and two deviations are
    used for scaling.
    """
    def __init__(self, attributes, impute, normalize, means, stdvars):
        super().__init__(attributes, 0, impute)
        self.normalize = normalize
        self.means = means
        self.vars = stdvars

    def compute_distances(self, x1, x2=None):
        """
        The method
        - extracts normalized continuous attributes and then uses `row_norms`
          and `safe_sparse_do`t to compute the distance as x^2 - 2xy - y^2
          (the trick from sklearn);
        - calls a function in Cython that adds the contributions of discrete
          columns
        """
        if self.normalize:
            x1 = x1 - self.means
            x1 /= np.sqrt(2 * self.vars)

        # adapted from sklearn.metric.euclidean_distances
        xx = row_norms(x1.T, squared=True)[:, np.newaxis]
        distances = safe_sparse_dot(x1.T, x1, dense_output=True)
        distances *= -2
        distances += xx
        distances += xx.T
        with np.errstate(invalid="ignore"):  # Nans are fixed below
            np.maximum(distances, 0, out=distances)
        distances.flat[::distances.shape[0] + 1] = 0.0

        fixer = _distance.fix_euclidean_cols_normalized if self.normalize \
            else _distance.fix_euclidean_cols
        fixer(distances, x1, self.means, self.vars)
        return np.sqrt(distances)


class Euclidean(FittedDistance):
    supports_sparse = True  # via fallback
    supports_discrete = True
    supports_normalization = True
    fallback = SklDistance('euclidean')
    rows_model_type = EuclideanRowsModel

    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):
        # pylint: disable=arguments-differ
        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)

    def get_continuous_stats(self, column):
        """
        Return mean, variance and distance betwwen pairs of missing values
        for the given columns. The method is called by inherited `fit_rows`
        to construct a row-distance model
        """
        mean = util.nanmean(column)
        var = util.nanvar(column)
        if self.normalize:
            if var == 0:
                return None
            dist_missing2_cont = 1
        else:
            dist_missing2_cont = 2 * var
            if np.isnan(dist_missing2_cont):
                dist_missing2_cont = 0
        return mean, var, dist_missing2_cont

    def fit_cols(self, attributes, x, n_vals):
        """
        Return `EuclideanColumnsModel` with stored means and variances
        for normalization and imputation.
        """
        def nowarn(msg, cat, *args, **kwargs):
            if cat is RuntimeWarning and msg in (
                    "Mean of empty slice", "Degrees of freedom <= 0 for slice"):
                if self.normalize:
                    raise ValueError("some columns have no defined values")
            else:
                orig_warn(msg, cat, *args, **kwargs)

        self.check_no_discrete(n_vals)
        # catch_warnings resets the registry for "once", while avoiding this
        # warning would be annoying and slow, hence patching
        orig_warn = warnings.warn
        with patch("warnings.warn", new=nowarn):
            means = np.nanmean(x, axis=0)
            stdvars = np.nanvar(x, axis=0)
        if self.normalize and not stdvars.all():
            raise ValueError("some columns are constant")
        return EuclideanColumnsModel(
            attributes, self.impute, self.normalize, means, stdvars)


class ManhattanRowsModel(FittedDistanceModel):
    """
    Model for computation of Euclidean distances between rows.

    Means are used as offsets for normalization, and two deviations are
    used for scaling.
    """
    def __init__(self, attributes, impute, normalize,
                 continuous, discrete,
                 medians, mads, dist_missing2_cont,
                 dist_missing_disc, dist_missing2_disc):
        super().__init__(attributes, 1, impute)
        self.normalize = normalize
        self.continuous = continuous
        self.discrete = discrete
        self.medians = medians
        self.mads = mads
        self.dist_missing2_cont = dist_missing2_cont
        self.dist_missing_disc = dist_missing_disc
        self.dist_missing2_disc = dist_missing2_disc

    def compute_distances(self, x1, x2):
        """
        The method
        - extracts normalized continuous attributes and computes distances
          ignoring the possibility of nans
        - recomputes the distances between pairs of rows that yielded nans
        - adds the contributions of discrete columns using the same function as
          the Euclidean distance
        """
        if self.continuous.any():
            data1, data2 = self.continuous_columns(
                x1, x2, self.medians, 2 * self.mads)
            distances = _distance.manhattan_rows_cont(
                data1, data2, x2 is not None)
            if self.normalize:
                _distance.fix_manhattan_rows_normalized(
                    distances, data1, data2, x2 is not None)
            else:
                _distance.fix_manhattan_rows(
                    distances, data1, data2,
                    self.medians, self.mads, self.dist_missing2_cont,
                    x2 is not None)
        else:
            distances = np.zeros((x1.shape[0],
                                  (x2 if x2 is not None else x1).shape[0]))

        if np.any(self.discrete):
            data1, data2 = self.discrete_columns(x1, x2)
            # For discrete attributes, Euclidean is same as Manhattan
            _distance.euclidean_rows_discrete(
                distances, data1, data2, self.dist_missing_disc,
                self.dist_missing2_disc, x2 is not None)

        if x2 is None:
            _distance.lower_to_symmetric(distances)
        return distances


class ManhattanColumnsModel(FittedDistanceModel):
    """
    Model for computation of Manhattan distances between columns.

    Medians are used as offsets for normalization, and two MADS are
    used for scaling.
    """

    def __init__(self, attributes, impute, normalize, medians, mads):
        super().__init__(attributes, 0, impute)
        self.normalize = normalize
        self.medians = medians
        self.mads = mads

    def compute_distances(self, x1, x2=None):
        if self.normalize:
            x1 = x1 - self.medians
            x1 /= 2
            x1 /= self.mads
        return _distance.manhattan_cols(x1, self.medians, self.mads, self.normalize)


class Manhattan(FittedDistance):
    supports_sparse = True  # via fallback
    supports_discrete = True
    supports_normalization = True
    fallback = SklDistance('manhattan')
    rows_model_type = ManhattanRowsModel

    def __new__(cls, e1=None, e2=None, axis=1, impute=False, normalize=False):
        # pylint: disable=arguments-differ
        return super().__new__(cls, e1, e2, axis, impute, normalize=normalize)

    def get_continuous_stats(self, column):
        """
        Return median, MAD and distance betwwen pairs of missing values
        for the given columns. The method is called by inherited `fit_rows`
        to construct a row-distance model
        """
        median = np.nanmedian(column)
        mad = np.nanmedian(np.abs(column - median))
        if self.normalize:
            if mad == 0:
                return None
            dist_missing2_cont = 1
        else:
            dist_missing2_cont = 2 * mad
            if np.isnan(dist_missing2_cont):
                dist_missing2_cont = 0
        return median, mad, dist_missing2_cont

    def fit_cols(self, attributes, x, n_vals):
        """
        Return `ManhattanColumnsModel` with stored medians and MADs
        for normalization and imputation.
        """
        self.check_no_discrete(n_vals)
        if x.size == 0:
            medians = np.zeros(len(x))
            mads = np.zeros(len(x))
        else:
            medians = np.nanmedian(x, axis=0)
            mads = np.nanmedian(np.abs(x - medians), axis=0)
        if self.normalize and (np.isnan(mads).any() or not mads.all()):
            raise ValueError(
                "some columns have zero absolute distance from median, "
                "or no values")
        return ManhattanColumnsModel(
            attributes, self.impute, self.normalize, medians, mads)


class Cosine(FittedDistance):
    supports_sparse = True  # via fallback
    supports_discrete = False
    fallback = SklDistance('cosine')

    @staticmethod
    def discrete_to_indicators(x, discrete):
        """Change non-zero values of discrete attributes to 1."""
        if discrete.any():
            x = x.copy()
            for col, disc in enumerate(discrete):
                if disc:
                    x[:, col].clip(0, 1, out=x[:, col])
        return x

    def fit_rows(self, attributes, x, n_vals):
        """Return a model for cosine distances with stored means for imputation
        """
        discrete = n_vals > 0
        x = self.discrete_to_indicators(x, discrete)
        means = util.nanmean(x, axis=0)
        means = np.nan_to_num(means)
        return self.CosineModel(attributes, self.axis, self.impute,
                                discrete, means)

    fit_cols = fit_rows

    def get_continuous_stats(self, column):
        # Implement an unneeded abstract method to silence pylint
        return None

    class CosineModel(FittedDistanceModel):
        """Model for computation of cosine distances across rows and columns.
        All non-zero discrete values are treated as 1."""
        def __init__(self, attributes, axis, impute, discrete, means):
            super().__init__(attributes, axis, impute)
            self.discrete = discrete
            self.means = means

        def compute_distances(self, x1, x2):
            """
            The method imputes the missing values as means and calls
            safe_sparse_dot. Imputation simplifies computation at a cost of
            (theoretically) slightly wrong distance between pairs of missing
             values.
            """

            def prepare_data(x):
                if self.discrete.any():
                    data = Cosine.discrete_to_indicators(x, self.discrete)
                else:
                    data = x.copy()
                for col, mean in enumerate(self.means):
                    column = data[:, col]
                    column[np.isnan(column)] = mean
                if self.axis == 0:
                    data = data.T
                data /= row_norms(data)[:, np.newaxis]
                return data

            data1 = prepare_data(x1)
            data2 = data1 if x2 is None else prepare_data(x2)
            dist = safe_sparse_dot(data1, data2.T)
            np.clip(dist, -1, 1, out=dist)
            if x2 is None:
                diag = np.diag_indices_from(dist)
                dist[diag] = np.where(np.isnan(dist[diag]), np.nan, 1.0)
            return 1 - dist


class JaccardModel(FittedDistanceModel):
    """
    Model for computation of cosine distances across rows and columns.
    All non-zero values are treated as 1.
    """
    def __init__(self, attributes, axis, impute, ps):
        super().__init__(attributes, axis, impute)
        self.ps = ps

    def compute_distances(self, x1, x2):
        if sp.issparse(x1):
            return self._compute_sparse(x1, x2)
        else:
            return self._compute_dense(x1, x2)

    def _compute_dense(self, x1, x2):
        """
        The method uses a function implemented in Cython. Data (`x1` and `x2`)
        is accompanied by two tables. One is a 2-d table in which elements of
        `x1` (`x2`) are replaced by 0's and 1's. The other is a vector
        indicating rows (or column) with nan values.

        The function in Cython uses a fast loop without any conditions to
        compute distances between rows without missing values, and a slower
        loop for those with missing values.
        """
        # view is false positive, pylint: disable=no-member
        nonzeros1 = np.not_equal(x1, 0).view(np.int8)
        if self.axis == 1:
            nans1 = _distance.any_nan_row(x1)
            if x2 is None:
                nonzeros2, nans2 = nonzeros1, nans1
            else:
                nonzeros2 = np.not_equal(x2, 0).view(np.int8)
                nans2 = _distance.any_nan_row(x2)
            return _distance.jaccard_rows(
                nonzeros1, nonzeros2,
                x1, x1 if x2 is None else x2,
                nans1, nans2,
                self.ps,
                x2 is not None)
        else:
            nans1 = _distance.any_nan_row(x1.T)
            return _distance.jaccard_cols(
                nonzeros1, x1, nans1, self.ps)

    @staticmethod
    def _compute_sparse(x1, x2=None):
        symmetric = x2 is None
        if symmetric:
            x2 = x1
        x1 = sp.csr_matrix(x1)
        x1.eliminate_zeros()
        x2 = sp.csr_matrix(x2)
        x2.eliminate_zeros()
        n, m = x1.shape[0], x2.shape[0]
        matrix = np.zeros((n, m))
        for i in range(n):
            xi_ind = set(x1[i].indices)
            for j in range(i if symmetric else m):
                jacc = 1 - len(xi_ind.intersection(x2[j].indices))\
                           / len(set(x1[i].indices).union(x1[j].indices))
                matrix[i, j] = jacc
                if symmetric:
                    matrix[j, i] = jacc
        return matrix


class Jaccard(FittedDistance):
    supports_sparse = True
    supports_discrete = True
    ModelType = JaccardModel

    def fit_rows(self, attributes, x, n_vals):
        """
        Return a model for computation of Jaccard values. The model stores
        frequencies of non-zero values per each column.
        """
        if sp.issparse(x):
            ps = x.getnnz(axis=0)
        else:
            ps = np.fromiter(
                (_distance.p_nonzero(x[:, col]) for col in range(len(n_vals))),
                dtype=np.double, count=len(n_vals))
        return JaccardModel(attributes, self.axis, self.impute, ps)

    fit_cols = fit_rows

    def get_continuous_stats(self, column):
        # Implement an unneeded abstract method to silence pylint
        return None


class CorrelationDistanceModel(DistanceModel):
    """Helper class for normal and absolute Pearson and Spearman correlation"""
    def __init__(self, absolute, axis=1, impute=False):
        super().__init__(axis, impute)
        self.absolute = absolute

    def compute_distances(self, x1, x2):
        rho = self.compute_correlation(x1, x2)
        if self.absolute:
            return (1. - np.abs(rho)) / 2.
        else:
            return (1. - rho) / 2.

    def compute_correlation(self, x1, x2):
        raise NotImplementedError()


class SpearmanModel(CorrelationDistanceModel):
    def compute_correlation(self, x1, x2):
        if x2 is None:
            n1 = x1.shape[1 - self.axis]
            if n1 == 1:
                rho = 1.0
            elif n1 == 2:
                # Special case to properly fill degenerate self correlations
                # (nan, inf on the diagonals)
                rho = stats.spearmanr(x1, x1, axis=self.axis)[0]
                assert rho.shape == (4, 4)
                rho = rho[:2, :2].copy()
            else:
                # scalar if n1 == 1
                rho = stats.spearmanr(x1, axis=self.axis)[0]
            return np.atleast_2d(rho)
        else:
            return _spearmanr2(x1, x2, axis=self.axis)


def _spearmanr2(a, b, axis=0):
    """
    Compute all pairwise spearman rank moment correlations between rows
    or columns of a and b

    Parameters
    ----------
    a : (N, M) numpy.ndarray
        The input cases a.
    b : (J, K) numpy.ndarray
        The input cases b. In case of axis == 0: J must equal N;
        otherwise if axis == 1 then K must equal M.
    axis : int
        If 0 the correlation are computed between a and b's columns.
        Otherwise if 1 the correlations are computed between rows.

    Returns
    -------
    cor : (N, J) or (M, K) nd.array
        If axis == 0 then (N, J) matrix of correlations between a x b columns
        else a (N, J) matrix of correlations between a x b rows.

    See Also
    --------
    scipy.stats.spearmanr
    """
    a, b = np.atleast_2d(a, b)
    assert a.shape[axis] == b.shape[axis]
    ar = np.apply_along_axis(stats.rankdata, axis, a)
    br = np.apply_along_axis(stats.rankdata, axis, b)

    return _corrcoef2(ar, br, axis=axis)


def _corrcoef2(a, b, axis=0):
    """
    Compute all pairwise Pearson product-moment correlation coefficients
    between rows or columns of a and b

    Parameters
    ----------
    a : (N, M) numpy.ndarray
        The input cases a.
    b : (J, K) numpy.ndarray
        The input cases b. In case of axis == 0: J must equal N;
        otherwise if axis == 1 then K must equal M.
    axis : int
        If 0 the correlation are computed between a and b's columns.
        Otherwise if 1 the correlations are computed between rows.

    Returns
    -------
    cor : (N, J) or (M, K) nd.array
        If axis == 0 then (N, J) matrix of correlations between a x b columns
        else a (N, J) matrix of correlations between a x b rows.

    See Also
    --------
    numpy.corrcoef
    """
    a, b = np.atleast_2d(a, b)
    if axis not in (0, 1):
        raise ValueError("Invalid axis {} (only 0 or 1 accepted)".format(axis))

    mean_a = np.mean(a, axis=axis, keepdims=True)
    mean_b = np.mean(b, axis=axis, keepdims=True)
    assert a.shape[axis] == b.shape[axis]

    n = a.shape[1 - axis]
    m = b.shape[1 - axis]

    a = a - mean_a
    b = b - mean_b

    if axis == 0:
        C = a.T.dot(b)
        assert C.shape == (n, m)
    elif axis == 1:
        C = a.dot(b.T)
        assert C.shape == (n, m)

    ss_a = np.sum(a ** 2, axis=axis, keepdims=True)
    ss_b = np.sum(b ** 2, axis=axis, keepdims=True)

    if axis == 0:
        ss_a = ss_a.T
    else:
        ss_b = ss_b.T

    assert ss_a.shape == (n, 1)
    assert ss_b.shape == (1, m)
    C /= np.sqrt(ss_a)
    C /= np.sqrt(ss_b)
    return C


class CorrelationDistance(Distance):
    # pylint: disable=abstract-method
    supports_missing = False


class SpearmanR(CorrelationDistance):
    def fit(self, _):
        return SpearmanModel(False, self.axis, self.impute)


class SpearmanRAbsolute(CorrelationDistance):
    def fit(self, _):
        return SpearmanModel(True, self.axis, self.impute)


class PearsonModel(CorrelationDistanceModel):
    def compute_correlation(self, x1, x2):
        if x2 is None:
            c = np.corrcoef(x1, rowvar=self.axis == 1)
            return np.atleast_2d(c)
        else:
            return _corrcoef2(x1, x2, axis=self.axis)


class PearsonR(CorrelationDistance):
    def fit(self, _):
        return PearsonModel(False, self.axis, self.impute)


class PearsonRAbsolute(CorrelationDistance):
    def fit(self, _):
        return PearsonModel(True, self.axis, self.impute)


class Mahalanobis(Distance):
    supports_sparse = False
    supports_missing = False

    def fit(self, data):
        """Return a model with stored inverse covariance matrix"""
        x = _orange_to_numpy(data)
        if self.axis == 0:
            x = x.T
        try:
            c = np.cov(x.T)
        except:
            raise MemoryError("Covariance matrix is too large.")
        try:
            vi = np.linalg.inv(c)
        except:
            raise ValueError("Computation of inverse covariance matrix failed.")
        return MahalanobisModel(self.axis, self.impute, vi)


class MahalanobisModel(DistanceModel):
    def __init__(self, axis, impute, vi):
        super().__init__(axis, impute)
        self.vi = vi

    def __call__(self, e1, e2=None, impute=None):
        # argument `impute` is here just for backward compatibility; don't use
        if impute is not None:
            self.impute = impute
        return super().__call__(e1, e2)

    def compute_distances(self, x1, x2):
        if self.axis == 0:
            x1 = x1.T
            if x2 is not None:
                x2 = x2.T
        if x1.shape[1] != self.vi.shape[0] or \
                x2 is not None and x2.shape[1] != self.vi.shape[0]:
            raise ValueError('Incorrect number of features.')
        return skl_metrics.pairwise.pairwise_distances(
            x1, x2, metric='mahalanobis', VI=self.vi)


# TODO: Appears to have been used only in the Distances widget (where it had
# to be handled as a special case and is now replaced with the above class)
# and in tests. Remove?
class MahalanobisDistance:
    """
    Obsolete class needed for backward compatibility.

    Previous implementation of instances did not have a separate fitting phase,
    except for MahalanobisDistance, which was implemented in a single class
    but required first (explicitly) calling the method 'fit'. The backward
    compatibility hack in :obj:`Distance` cannot handle such use, hence it
    is provided in this class.
    """
    def __new__(cls, data=None, axis=1, _='Mahalanobis'):
        if data is None:
            return cls
        return Mahalanobis(axis=axis).fit(data)

class Hamming(Distance):
    supports_sparse = False
    supports_missing = False
    supports_normalization = False
    supports_discrete = True

    def fit(self, data):
        x = _orange_to_numpy(data)
        if self.axis == 0:
            return HammingColumnsModel(self.axis, self.impute, x)
        else:
            return HammingRowsModel(self.axis, self.impute, x)

class HammingColumnsModel(DistanceModel):
    """
    Model for computation of Hamming distances between columns.
    """
    def __init__(self, axis, impute, x):
        super().__init__(axis, impute)
        self.x = x

    def __call__(self, e1, e2=None, impute=None):
        if impute is not None:
            self.impute = impute
        return super().__call__(e1, e2)

    def compute_distances(self, x1, x2=None):
        return pairwise_distances(x1.T, metric='hamming')

class HammingRowsModel(DistanceModel):
    """
    Model for computation of Hamming distances between rows.
    """
    def __init__(self, axis, impute, x):
        super().__init__(axis, impute)
        self.x = x

    def __call__(self, e1, e2=None, impute=None):
        if impute is not None:
            self.impute = impute
        return super().__call__(e1, e2)

    def compute_distances(self, x1, x2=None):
        return pairwise_distances(x1, metric='hamming')

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user