Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b7b0653
Add files via upload
Palash123-4 Jan 25, 2024
68a7cfa
Add the multivariate distance covariance
Palash123-4 Jan 25, 2024
af0568d
Update _dcor.py
Palash123-4 Jan 25, 2024
21f4b8a
Merge branch 'vnmabus:develop' into develop
Palash123-4 Jan 31, 2024
d44fb7d
update random projection-
Jan 31, 2024
946397c
update random projection based test of independence
Jan 31, 2024
62152ef
add dist_sum function
Jan 31, 2024
3207181
Merge branch 'develop' of https://github.com/Palash123-4/dcor into de…
Jan 31, 2024
3b6fde1
add citation of random projections based distance covariance
Jan 31, 2024
8890215
update with spaces
Feb 1, 2024
0b73538
update with spaces
Feb 1, 2024
19a71f6
update with spaces
Feb 1, 2024
db98194
insert .
Feb 1, 2024
d1b4050
insert .
Feb 1, 2024
a41bdb8
insert .
Feb 1, 2024
0496e5a
insert .
Feb 1, 2024
0718f7e
update module
Feb 1, 2024
b25130d
update module
Feb 1, 2024
7b55726
update dimension evaluation
Feb 1, 2024
c89131e
update dimension evaluation
Feb 1, 2024
974c84e
Add files via upload
Palash123-4 May 6, 2024
3d25d06
Add files via upload
Palash123-4 Aug 2, 2024
bb32079
Merge branch 'vnmabus:develop' into develop
Palash123-4 Sep 3, 2024
3f3824c
Fix circular import in _rowwise module initialization
Palash123-4 Apr 20, 2026
1a55352
Merge branch 'develop' into develop
Palash123-4 Apr 20, 2026
eaced17
Fix ReadTheDocs build by using importlib.metadata instead of pkg_reso…
Palash123-4 Apr 20, 2026
6b1ae7e
Merge branch 'develop' of https://github.com/Palash123-4/dcor into de…
Palash123-4 Apr 20, 2026
d90b4a3
Fix BibTeX syntax error in refs.bib
Palash123-4 Apr 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions dcor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,13 @@
)
from ._hypothesis import HypothesisTest as HypothesisTest
from ._partial_dcor import (
partial_distance_correlation,
partial_distance_correlation as partial_distance_correlation,
partial_distance_covariance as partial_distance_covariance,
)
from ._rowwise import RowwiseMode as RowwiseMode, rowwise as rowwise
from ._rowwise import RowwiseMode as RowwiseMode, rowwise as rowwise, _initialize_rowwise_functions
from ._utils import CompileMode as CompileMode

__version__ = "0.8.dev0"
__version__ = "0.6"

# Initialize rowwise functions after all modules are loaded
_initialize_rowwise_functions()
125 changes: 125 additions & 0 deletions dcor/_dcor.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
array_namespace,
numpy_namespace,
)
##Additional module for Multivariate dcov test-----------------------------------------
from scipy.special import gammaln
import math
from dcor._rowwise import rowwise
##-------------------------------------------------------------------------------------

Array = TypeVar("Array", bound=ArrayType)

Expand Down Expand Up @@ -1169,3 +1174,123 @@ def distance_correlation_af_inv(
compile_mode=compile_mode,
),
)





def gamma_ratio(p):
"""
Parameters

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer Google style docstrings over NumPy style ones.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You closed the conversation without changing it, please don't do that.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have replaced ' ' ' by " " "

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Google style docstrings, as opposed to NumPy style docstrings, use a colon to specify sections such as Args: or Returns:, instead of placing hyphens in the line below. See https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html for examples.

----------
p : is the dimension of the data

Returns
-------
This function evaluates the gamma ratio, which is
required to calculate the constants C_p and C_q (in function u_dist_cov_sqr_mv())

"""

return np.exp(gammaln((p + 1) / 2) - gammaln(p / 2))



def rndm_projection(X, p):
"""
Parameters
----------
X : N x p, array of arrays
where, p: number of dimensions (p >= 1) and N: number of samples
p : number of dimensions (p >= 1)

Comment thread
Palash123-4 marked this conversation as resolved.
Returns
-------
X_new : an array of size N
DESCRIPTION: Random projection of multivariate array
"""

# X_std = multivariate_normal.rvs( np.zeros(p), np.identity(p), size = 1)
X_standard = np.random.standard_normal(p)

X_norm = np.linalg.norm(X_standard)
U_sphere = np.array(X_standard) / X_norm # Normalize X_std

if p > 1:
X_new = U_sphere @ X.T
else:
X_new = U_sphere * X
return X_new


def u_dist_cov_sqr_mv(X, Y, n_projs = 500, method = "mergesort"):
r"""
Numerically Efficient Multivariate Distance Covariance Based on
Random Projections, the computation complexity is
:math:`O(kn\log n)`, where k is the number of projections (n_projs)

For more details see,
:footcite:`b-dcov_random_projection`.


Parameters
----------
X : N x p, array of arrays, where p > 1
Y : N x q, array of arrays, where q >= 1
where p and q: number of dimensions of variable X and Y, respectively and N: number of samples

n_projs : Number of projections (integer type), optional
DESCRIPTION. The default is 500.(paper suggests: n_projs < N/logN, larger n_projs provides better results)
method : fast computation method either "mergesort" or "avl", optional
DESCRIPTION. The default is "mergesort".

Returns
-------
omega_bar : Float type
DESCRIPTION: Produce fastly computed unbiased distance covariance between X and Y




Examples:
>>> import numpy as np
>>> import dcor
>>> from scipy.stats import multivariate_normal
>>> mean_vector = [2, 3, 5, 3, 2, 1]
>>> matrix_size = 6
>>> np.random.seed(123) # in order to achieve reproducible results
>>> A = 0.5 * np.random.rand(matrix_size, matrix_size)
>>> B = np.dot(A, A.transpose())
>>> n_samples = 3000
>>> mv = multivariate_normal( mean = mean_vector, cov = B)
>>> X = mv.rvs(size = n_samples, random_state = 123)
>>> X1 = X.T[:4]
>>> X2 = X.T[4:]
>>> print(f"Computing fast distance covariance = {u_dist_cov_sqr_mv(X1.T, X2.T)}")
"""

n_samples = np.shape(X)[0]
p = np.shape(X)[1]
if Y.T.ndim == 1:
q = 1
else:
q = np.shape(Y)[1]

sqrt_pi_value = math.sqrt(math.pi)
C_p = sqrt_pi_value * gamma_ratio(p)
C_q = sqrt_pi_value * gamma_ratio(q)


X_proj = np.empty(( n_projs, n_samples))
Y_proj = np.empty(( n_projs, n_samples))

for i in range(n_projs):
Comment thread
Palash123-4 marked this conversation as resolved.
X_proj[i, :] = rndm_projection(X, p)
Y_proj[i, :] = rndm_projection(Y, q)
pass

omega_ = rowwise(u_distance_covariance_sqr,
X_proj, Y_proj, rowwise_mode = method)
omega_bar = C_p * C_q * np.mean(omega_)

return omega_bar
35 changes: 19 additions & 16 deletions dcor/_rowwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
def _generate_rowwise_distance_covariance_sqr(unbiased):
def rowwise_distance_covariance_sqr(
x, y, exponent=1, *,
method=_dcor.DistanceCovarianceMethod.AUTO,
method=None,
**kwargs):

if method is None:
method = _dcor.DistanceCovarianceMethod.AUTO

if not _dcor._can_use_fast_algorithm(x[0], y[0],
exponent=exponent):
return NotImplemented
Expand All @@ -34,11 +37,13 @@ def rowwise_distance_covariance_sqr(
return rowwise_distance_covariance_sqr


_dcor.distance_covariance_sqr.rowwise_function = (
_generate_rowwise_distance_covariance_sqr(unbiased=False))
def _initialize_rowwise_functions():
"""Initialize rowwise functions after _dcor module is fully loaded."""
_dcor.distance_covariance_sqr.rowwise_function = (
_generate_rowwise_distance_covariance_sqr(unbiased=False))

_dcor.u_distance_covariance_sqr.rowwise_function = (
_generate_rowwise_distance_covariance_sqr(unbiased=True))
_dcor.u_distance_covariance_sqr.rowwise_function = (
_generate_rowwise_distance_covariance_sqr(unbiased=True))


def _rowwise_distance_covariance(*args, **kwargs):
Expand All @@ -50,7 +55,15 @@ def _rowwise_distance_covariance(*args, **kwargs):
return _sqrt(res_covs)


_dcor.distance_covariance.rowwise_function = _rowwise_distance_covariance
_dcor.distance_covariance.rowwise_function = _rowwise_distance_covariance

_dcor.distance_correlation_sqr.rowwise_function = (
_generate_rowwise_distance_correlation_sqr(unbiased=False))

_dcor.u_distance_correlation_sqr.rowwise_function = (
_generate_rowwise_distance_correlation_sqr(unbiased=True))

_dcor.distance_correlation.rowwise_function = _rowwise_distance_correlation


def _generate_rowwise_distance_correlation_sqr(unbiased):
Expand Down Expand Up @@ -82,13 +95,6 @@ def rowwise_distance_correlation_sqr(x, y, **kwargs):
return rowwise_distance_correlation_sqr


_dcor.distance_correlation_sqr.rowwise_function = (
_generate_rowwise_distance_correlation_sqr(unbiased=False))

_dcor.u_distance_correlation_sqr.rowwise_function = (
_generate_rowwise_distance_correlation_sqr(unbiased=True))


def _rowwise_distance_correlation(*args, **kwargs):

res_corrs = _dcor.distance_correlation_sqr.rowwise_function(
Expand All @@ -99,9 +105,6 @@ def _rowwise_distance_correlation(*args, **kwargs):
return _sqrt(res_corrs)


_dcor.distance_correlation.rowwise_function = _rowwise_distance_correlation


def rowwise(
function: Callable[..., Array],
x: Array,
Expand Down
33 changes: 33 additions & 0 deletions dcor/distances.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

from dcor._utils import ArrayType, _sqrt, _transform_to_2d, array_namespace

from numba import njit, prange # Additional repo for dist_sum

from ._utils import _can_be_numpy_double

Array = TypeVar("Array", bound=ArrayType)
Expand Down Expand Up @@ -159,3 +161,34 @@ def pairwise_distances(

x, y = _transform_to_2d(x, y)
return _cdist(x, y, exponent=exponent)





@njit(fastmath=True, parallel=True, cache=True)
def dist_sum(X):
"""
Parameters
----------
X : 1D array.

Returns
-------
res : sum of distinct Euclidean distances corresponding to the elements of X.

Note: To implement numba, one needs to consider "numpy==1.25" or less.
"""
res = 0
for i in prange(len(X)):
for j in prange(len(X)):
if i < j:
res += np.abs(X[i] - X[j])
pass
pass
pass
return res




Loading