diff --git a/.github/workflows/autoreconf.yml b/.github/workflows/autoreconf.yml index eb27c64..21407a6 100644 --- a/.github/workflows/autoreconf.yml +++ b/.github/workflows/autoreconf.yml @@ -21,17 +21,11 @@ jobs: run: | autoreconf -fiv ./configure - make dist - - - name: Extract dist files - run: | - tar -zxvf scdemon-*.tar.gz - cp -r scdemon-*/* . - name: Push to Main Branch run: | git config --global user.name 'GitHub Action' git config --global user.email 'action@github.com' - git add config.guess config.sub configure configure.ac Makefile.in Makefile.am install-sh aclocal.m4 missing DESCRIPTION VERSION + git add configure DESCRIPTION VERSION docs/sphinx/conf.py git commit -m "Auto-update Autotools files" || echo "No changes to commit" git push origin HEAD:main -f \ No newline at end of file diff --git a/.gitignore b/.gitignore index c312387..9e037cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +## makevars +src/Makevars + ## autoconf autom4te.cache/ config.status diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7691e8c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.15...3.27) +project( + ${SKBUILD_PROJECT_NAME} + VERSION ${SKBUILD_PROJECT_VERSION} + LANGUAGES CXX) + +# Set C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) +find_package(pybind11 CONFIG REQUIRED) + +# Find OpenMP +find_package(OpenMP REQUIRED) +if(OpenMP_CXX_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + +# Include Eigen +find_package(Eigen3 3.3 REQUIRED NO_MODULE) + +python_add_library(_core MODULE scdemon/py_se.cpp WITH_SOABI) +target_link_libraries(_core PRIVATE pybind11::headers) +target_link_libraries(_core PRIVATE Eigen3::Eigen) + +target_compile_definitions(_core PRIVATE VERSION_INFO=${PROJECT_VERSION}) + +# Include the C++ headers +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) +install(TARGETS _core DESTINATION ${SKBUILD_PROJECT_NAME}) diff --git a/README.org b/README.org index 9af412d..ee18c5f 100644 --- a/README.org +++ b/README.org @@ -34,6 +34,11 @@ BigCLAM/Leiden - .varp: PCA based ANN (bool) - .varp: filtered graph (CSR, data=tvalue) - .var / .varm: clustering / cluster loadings +**** Minimal conda environment +#+BEGIN_SRC bash +mamba create -n scdemonpy conda-forge::gxx_linux-64 conda-forge::gcc_linux-64 conda-forge::gfortran_linux-64 conda-forge::eigen conda-forge::gsl conda-forge::anndata conda-forge::tqdm conda-forge::pybind11 conda-forge::pip conda-forge::igraph conda-forge::umap-learn +mamba create -n scdemonr conda-forge::gxx_linux-64 conda-forge::gcc_linux-64 conda-forge::gfortran_linux-64 conda-forge::r-devtools conda-forge::r-rcppeigen conda-forge::r-rcppprogress conda-forge::gsl bioconda::bioconductor-rhdf5 conda-forge::r-igraph conda-forge::r-uwot conda-forge::r-irlba +#+END_SRC **** API ***** build_nn_graph 1. extract dimreduc, variables, covariates using params. Order obs/obsm based statistics if applicable. @@ -46,11 +51,21 @@ BigCLAM/Leiden *** DONE C++ demo code linked to python and R *** DONE HC0 SE in C++ **** DONE Eigen::MatrixBase type -*** TODO KNN interface in R/Python -**** Sparse matrix conversion: 0/1 indexing +*** TODO CircleCI and codecov +*** DONE Sparse matrix conversion: 0/1 indexing +*** TODO simplify setup +use data.table https://github.com/Rdatatable/data.table/blob/master/configure and nloptr https://github.com/astamm/nloptr/blob/master/configure as templates +- scikit-build + CMake for python +- configure.ac/configure/cleanup scripts for R *** TODO pkgdown website +- github action https://github.com/r-lib/actions/blob/v2/examples/pkgdown.yaml +*** TODO CI circleCI like bioconda? +*** TODO testing/codecov +*** TODO linting +- lintr action https://github.com/r-lib/actions/blob/v2/examples/lint.yaml +- python linting like anndata *** TODO sphinx/readthedocs -*** TODO threaded implementation +*** DONE threaded implementation **** OpenMP vs STL parallel *** TODO CMake build for R and python *** TODO vignettes in R and python @@ -62,3 +77,8 @@ BigCLAM/Leiden **** bootstrapped cluster SE *** TODO Newey-West in C++ : sort by sample depth to account for depth autocorrelation *** TODO Submit to bioconda (R, python versions) +*** TODO Add to bioconductor?, seurat-wrappers, scanpy.external.tl +*** TODO Single-cell Multi-omic: Use CCA or OPA; combine graphs +*** TODO metacell support instead of using PCA based +*** TODO support for WGCNA + diff --git a/cleanup b/cleanup new file mode 100755 index 0000000..b9cc889 --- /dev/null +++ b/cleanup @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +rm -f src/Makevars diff --git a/configure.ac b/configure.ac index e02b240..35a00c0 100644 --- a/configure.ac +++ b/configure.ac @@ -1,47 +1,25 @@ -AC_INIT([scdemon], [0.0.2]) +AC_INIT([scdemon], [0.0.3]) AC_MSG_NOTICE([Creating VERSION file]) echo m4_defn([AC_PACKAGE_VERSION]) > VERSION -AC_CANONICAL_BUILD -AC_CANONICAL_HOST -AC_CANONICAL_TARGET +: ${R_HOME=$(R RHOME)} +if test -z "${R_HOME}"; then + AC_MSG_ERROR([Could not determine R_HOME.]) +fi +CXX=`"${R_HOME}/bin/R" CMD config CXX` +if test -z "${CXX}"; then + AC_MSG_ERROR([No C++ compiler available]) +fi +CXXFLAGS=`"${R_HOME}/bin/R" CMD config CXXFLAGS` +CPPFLAGS=`"${R_HOME}/bin/R" CMD config CPPFLAGS` AC_LANG([C++]) +AC_REQUIRE_CPP AC_PROG_CXX -PKG_PROG_PKG_CONFIG -PKG_CHECK_MODULES([EIGEN], [eigen3 >= 3.3.9], [], [AC_MSG_WARN([Eigen flags may not be set for python])]) -PKG_CHECK_MODULES([HDF5], [hdf5], [], [AC_MSG_WARN([HDF5 may not be set for testing])]) -PKG_CHECK_MODULES([GSL], [gsl], [], [AC_MSG_ERROR([GSL is required, please install])]) AC_OPENMP - -AC_CHECK_PROG([R_FOUND], [R], [yes], [no]) -if test "x$R_FOUND" = xno; then - AC_MSG_WARN([R is not installed.]) -fi -AC_PROG_MAKE_SET - -AM_INIT_AUTOMAKE([foreign subdir-objects]) -AM_MAINTAINER_MODE - - -AC_ARG_ENABLE([cxxtest], - [AS_HELP_STRING([--enable-cxxtest], [Enable the compilation of c++ binary])], - [cxxtest=$enableval], - [cxxtest=no]) - -AM_CONDITIONAL([ENABLE_CXX_TEST], [test "x$cxxtest" = "xyes"]) - -AC_SUBST([PKG_CXXFLAGS], ["$CXXFLAGS $OPENMP_CXXFLAGS $GSL_CFLAGS"]) -AC_SUBST([PKG_LIBS], ["$LDFLAGS $OPENMP_CXXFLAGS $GSL_LIBS"]) -AC_SUBST([EIGEN_CXXFLAGS], ["$EIGEN_CFLAGS"]) -AC_SUBST([EIGEN_LIBS], ["$EIGEN_LIBS"]) -AC_SUBST([OPENMP_CXXFLAGS], ["$OPENMP_CXXFLAGS"]) -AC_SUBST([OPENMP_LIBS], ["$OPENMP_CXXFLAGS"]) -AC_SUBST([HDF5_CXXFLAGS], ["$HDF5_CXXFLAGS"]) -AC_SUBST([HDF5_LIBS], ["$HDF5_LIBS"]) -AC_SUBST([GSL_CXXFLAGS], ["$GSL_CFLAGS"]) -AC_SUBST([GSL_LIBS], ["$GSL_LIBS"]) -AC_CONFIG_FILES([src/Makevars Makefile DESCRIPTION docs/sphinx/conf.py]) +AC_SUBST([PKG_CXXFLAGS], ["$CXXFLAGS $OPENMP_CXXFLAGS"]) +AC_SUBST([PKG_LIBS], ["$LDFLAGS $OPENMP_CXXFLAGS"]) +AC_CONFIG_FILES([src/Makevars DESCRIPTION]) AC_OUTPUT diff --git a/docs/sphinx/conf.py.in b/docs/sphinx/conf.py similarity index 94% rename from docs/sphinx/conf.py.in rename to docs/sphinx/conf.py index 5070e18..fa1e0b4 100644 --- a/docs/sphinx/conf.py.in +++ b/docs/sphinx/conf.py @@ -5,11 +5,11 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information - +from scdemon import __version__ project = 'scdemon' copyright = '2024, Benjamin James' author = 'Benjamin James' -release = '@VERSION@' +release = __version__ # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9daf3e9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[build-system] +requires = ["scikit-build-core>=0.3.3", "pybind11"] +build-backend = "scikit_build_core.build" + +[project] +name = "scdemon" +version = "0.0.3" +description = "Single cell decomposition into networks" +authors = [{name = "Benjamin James", email = "benjames@mit.edu"}, + {name = "Carles Boix", email = "cboix@mit.edu"}] +license = {file = "LICENSE"} +requires-python = ">=3.7" +dependencies = ["numpy", "pandas", "scipy", "tqdm"] + +[project.optional-dependencies] +test = ["pytest"] + +[tool.scikit-build] +wheel.expand-macos-universal-tags = true diff --git a/scdemon/__init__.py b/scdemon/__init__.py index 5d547ee..47678f9 100644 --- a/scdemon/__init__.py +++ b/scdemon/__init__.py @@ -1,6 +1,6 @@ -import scdemon_ext +#from _core import * import sys - +from ._core import * from tqdm.auto import tqdm class ProgressManager: def __init__(self): diff --git a/scdemon/py_se.cpp b/scdemon/py_se.cpp index 8fa54c6..d939e24 100644 --- a/scdemon/py_se.cpp +++ b/scdemon/py_se.cpp @@ -28,7 +28,7 @@ Eigen::MatrixXd py_ols_beta(const py::EigenDRef &X, return ols_beta(X, Y); } -PYBIND11_MODULE(scdemon_ext, m) { +PYBIND11_MODULE(_core, m) { m.def("ols_beta", &py_ols_beta); m.def("robust_se_X", &py_robust_se_X); m.def("robust_se", &py_robust_se); diff --git a/src/Makevars.in b/src/Makevars.in index ab3565f..84888a1 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -1,8 +1,2 @@ PKG_CXXFLAGS = @PKG_CXXFLAGS@ PKG_LIBS = @PKG_LIBS@ -OPENMP_CXXFLAGS = @OPENMP_CXXFLAGS@ -OPENMP_LIBS = @OPENMP_LIBS@ -EIGEN_CXXFLAGS = @EIGEN_CXXFLAGS@ -EIGEN_LIBS = @EIGEN_LIBS@ -GSL_CXXFLAGS = @GSL_CXXFLAGS@ -GSL_LIBS = @GSL_LIBS@ diff --git a/src/Makevars.win b/src/Makevars.win new file mode 100644 index 0000000..139b1d1 --- /dev/null +++ b/src/Makevars.win @@ -0,0 +1,2 @@ +PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) +PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS)