Skip to content

Commit 8137458

Browse files
benjefferyjeromekelleher
authored andcommitted
Add cython example
1 parent accc1de commit 8137458

6 files changed

Lines changed: 199 additions & 0 deletions

File tree

.circleci/config.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ commands:
121121
make allchecks
122122
python -m pytest -n2
123123
124+
- run:
125+
name: Build cython example LWT interface code and run
126+
command: |
127+
cd python/lwt_interface/cython_example
128+
make
129+
124130
- run:
125131
name: Generate coverage
126132
command: |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
all: compile run
2+
3+
compile:
4+
pip install -e . --use-pep517
5+
6+
run:
7+
PYTHONPATH=../.. python -c "import example; example.main()"
8+
9+
clean:
10+
rm -rf build/
11+
rm -rf tskit_cython_example.egg-info/
12+
rm -f example.c
13+
rm -f *.so
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2019-2020 Tskit Developers
5+
* Copyright (c) 2015-2018 University of Oxford
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in all
15+
* copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
* SOFTWARE.
24+
*/
25+
// Turn off clang-formatting for this file as turning off formatting
26+
// for specific bits will make it more confusing.
27+
// clang-format off
28+
29+
#define PY_SSIZE_T_CLEAN
30+
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
31+
32+
#include <Python.h>
33+
#include <structmember.h>
34+
#include <numpy/arrayobject.h>
35+
36+
#include "kastore.h"
37+
#include "tskit.h"
38+
39+
#include "tskit_lwt_interface.h"
40+
41+
static PyMethodDef lwt_methods[] = {
42+
{ NULL, NULL, 0, NULL } /* sentinel */
43+
};
44+
45+
static struct PyModuleDef lwt_module = {
46+
.m_base = PyModuleDef_HEAD_INIT,
47+
.m_name = "_lwt",
48+
.m_doc = "tskit LightweightTableCollection",
49+
.m_size = -1,
50+
.m_methods = lwt_methods };
51+
52+
PyMODINIT_FUNC
53+
PyInit__lwtc(void)
54+
{
55+
PyObject *module = PyModule_Create(&lwt_module);
56+
if (module == NULL) {
57+
return NULL;
58+
}
59+
import_array();
60+
if (register_lwt_class(module) != 0) {
61+
return NULL;
62+
}
63+
return module;
64+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from libc.stdint cimport uint32_t
2+
import _lwtc
3+
import tskit
4+
5+
cdef extern from "tskit.h" nogil:
6+
ctypedef uint32_t tsk_flags_t
7+
ctypedef struct tsk_table_collection_t:
8+
pass
9+
ctypedef struct tsk_treeseq_t:
10+
pass
11+
int tsk_treeseq_init(tsk_treeseq_t *self, const tsk_table_collection_t *tables, tsk_flags_t options)
12+
int tsk_treeseq_free(tsk_treeseq_t *self)
13+
int tsk_table_collection_build_index(tsk_table_collection_t *self, tsk_flags_t options)
14+
ctypedef struct tsk_tree_t:
15+
pass
16+
int tsk_tree_init(tsk_tree_t *self, const tsk_treeseq_t *ts, tsk_flags_t options)
17+
int tsk_tree_first(tsk_tree_t *self)
18+
int tsk_tree_next(tsk_tree_t *self)
19+
int tsk_tree_last(tsk_tree_t *self)
20+
int tsk_tree_prev(tsk_tree_t *self)
21+
int tsk_tree_get_num_roots(tsk_tree_t *self)
22+
int tsk_tree_free(tsk_tree_t *self)
23+
const char *tsk_strerror(int err)
24+
25+
cdef extern:
26+
ctypedef class _lwtc.LightweightTableCollection [object LightweightTableCollection]:
27+
cdef tsk_table_collection_t *tables
28+
29+
def check_tsk_error(val):
30+
if val < 0:
31+
raise RuntimeError(tsk_strerror(val))
32+
33+
def iterate_trees(pyts: tskit.TreeSequence):
34+
lwtc = LightweightTableCollection()
35+
lwtc.fromdict(pyts.dump_tables().asdict())
36+
cdef tsk_treeseq_t ts
37+
err = tsk_treeseq_init(&ts, lwtc.tables, 0)
38+
check_tsk_error(err)
39+
cdef tsk_tree_t tree
40+
ret = tsk_tree_init(&tree, &ts, 0)
41+
check_tsk_error(ret)
42+
43+
print("Iterate forwards")
44+
cdef int tree_iter = tsk_tree_first(&tree)
45+
while tree_iter == 1:
46+
print("\ttree has %d roots" % (tsk_tree_get_num_roots(&tree)))
47+
tree_iter = tsk_tree_next(&tree)
48+
check_tsk_error(tree_iter)
49+
50+
print("Iterate backwards")
51+
tree_iter = tsk_tree_last(&tree)
52+
while tree_iter == 1:
53+
print("\ttree has %d roots" % (tsk_tree_get_num_roots(&tree)))
54+
tree_iter = tsk_tree_prev(&tree)
55+
check_tsk_error(tree_iter)
56+
57+
tsk_tree_free(&tree)
58+
tsk_treeseq_free(&ts)
59+
60+
def main():
61+
import msprime as msp # (msprime could be compiled against a different version of tskit)
62+
ts = msp.simulate(sample_size=5, length=100, recombination_rate=.01)
63+
iterate_trees(ts)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[build-system]
2+
requires = ["setuptools>=64", "wheel", "Cython", "numpy"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "tskit_cython_example"
7+
version = "0.0.1"
8+
description = "Cython example for tskit"
9+
authors = [{name = "tskit developers"}]
10+
dependencies = ["numpy", "Cython"]
11+
12+
[tool.setuptools]
13+
packages = []
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import glob
2+
import os
3+
4+
import numpy as np
5+
from Cython.Build import cythonize
6+
from setuptools import setup
7+
from setuptools.extension import Extension
8+
9+
TSKIT_BASE = os.path.join(os.path.dirname(__file__), "..", "..", "..")
10+
TSKIT_C_PATH = os.path.join(TSKIT_BASE, "c")
11+
TSKIT_PY_PATH = os.path.join(TSKIT_BASE, "python/lwt_interface")
12+
KASTORE_PATH = os.path.join(TSKIT_BASE, "c", "subprojects", "kastore")
13+
include_dirs = [TSKIT_C_PATH, TSKIT_PY_PATH, KASTORE_PATH, np.get_include()]
14+
15+
tskit_sourcefiles = list(glob.glob(os.path.join(TSKIT_C_PATH, "tskit", "*.c"))) + [
16+
os.path.join(KASTORE_PATH, "kastore.c")
17+
]
18+
19+
extensions = [
20+
Extension(
21+
"_lwtc",
22+
["_lwtc.c"] + tskit_sourcefiles,
23+
language="c",
24+
include_dirs=include_dirs,
25+
),
26+
Extension(
27+
"example",
28+
["example.pyx"] + tskit_sourcefiles,
29+
language="c",
30+
include_dirs=include_dirs,
31+
),
32+
]
33+
34+
extensions = cythonize(extensions, language_level=3)
35+
36+
setup(
37+
name="tskit_cython_example",
38+
version="0.0.1",
39+
ext_modules=extensions,
40+
)

0 commit comments

Comments
 (0)