Skip to content
This repository was archived by the owner on Oct 21, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion diffxpy/pkg_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@

BATCHGLM_BACKEND = "tf1"
BATCHGLM_FEATUREWISE = True
BATCHGLM_AUTOGRAD = True
BATCHGLM_AUTOGRAD = False
2 changes: 2 additions & 0 deletions diffxpy/testing/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ def _fit(
constructor_args = {}
if quick_scale is not None:
constructor_args["quick_scale"] = quick_scale
if batch_size is not None and backend != "tf2":
constructor_args["batch_size"] = batch_size
# Backend-specific constructor arguments:
if backend.lower() in ["tf1"]:
constructor_args['provide_optimizers'] = {
Expand Down
81 changes: 81 additions & 0 deletions diffxpy/unit_test/test_compare_numpy_tf2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import unittest
import logging
import diffxpy.api as de
import numpy as np


class TestBackendsNb(unittest.TestCase):

"""
Negative binomial noise model unit tests that test whether the wald test results
in the same logfoldchange, p- and q-values and the coefficents are the same after
fitting when using the same simulated data.
"""

def __init__(self, *args, **kwargs):

super(TestBackendsNb, self).__init__(*args, **kwargs)

from batchglm.api.models.numpy.glm_nb import Simulator
self.sim = Simulator(num_observations=10000, num_features=200)
self.sim.generate_sample_description(num_batches=0, num_conditions=4)
self.sim.generate_params()
self.sim.generate_data()

logging.getLogger("tensorflow").setLevel(logging.ERROR)
logging.getLogger("batchglm").setLevel(logging.WARNING)
logging.getLogger("diffxpy").setLevel(logging.WARNING)

self.numpy_results = de.test.wald(
data=self.sim.input_data,
sample_description=self.sim.sample_description,
factor_loc_totest="condition",
formula_loc="~ 1 + condition + batch",
noise_model='nb',
backend='numpy'
)
_ = self.numpy_results.summary()

self.tf2_results = de.test.wald(
data=self.sim.input_data,
sample_description=self.sim.sample_description,
factor_loc_totest="condition",
formula_loc="~ 1 + condition + batch",
noise_model='nb',
backend='tf2'
)
_ = self.tf2_results.summary()

"""
Test with numpy:
"""

def test_coeff_similarity(self):

a_var_max_diff = np.max(np.abs(self.tf2_results.model_estim.a_var-self.numpy_results.model_estim.a_var))
b_var_max_diff = np.max(np.abs(self.tf2_results.model_estim.b_var-self.numpy_results.model_estim.b_var))
assert a_var_max_diff < 1e-6 and b_var_max_diff < 1e-6, \
("a_var_max_diff: %f, b_var_max_diff: %f", a_var_max_diff, b_var_max_diff)

return True

def test_logfoldchange_similarity(self):
max_diff = np.max(np.abs(self.tf2_results.summary()['log2fc'].values-self.numpy_results.summary()['log2fc'].values))
assert max_diff < 1e-12, ("log_fold_change difference: %f > 1e-12", max_diff)

return True

def test_pval_similarity(self):
max_diff = np.max(np.abs(self.tf2_results.pval-self.numpy_results.pval))
assert max_diff < 1e-12, ("p-val difference: %f > 1e-12", max_diff)

return True

def test_qval_similarity(self):
max_diff = np.max(np.abs(self.tf2_results.summary()['qval'].values-self.numpy_results.summary()['qval'].values))
assert max_diff < 1e-12, ("q-val difference: %f > 1e-12", max_diff)

return True

if __name__ == '__main__':
unittest.main()
28 changes: 14 additions & 14 deletions diffxpy/unit_test/test_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def _test_model_fit(
"""
Test if de.wald() generates a uniform p-value distribution
if it is given data simulated based on the null model. Returns the p-value
of the two-side Kolmgorov-Smirnov test for equality of the observed
of the two-side Kolmgorov-Smirnov test for equality of the observed
p-value distribution and a uniform distribution.

:param n_cells: Number of cells to simulate (number of observations per test).
Expand All @@ -34,7 +34,7 @@ def _test_model_fit(
raise ValueError("noise model %s not recognized" % noise_model)

sim = Simulator(num_observations=n_cells, num_features=n_genes)
sim.generate_sample_description(num_batches=0, num_conditions=0)
sim.generate_sample_description(num_batches=1, num_conditions=1)
sim.generate_params(rand_fn_scale=rand_fn_scale)
sim.generate_data()

Expand Down Expand Up @@ -77,7 +77,7 @@ def _test_model_fit_partition(
raise ValueError("noise model %s not recognized" % noise_model)

sim = Simulator(num_observations=n_cells, num_features=n_genes)
sim.generate_sample_description(num_batches=0, num_conditions=0)
sim.generate_sample_description(num_batches=1, num_conditions=1)
sim.generate_params(rand_fn_scale=rand_fn_scale)
sim.generate_data()

Expand Down Expand Up @@ -121,7 +121,7 @@ def _test_residuals_fit(
raise ValueError("noise model %s not recognized" % noise_model)

sim = Simulator(num_observations=n_cells, num_features=n_genes)
sim.generate_sample_description(num_batches=0, num_conditions=0)
sim.generate_sample_description(num_batches=1, num_conditions=1)
sim.generate()

random_sample_description = pd.DataFrame({
Expand Down Expand Up @@ -209,23 +209,23 @@ def test_residuals_fit(
noise_model="nb"
)


"""
class TestFitNorm(_TestFit, unittest.TestCase):
"""

Normal noise model unit tests that tests whether model fit relay works.
"""


def test_model_fit(
self,
n_cells: int = 2000,
n_genes: int = 2
):
"""

Test if model fit for "norm" noise model works.

:param n_cells: Number of cells to simulate (number of observations per test).
:param n_genes: Number of genes to simulate (number of tests).
"""

logging.getLogger("tensorflow").setLevel(logging.ERROR)
logging.getLogger("batchglm").setLevel(logging.WARNING)
logging.getLogger("diffxpy").setLevel(logging.WARNING)
Expand All @@ -242,12 +242,12 @@ def test_model_fit_partition(
n_cells: int = 2000,
n_genes: int = 2
):
"""

Test if partitioned model fit for "norm" noise model works.

:param n_cells: Number of cells to simulate (number of observations per test).
:param n_genes: Number of genes to simulate (number of tests).
"""

logging.getLogger("tensorflow").setLevel(logging.ERROR)
logging.getLogger("batchglm").setLevel(logging.WARNING)
logging.getLogger("diffxpy").setLevel(logging.WARNING)
Expand All @@ -264,12 +264,12 @@ def test_residuals_fit(
n_cells: int = 2000,
n_genes: int = 2
):
"""

Test if residual fit for "norm" noise model works.

:param n_cells: Number of cells to simulate (number of observations per test).
:param n_genes: Number of genes to simulate (number of tests).
"""

logging.getLogger("tensorflow").setLevel(logging.ERROR)
logging.getLogger("batchglm").setLevel(logging.WARNING)
logging.getLogger("diffxpy").setLevel(logging.WARNING)
Expand All @@ -280,7 +280,7 @@ def test_residuals_fit(
n_genes=n_genes,
noise_model="norm"
)

"""

if __name__ == '__main__':
unittest.main()