sstat 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/ext/sstat/Makefile +238 -0
- data/ext/sstat/lib/distribution.h +274 -0
- data/ext/sstat/lib/global_utility.h +17 -0
- data/ext/sstat/lib/survival.h +6 -0
- data/ext/sstat/lib/survival_def.h +15 -0
- data/ext/sstat/lib/survival_func.h +190 -0
- data/ext/sstat/lib/survival_utility.h +292 -0
- data/ext/sstat/lib/type_def.h +35 -0
- data/ext/sstat/sstat.c +107 -0
- data/ext/sstat/sstat.h +28 -0
- data/lib/simple_statistics.rb +5 -0
- data/lib/simple_statistics/version.rb +3 -0
- data/lib/sstat.so +0 -0
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: beee6865b0bc618d70c67be9c3f000089416b24e
|
|
4
|
+
data.tar.gz: 21761e26f6a5af3402d3adc1d12e4a2af33897ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d994e68d96cdebf07f8a2da62c14329eb0c65f29cedcc3c5f71563f6af7de1b1f480e608fa1a575d7129122dbf7da5d5a42976aac4ff9f27ef111c741dbcb0f2
|
|
7
|
+
data.tar.gz: bbe5ab1b30dbaeee27995d678b2dcf64e8d5a0b456e263d12d8685464a95da119d4145deb431444a49c278b6846ad375e87e9c877ebdb63cb3a7d0b90d11bce3
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "simple_statistics"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/ext/sstat/Makefile
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
|
|
2
|
+
SHELL = /bin/sh
|
|
3
|
+
|
|
4
|
+
# V=0 quiet, V=1 verbose. other values don't work.
|
|
5
|
+
V = 0
|
|
6
|
+
Q1 = $(V:1=)
|
|
7
|
+
Q = $(Q1:0=@)
|
|
8
|
+
ECHO1 = $(V:1=@:)
|
|
9
|
+
ECHO = $(ECHO1:0=@echo)
|
|
10
|
+
|
|
11
|
+
#### Start of system configuration section. ####
|
|
12
|
+
|
|
13
|
+
srcdir = .
|
|
14
|
+
topdir = /home/chizhang/.rvm/rubies/ruby-2.1.1/include/ruby-2.1.0
|
|
15
|
+
hdrdir = $(topdir)
|
|
16
|
+
arch_hdrdir = /home/chizhang/.rvm/rubies/ruby-2.1.1/include/ruby-2.1.0/x86_64-linux
|
|
17
|
+
PATH_SEPARATOR = :
|
|
18
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
|
19
|
+
prefix = $(DESTDIR)/home/chizhang/.rvm/rubies/ruby-2.1.1
|
|
20
|
+
rubysitearchprefix = $(rubylibprefix)/$(sitearch)
|
|
21
|
+
rubyarchprefix = $(rubylibprefix)/$(arch)
|
|
22
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
|
23
|
+
exec_prefix = $(prefix)
|
|
24
|
+
vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
|
|
25
|
+
sitearchhdrdir = $(sitehdrdir)/$(sitearch)
|
|
26
|
+
rubyarchhdrdir = $(rubyhdrdir)/$(arch)
|
|
27
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
|
28
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
|
29
|
+
rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
|
|
30
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
|
31
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
|
32
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
|
33
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
|
34
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
|
35
|
+
sitedir = $(rubylibprefix)/site_ruby
|
|
36
|
+
rubyarchdir = $(rubylibdir)/$(arch)
|
|
37
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
|
38
|
+
sitearchincludedir = $(includedir)/$(sitearch)
|
|
39
|
+
archincludedir = $(includedir)/$(arch)
|
|
40
|
+
sitearchlibdir = $(libdir)/$(sitearch)
|
|
41
|
+
archlibdir = $(libdir)/$(arch)
|
|
42
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
|
43
|
+
mandir = $(datarootdir)/man
|
|
44
|
+
localedir = $(datarootdir)/locale
|
|
45
|
+
libdir = $(exec_prefix)/lib
|
|
46
|
+
psdir = $(docdir)
|
|
47
|
+
pdfdir = $(docdir)
|
|
48
|
+
dvidir = $(docdir)
|
|
49
|
+
htmldir = $(docdir)
|
|
50
|
+
infodir = $(datarootdir)/info
|
|
51
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
|
52
|
+
oldincludedir = $(DESTDIR)/usr/include
|
|
53
|
+
includedir = $(prefix)/include
|
|
54
|
+
localstatedir = $(prefix)/var
|
|
55
|
+
sharedstatedir = $(prefix)/com
|
|
56
|
+
sysconfdir = $(prefix)/etc
|
|
57
|
+
datadir = $(datarootdir)
|
|
58
|
+
datarootdir = $(prefix)/share
|
|
59
|
+
libexecdir = $(exec_prefix)/libexec
|
|
60
|
+
sbindir = $(exec_prefix)/sbin
|
|
61
|
+
bindir = $(exec_prefix)/bin
|
|
62
|
+
archdir = $(rubyarchdir)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
CC = gcc
|
|
66
|
+
CXX = g++
|
|
67
|
+
LIBRUBY = $(LIBRUBY_SO)
|
|
68
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
|
69
|
+
LIBRUBYARG_SHARED = -Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)
|
|
70
|
+
LIBRUBYARG_STATIC = -Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)-static
|
|
71
|
+
empty =
|
|
72
|
+
OUTFLAG = -o $(empty)
|
|
73
|
+
COUTFLAG = -o $(empty)
|
|
74
|
+
|
|
75
|
+
RUBY_EXTCONF_H =
|
|
76
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
|
77
|
+
optflags = -O3 -fno-fast-math
|
|
78
|
+
debugflags = -ggdb3
|
|
79
|
+
warnflags = -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration
|
|
80
|
+
CCDLFLAGS = -fPIC
|
|
81
|
+
CFLAGS = $(CCDLFLAGS) $(cflags) -fPIC -std=gnu99 -Wno-declaration-after-statement $(ARCH_FLAG)
|
|
82
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
|
83
|
+
DEFS =
|
|
84
|
+
CPPFLAGS = $(DEFS) $(cppflags)
|
|
85
|
+
CXXFLAGS = $(CCDLFLAGS) $(cxxflags) $(ARCH_FLAG)
|
|
86
|
+
ldflags = -L. -fstack-protector -rdynamic -Wl,-export-dynamic
|
|
87
|
+
dldflags =
|
|
88
|
+
ARCH_FLAG =
|
|
89
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
|
|
90
|
+
LDSHARED = $(CC) -shared
|
|
91
|
+
LDSHAREDXX = $(CXX) -shared
|
|
92
|
+
AR = ar
|
|
93
|
+
EXEEXT =
|
|
94
|
+
|
|
95
|
+
RUBY_INSTALL_NAME = ruby
|
|
96
|
+
RUBY_SO_NAME = ruby
|
|
97
|
+
RUBYW_INSTALL_NAME =
|
|
98
|
+
RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
|
|
99
|
+
RUBYW_BASE_NAME = rubyw
|
|
100
|
+
RUBY_BASE_NAME = ruby
|
|
101
|
+
|
|
102
|
+
arch = x86_64-linux
|
|
103
|
+
sitearch = $(arch)
|
|
104
|
+
ruby_version = 2.1.0
|
|
105
|
+
ruby = $(bindir)/ruby
|
|
106
|
+
RUBY = $(ruby)
|
|
107
|
+
ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
|
|
108
|
+
|
|
109
|
+
RM = rm -f
|
|
110
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
|
111
|
+
RMDIRS = rmdir --ignore-fail-on-non-empty -p
|
|
112
|
+
MAKEDIRS = /bin/mkdir -p
|
|
113
|
+
INSTALL = /usr/bin/install -c
|
|
114
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
|
115
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
|
116
|
+
COPY = cp
|
|
117
|
+
TOUCH = exit >
|
|
118
|
+
|
|
119
|
+
#### End of system configuration section. ####
|
|
120
|
+
|
|
121
|
+
preload =
|
|
122
|
+
|
|
123
|
+
libpath = . $(libdir)
|
|
124
|
+
LIBPATH = -L. -L$(libdir) -Wl,-R$(libdir)
|
|
125
|
+
DEFFILE =
|
|
126
|
+
|
|
127
|
+
CLEANFILES = mkmf.log
|
|
128
|
+
DISTCLEANFILES =
|
|
129
|
+
DISTCLEANDIRS =
|
|
130
|
+
|
|
131
|
+
extout =
|
|
132
|
+
extout_prefix =
|
|
133
|
+
target_prefix =
|
|
134
|
+
LOCAL_LIBS =
|
|
135
|
+
LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lcrypt -lm -lc
|
|
136
|
+
ORIG_SRCS = sstat.c
|
|
137
|
+
SRCS = $(ORIG_SRCS)
|
|
138
|
+
OBJS = sstat.o
|
|
139
|
+
HDRS = $(srcdir)/sstat.h
|
|
140
|
+
TARGET = sstat
|
|
141
|
+
TARGET_NAME = sstat
|
|
142
|
+
TARGET_ENTRY = Init_$(TARGET_NAME)
|
|
143
|
+
DLLIB = $(TARGET).so
|
|
144
|
+
EXTSTATIC =
|
|
145
|
+
STATIC_LIB =
|
|
146
|
+
|
|
147
|
+
TIMESTAMP_DIR = .
|
|
148
|
+
BINDIR = $(bindir)
|
|
149
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
|
150
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
|
151
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
|
152
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
|
153
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
|
154
|
+
|
|
155
|
+
TARGET_SO = $(DLLIB)
|
|
156
|
+
CLEANLIBS = $(TARGET).so
|
|
157
|
+
CLEANOBJS = *.o *.bak
|
|
158
|
+
|
|
159
|
+
all: $(DLLIB)
|
|
160
|
+
static: $(STATIC_LIB)
|
|
161
|
+
.PHONY: all install static install-so install-rb
|
|
162
|
+
.PHONY: clean clean-so clean-static clean-rb
|
|
163
|
+
|
|
164
|
+
clean-static::
|
|
165
|
+
clean-rb-default::
|
|
166
|
+
clean-rb::
|
|
167
|
+
clean-so::
|
|
168
|
+
clean: clean-so clean-static clean-rb-default clean-rb
|
|
169
|
+
-$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
|
|
170
|
+
|
|
171
|
+
distclean-rb-default::
|
|
172
|
+
distclean-rb::
|
|
173
|
+
distclean-so::
|
|
174
|
+
distclean-static::
|
|
175
|
+
distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
|
|
176
|
+
-$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
|
177
|
+
-$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
|
178
|
+
-$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
|
|
179
|
+
|
|
180
|
+
realclean: distclean
|
|
181
|
+
install: install-so install-rb
|
|
182
|
+
|
|
183
|
+
install-so: $(DLLIB) $(TIMESTAMP_DIR)/.RUBYARCHDIR.time
|
|
184
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
|
185
|
+
clean-static::
|
|
186
|
+
-$(Q)$(RM) $(STATIC_LIB)
|
|
187
|
+
install-rb: pre-install-rb install-rb-default
|
|
188
|
+
install-rb-default: pre-install-rb-default
|
|
189
|
+
pre-install-rb: Makefile
|
|
190
|
+
pre-install-rb-default: Makefile
|
|
191
|
+
pre-install-rb-default:
|
|
192
|
+
$(ECHO) installing default sstat libraries
|
|
193
|
+
$(TIMESTAMP_DIR)/.RUBYARCHDIR.time:
|
|
194
|
+
$(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
|
|
195
|
+
$(Q) $(TOUCH) $@
|
|
196
|
+
|
|
197
|
+
site-install: site-install-so site-install-rb
|
|
198
|
+
site-install-so: install-so
|
|
199
|
+
site-install-rb: install-rb
|
|
200
|
+
|
|
201
|
+
.SUFFIXES: .c .m .cc .mm .cxx .cpp .C .o
|
|
202
|
+
|
|
203
|
+
.cc.o:
|
|
204
|
+
$(ECHO) compiling $(<)
|
|
205
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
|
206
|
+
|
|
207
|
+
.mm.o:
|
|
208
|
+
$(ECHO) compiling $(<)
|
|
209
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
|
210
|
+
|
|
211
|
+
.cxx.o:
|
|
212
|
+
$(ECHO) compiling $(<)
|
|
213
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
|
214
|
+
|
|
215
|
+
.cpp.o:
|
|
216
|
+
$(ECHO) compiling $(<)
|
|
217
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
|
218
|
+
|
|
219
|
+
.C.o:
|
|
220
|
+
$(ECHO) compiling $(<)
|
|
221
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
|
222
|
+
|
|
223
|
+
.c.o:
|
|
224
|
+
$(ECHO) compiling $(<)
|
|
225
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
|
226
|
+
|
|
227
|
+
.m.o:
|
|
228
|
+
$(ECHO) compiling $(<)
|
|
229
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
|
230
|
+
|
|
231
|
+
$(DLLIB): $(OBJS) Makefile
|
|
232
|
+
$(ECHO) linking shared-object $(DLLIB)
|
|
233
|
+
-$(Q)$(RM) $(@)
|
|
234
|
+
$(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
$(OBJS): $(HDRS) $(ruby_headers)
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
#ifndef _SSTAT_DISTRIBUTION_UTILITY_H_
|
|
2
|
+
#define _SSTAT_DISTRIBUTION_UTILITY_H_
|
|
3
|
+
#include "type_def.h"
|
|
4
|
+
static double
|
|
5
|
+
get_del (double x, double rational)
|
|
6
|
+
{
|
|
7
|
+
double xsq = 0.0;
|
|
8
|
+
double del = 0.0;
|
|
9
|
+
double result = 0.0;
|
|
10
|
+
|
|
11
|
+
xsq = floor (x * GAUSS_SCALE) / GAUSS_SCALE;
|
|
12
|
+
del = (x - xsq) * (x + xsq);
|
|
13
|
+
del *= 0.5;
|
|
14
|
+
|
|
15
|
+
result = exp (-0.5 * xsq * xsq) * exp (-1.0 * del) * rational;
|
|
16
|
+
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* Normal cdf for fabs(x) < 0.66291
|
|
22
|
+
*/
|
|
23
|
+
static double
|
|
24
|
+
gauss_small (const double x)
|
|
25
|
+
{
|
|
26
|
+
unsigned int i;
|
|
27
|
+
double result = 0.0;
|
|
28
|
+
double xsq;
|
|
29
|
+
double xnum;
|
|
30
|
+
double xden;
|
|
31
|
+
|
|
32
|
+
const double a[5] = {
|
|
33
|
+
2.2352520354606839287,
|
|
34
|
+
161.02823106855587881,
|
|
35
|
+
1067.6894854603709582,
|
|
36
|
+
18154.981253343561249,
|
|
37
|
+
0.065682337918207449113
|
|
38
|
+
};
|
|
39
|
+
const double b[4] = {
|
|
40
|
+
47.20258190468824187,
|
|
41
|
+
976.09855173777669322,
|
|
42
|
+
10260.932208618978205,
|
|
43
|
+
45507.789335026729956
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
xsq = x * x;
|
|
47
|
+
xnum = a[4] * xsq;
|
|
48
|
+
xden = xsq;
|
|
49
|
+
|
|
50
|
+
for (i = 0; i < 3; i++)
|
|
51
|
+
{
|
|
52
|
+
xnum = (xnum + a[i]) * xsq;
|
|
53
|
+
xden = (xden + b[i]) * xsq;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
result = x * (xnum + a[3]) / (xden + b[3]);
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
* Normal cdf for 0.66291 < fabs(x) < sqrt(32).
|
|
63
|
+
*/
|
|
64
|
+
static double
|
|
65
|
+
gauss_medium (const double x)
|
|
66
|
+
{
|
|
67
|
+
unsigned int i;
|
|
68
|
+
double temp = 0.0;
|
|
69
|
+
double result = 0.0;
|
|
70
|
+
double xnum;
|
|
71
|
+
double xden;
|
|
72
|
+
double absx;
|
|
73
|
+
|
|
74
|
+
const double c[9] = {
|
|
75
|
+
0.39894151208813466764,
|
|
76
|
+
8.8831497943883759412,
|
|
77
|
+
93.506656132177855979,
|
|
78
|
+
597.27027639480026226,
|
|
79
|
+
2494.5375852903726711,
|
|
80
|
+
6848.1904505362823326,
|
|
81
|
+
11602.651437647350124,
|
|
82
|
+
9842.7148383839780218,
|
|
83
|
+
1.0765576773720192317e-8
|
|
84
|
+
};
|
|
85
|
+
const double d[8] = {
|
|
86
|
+
22.266688044328115691,
|
|
87
|
+
235.38790178262499861,
|
|
88
|
+
1519.377599407554805,
|
|
89
|
+
6485.558298266760755,
|
|
90
|
+
18615.571640885098091,
|
|
91
|
+
34900.952721145977266,
|
|
92
|
+
38912.003286093271411,
|
|
93
|
+
19685.429676859990727
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
absx = fabs (x);
|
|
97
|
+
|
|
98
|
+
xnum = c[8] * absx;
|
|
99
|
+
xden = absx;
|
|
100
|
+
|
|
101
|
+
for (i = 0; i < 7; i++)
|
|
102
|
+
{
|
|
103
|
+
xnum = (xnum + c[i]) * absx;
|
|
104
|
+
xden = (xden + d[i]) * absx;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
temp = (xnum + c[7]) / (xden + d[7]);
|
|
108
|
+
|
|
109
|
+
result = get_del (x, temp);
|
|
110
|
+
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* Normal cdf for
|
|
116
|
+
* {sqrt(32) < x < GAUSS_XUPPER} union { GAUSS_XLOWER < x < -sqrt(32) }.
|
|
117
|
+
*/
|
|
118
|
+
static double
|
|
119
|
+
gauss_large (const double x)
|
|
120
|
+
{
|
|
121
|
+
int i;
|
|
122
|
+
double result;
|
|
123
|
+
double xsq;
|
|
124
|
+
double temp;
|
|
125
|
+
double xnum;
|
|
126
|
+
double xden;
|
|
127
|
+
double absx;
|
|
128
|
+
|
|
129
|
+
const double p[6] = {
|
|
130
|
+
0.21589853405795699,
|
|
131
|
+
0.1274011611602473639,
|
|
132
|
+
0.022235277870649807,
|
|
133
|
+
0.001421619193227893466,
|
|
134
|
+
2.9112874951168792e-5,
|
|
135
|
+
0.02307344176494017303
|
|
136
|
+
};
|
|
137
|
+
const double q[5] = {
|
|
138
|
+
1.28426009614491121,
|
|
139
|
+
0.468238212480865118,
|
|
140
|
+
0.0659881378689285515,
|
|
141
|
+
0.00378239633202758244,
|
|
142
|
+
7.29751555083966205e-5
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
absx = fabs (x);
|
|
146
|
+
xsq = 1.0 / (x * x);
|
|
147
|
+
xnum = p[5] * xsq;
|
|
148
|
+
xden = xsq;
|
|
149
|
+
|
|
150
|
+
for (i = 0; i < 4; i++)
|
|
151
|
+
{
|
|
152
|
+
xnum = (xnum + p[i]) * xsq;
|
|
153
|
+
xden = (xden + q[i]) * xsq;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
temp = xsq * (xnum + p[4]) / (xden + q[4]);
|
|
157
|
+
temp = (M_1_SQRT2PI - temp) / absx;
|
|
158
|
+
|
|
159
|
+
result = get_del (x, temp);
|
|
160
|
+
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
double
|
|
165
|
+
gsl_cdf_ugaussian_P (const double x)
|
|
166
|
+
{
|
|
167
|
+
double result;
|
|
168
|
+
double absx = fabs (x);
|
|
169
|
+
|
|
170
|
+
if (absx < GAUSS_EPSILON)
|
|
171
|
+
{
|
|
172
|
+
result = 0.5;
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
else if (absx < 0.66291)
|
|
176
|
+
{
|
|
177
|
+
result = 0.5 + gauss_small (x);
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
else if (absx < SQRT32)
|
|
181
|
+
{
|
|
182
|
+
result = gauss_medium (x);
|
|
183
|
+
|
|
184
|
+
if (x > 0.0)
|
|
185
|
+
{
|
|
186
|
+
result = 1.0 - result;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
else if (x > GAUSS_XUPPER)
|
|
192
|
+
{
|
|
193
|
+
result = 1.0;
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
else if (x < GAUSS_XLOWER)
|
|
197
|
+
{
|
|
198
|
+
result = 0.0;
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
else
|
|
202
|
+
{
|
|
203
|
+
result = gauss_large (x);
|
|
204
|
+
|
|
205
|
+
if (x > 0.0)
|
|
206
|
+
{
|
|
207
|
+
result = 1.0 - result;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
double
|
|
215
|
+
cdf_ugaussian_Q (const double x)
|
|
216
|
+
{
|
|
217
|
+
double result;
|
|
218
|
+
double absx = fabs (x);
|
|
219
|
+
|
|
220
|
+
if (absx < GAUSS_EPSILON)
|
|
221
|
+
{
|
|
222
|
+
result = 0.5;
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
else if (absx < 0.66291)
|
|
226
|
+
{
|
|
227
|
+
result = gauss_small (x);
|
|
228
|
+
|
|
229
|
+
if (x < 0.0)
|
|
230
|
+
{
|
|
231
|
+
result = fabs (result) + 0.5;
|
|
232
|
+
}
|
|
233
|
+
else
|
|
234
|
+
{
|
|
235
|
+
result = 0.5 - result;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
else if (absx < SQRT32)
|
|
241
|
+
{
|
|
242
|
+
result = gauss_medium (x);
|
|
243
|
+
|
|
244
|
+
if (x < 0.0)
|
|
245
|
+
{
|
|
246
|
+
result = 1.0 - result;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
else if (x > -(GAUSS_XLOWER))
|
|
252
|
+
{
|
|
253
|
+
result = 0.0;
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
else if (x < -(GAUSS_XUPPER))
|
|
257
|
+
{
|
|
258
|
+
result = 1.0;
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
else
|
|
262
|
+
{
|
|
263
|
+
result = gauss_large (x);
|
|
264
|
+
|
|
265
|
+
if (x < 0.0)
|
|
266
|
+
{
|
|
267
|
+
result = 1.0 - result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
#endif
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#ifndef _SSTAT_GLOBAL_UTILITY_H_
|
|
2
|
+
#define _SSTAT_GLOBAL_UTILITY_H_
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
#include "type_def.h"
|
|
6
|
+
|
|
7
|
+
int compare_double (const void * a, const void * b)
|
|
8
|
+
{
|
|
9
|
+
return *((double*)a) > *((double*)b)? 1 : 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
int point_compare_x (const void * a, const void * b)
|
|
13
|
+
{
|
|
14
|
+
return ((struct point*)a)->x - ((struct point*)b)->x;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#endif
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#ifndef _SURVIVAL_STAT_FUNC_H_
|
|
2
|
+
#define _SURVIVAL_STAT_FUNC_H_
|
|
3
|
+
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include "survival_def.h"
|
|
7
|
+
#include "survival_utility.h"
|
|
8
|
+
|
|
9
|
+
double precentile(double* array, int size, double target_percentile)
|
|
10
|
+
{
|
|
11
|
+
double percentage_each = 1.0 / size;
|
|
12
|
+
int i;
|
|
13
|
+
int count = 0;
|
|
14
|
+
|
|
15
|
+
for (i = 1; i <= size; i++)
|
|
16
|
+
{
|
|
17
|
+
if ( i * percentage_each < target_percentile )
|
|
18
|
+
{
|
|
19
|
+
count++;
|
|
20
|
+
} else
|
|
21
|
+
{
|
|
22
|
+
return array[count];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return array[size - 1];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
int index_less_equal(double* array, int size, double target)
|
|
30
|
+
{
|
|
31
|
+
int i;
|
|
32
|
+
|
|
33
|
+
for (i = 0; i < size; i++)
|
|
34
|
+
{
|
|
35
|
+
if (array[i] > target)
|
|
36
|
+
return i;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return i;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
double log_rank_test(double* time_1, int* censored_1, double* time_2, int* censored_2, int size_1, int size_2)
|
|
43
|
+
{
|
|
44
|
+
int i, time_pnt_size;
|
|
45
|
+
int index;
|
|
46
|
+
|
|
47
|
+
array merged_time_pnts = merge_two_array(time_1, size_1, time_2, size_2);
|
|
48
|
+
array merged_uniq_time_pnts = create_sorted_unique_array(merged_time_pnts.D_ptr, merged_time_pnts.size);
|
|
49
|
+
|
|
50
|
+
//The lengths of Group_N_1 and Group_N_2 are not expected to be same. Step 1. create unique time array which inlcude time points for both
|
|
51
|
+
Group_N Group_N_1 = group_N_given_range(time_1, censored_1, size_1, merged_uniq_time_pnts.D_ptr, merged_uniq_time_pnts.size);
|
|
52
|
+
Group_N Group_N_2 = group_N_given_range(time_2, censored_2, size_2, merged_uniq_time_pnts.D_ptr, merged_uniq_time_pnts.size);
|
|
53
|
+
|
|
54
|
+
double Z = 0;
|
|
55
|
+
double V_i_sum = 0;
|
|
56
|
+
|
|
57
|
+
Group_N combined_Group_N_1;
|
|
58
|
+
Group_N combined_Group_N_2;
|
|
59
|
+
|
|
60
|
+
combined_Group_N_1.uncensored = (int*) malloc(merged_uniq_time_pnts.size * sizeof(int));
|
|
61
|
+
combined_Group_N_1.censored = (int*) malloc(merged_uniq_time_pnts.size * sizeof(int));
|
|
62
|
+
|
|
63
|
+
combined_Group_N_2.uncensored = (int*) malloc(merged_uniq_time_pnts.size * sizeof(int));
|
|
64
|
+
combined_Group_N_2.censored = (int*) malloc(merged_uniq_time_pnts.size * sizeof(int));
|
|
65
|
+
|
|
66
|
+
//CAUTION: DO NOT SET TIME ARRAY HEERE, USE merged_uniq_time_pnts INSTEAD
|
|
67
|
+
combined_Group_N_1.time = NULL;
|
|
68
|
+
combined_Group_N_2.time = NULL;
|
|
69
|
+
|
|
70
|
+
time_pnt_size = merged_uniq_time_pnts.size;
|
|
71
|
+
|
|
72
|
+
int* N1_at_risk = (int*) malloc(time_pnt_size * sizeof(int));
|
|
73
|
+
int* N2_at_risk = (int*) malloc(time_pnt_size * sizeof(int));
|
|
74
|
+
int* N_i = (int*) malloc(time_pnt_size * sizeof(int));
|
|
75
|
+
int* O_i = (int*) malloc(time_pnt_size * sizeof(int));
|
|
76
|
+
|
|
77
|
+
double* E_i = (double*) malloc(time_pnt_size * sizeof(double));
|
|
78
|
+
double* V_i = (double*) malloc(time_pnt_size * sizeof(double));
|
|
79
|
+
|
|
80
|
+
//update at_risk for 1 and 2 based on combined_time_arr.
|
|
81
|
+
for (i = 0; i < time_pnt_size; ++i)
|
|
82
|
+
{
|
|
83
|
+
index = find_first_index_has(Group_N_1.time, Group_N_1.size, merged_uniq_time_pnts.D_ptr[i]);
|
|
84
|
+
if (index >= 0)
|
|
85
|
+
{
|
|
86
|
+
combined_Group_N_1.uncensored[i] = Group_N_1.uncensored[index];
|
|
87
|
+
combined_Group_N_1.censored[i] = Group_N_1.censored[index];
|
|
88
|
+
} else {
|
|
89
|
+
|
|
90
|
+
combined_Group_N_1.uncensored[i] = 0;
|
|
91
|
+
combined_Group_N_1.censored[i] = 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (i = 0; i < time_pnt_size; ++i)
|
|
96
|
+
{
|
|
97
|
+
index = find_first_index_has(Group_N_2.time, Group_N_2.size, merged_uniq_time_pnts.D_ptr[i]);
|
|
98
|
+
|
|
99
|
+
if (index >= 0)
|
|
100
|
+
{
|
|
101
|
+
combined_Group_N_2.uncensored[i] = Group_N_2.uncensored[index];
|
|
102
|
+
combined_Group_N_2.censored[i] = Group_N_2.censored[index];
|
|
103
|
+
} else {
|
|
104
|
+
combined_Group_N_2.uncensored[i] = 0;
|
|
105
|
+
combined_Group_N_2.censored[i] = 0;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
N1_at_risk[0] = size_1 - combined_Group_N_1.censored[0];
|
|
110
|
+
N2_at_risk[0] = size_2 - combined_Group_N_2.censored[0];
|
|
111
|
+
|
|
112
|
+
for (i = 1; i < time_pnt_size; ++i)
|
|
113
|
+
{
|
|
114
|
+
N1_at_risk[i] = N1_at_risk[i - 1] - combined_Group_N_1.uncensored[i - 1] - combined_Group_N_1.censored[i];
|
|
115
|
+
N2_at_risk[i] = N2_at_risk[i - 1] - combined_Group_N_2.uncensored[i - 1] - combined_Group_N_2.censored[i];
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (i = 0; i < time_pnt_size; ++i)
|
|
120
|
+
{
|
|
121
|
+
N_i[i] = N1_at_risk[i] + N2_at_risk[i];
|
|
122
|
+
O_i[i] = (combined_Group_N_1.uncensored[i] + combined_Group_N_2.uncensored[i]);
|
|
123
|
+
E_i[i] = 1.0 * N1_at_risk[i] * O_i[i] / N_i[i];
|
|
124
|
+
|
|
125
|
+
if (N_i[i] > 1)
|
|
126
|
+
{
|
|
127
|
+
V_i[i] = 1.0 * O_i[i]
|
|
128
|
+
* (1.0 * N1_at_risk[i] / N_i[i])
|
|
129
|
+
* (1 - 1.0 * N1_at_risk[i] / N_i[i])
|
|
130
|
+
* (N_i[i] - O_i[i]) / (N_i[i] - 1);
|
|
131
|
+
|
|
132
|
+
V_i_sum += V_i[i];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
Z += (combined_Group_N_1.uncensored[i] - E_i[i]);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
Z = Z / sqrt(V_i_sum);
|
|
139
|
+
free(Group_N_1.uncensored);
|
|
140
|
+
free(Group_N_1.censored);
|
|
141
|
+
free(Group_N_2.uncensored);
|
|
142
|
+
free(Group_N_2.censored);
|
|
143
|
+
free(merged_time_pnts.D_ptr);
|
|
144
|
+
free(merged_uniq_time_pnts.D_ptr);
|
|
145
|
+
free(N1_at_risk);
|
|
146
|
+
free(N2_at_risk);
|
|
147
|
+
free(N_i);
|
|
148
|
+
free(O_i);
|
|
149
|
+
free(E_i);
|
|
150
|
+
free(V_i);
|
|
151
|
+
|
|
152
|
+
return Z;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
struct curve kaplan_meier(double* time, int* censored, int size)
|
|
156
|
+
{
|
|
157
|
+
|
|
158
|
+
int i, N;
|
|
159
|
+
|
|
160
|
+
Group_N at_risk = group_N_self_range(time, censored, size);
|
|
161
|
+
|
|
162
|
+
N = size;
|
|
163
|
+
|
|
164
|
+
struct point* KM = (struct point*) malloc(at_risk.size * sizeof(struct point));
|
|
165
|
+
|
|
166
|
+
for (i = 0; i < at_risk.size; i++)
|
|
167
|
+
{
|
|
168
|
+
if (i > 0)
|
|
169
|
+
{
|
|
170
|
+
N = (N - at_risk.uncensored[i - 1] - at_risk.censored[i - 1]);
|
|
171
|
+
KM[i].x = at_risk.time[i];
|
|
172
|
+
KM[i].y = 1.0 * (N - at_risk.uncensored[i] - at_risk.censored[i]) / (N - at_risk.censored[i]) * KM[i - 1].y;
|
|
173
|
+
} else {
|
|
174
|
+
KM[0].x = at_risk.time[i];
|
|
175
|
+
KM[0].y = 1.0 * (N - at_risk.uncensored[0] - at_risk.censored[0]) / (N - at_risk.censored[0]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
curve KM_curve;
|
|
180
|
+
KM_curve.point_array = KM;
|
|
181
|
+
KM_curve.size = at_risk.size;
|
|
182
|
+
|
|
183
|
+
free(at_risk.uncensored);
|
|
184
|
+
free(at_risk.censored);
|
|
185
|
+
free(at_risk.time);
|
|
186
|
+
|
|
187
|
+
return KM_curve;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#endif
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#ifndef _SURVIVAL_STAT_UTILITY_H_
|
|
2
|
+
#define _SURVIVAL_STAT_UTILITy_H_
|
|
3
|
+
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include "global_utility.h"
|
|
7
|
+
#include "survival_def.h"
|
|
8
|
+
#include "type_def.h"
|
|
9
|
+
|
|
10
|
+
struct array create_sorted_unique_array(double* array, int size)
|
|
11
|
+
{
|
|
12
|
+
struct array arr;
|
|
13
|
+
int i;
|
|
14
|
+
//To speed up, choose to do not memset arr.
|
|
15
|
+
arr.D_ptr = NULL;
|
|
16
|
+
int count;
|
|
17
|
+
|
|
18
|
+
qsort(array, size, sizeof(double), &compare_double);
|
|
19
|
+
|
|
20
|
+
count = 1;
|
|
21
|
+
//calcualte number of unique
|
|
22
|
+
for(i = 1; i < size; ++i)
|
|
23
|
+
{
|
|
24
|
+
if(array[i] != array[i-1])
|
|
25
|
+
{
|
|
26
|
+
count++;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
double * unique_arr = (double *) malloc(count * sizeof(double));
|
|
31
|
+
|
|
32
|
+
//assign unique elements
|
|
33
|
+
count = 1;
|
|
34
|
+
unique_arr[0] = array[0];
|
|
35
|
+
for(i = 1; i < size; ++i)
|
|
36
|
+
{
|
|
37
|
+
if(array[i] != array[i-1])
|
|
38
|
+
{
|
|
39
|
+
unique_arr[count] = array[i];
|
|
40
|
+
count++;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
arr.D_ptr = unique_arr;
|
|
45
|
+
arr.size = count;
|
|
46
|
+
|
|
47
|
+
return arr;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
array merge_two_array(double* array_1, int size_1, double* array_2, int size_2)
|
|
51
|
+
{
|
|
52
|
+
int i;
|
|
53
|
+
struct array arr;
|
|
54
|
+
|
|
55
|
+
//To speed up, choose to do not memset arr.
|
|
56
|
+
arr.D_ptr = NULL;
|
|
57
|
+
|
|
58
|
+
int total_size = size_1 + size_2;
|
|
59
|
+
double * merged_array = (double *) malloc(total_size * sizeof(double));
|
|
60
|
+
for(i = 0; i < size_1; i++)
|
|
61
|
+
{
|
|
62
|
+
merged_array[i] = array_1[i];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for( i = 0; i < size_2; i++)
|
|
66
|
+
{
|
|
67
|
+
merged_array[i + size_1] = array_2[i];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
arr.D_ptr = merged_array;
|
|
71
|
+
arr.size = total_size;
|
|
72
|
+
|
|
73
|
+
return arr;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
int find_first_index_has(double* arr, int size, double value)
|
|
77
|
+
{
|
|
78
|
+
int i;
|
|
79
|
+
for(i = 0; i < size; i++)
|
|
80
|
+
{
|
|
81
|
+
if(fabs(arr[i] - value) < EPSILON)
|
|
82
|
+
{
|
|
83
|
+
return i;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//no value in the array
|
|
88
|
+
return -1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
struct Group_N group_N_self_range(double* time, int* censored, int size)
|
|
92
|
+
{
|
|
93
|
+
int i, count_at, uncensored_num_at, censored_num_at;
|
|
94
|
+
double tmp, time_at;
|
|
95
|
+
|
|
96
|
+
// sort time and censored based on time together, time can censored array
|
|
97
|
+
struct point* time_censored_array = (struct point*) malloc(size * sizeof(struct point));
|
|
98
|
+
|
|
99
|
+
//censored, if censored[] is positive
|
|
100
|
+
for (i = 0; i < size; i++)
|
|
101
|
+
{
|
|
102
|
+
time_censored_array[i].x = time[i];
|
|
103
|
+
if (censored[i] > 0)
|
|
104
|
+
time_censored_array[i].y = 1;
|
|
105
|
+
else
|
|
106
|
+
time_censored_array[i].y = -1;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
qsort(time_censored_array, size, sizeof(struct point), &point_compare_x);
|
|
110
|
+
|
|
111
|
+
//count unique uncensored time point
|
|
112
|
+
int count = 0;
|
|
113
|
+
for (i = 0; i < size; i++)
|
|
114
|
+
{ //uncensored
|
|
115
|
+
if (time_censored_array[i].y < 0)
|
|
116
|
+
{
|
|
117
|
+
if (count == 0)
|
|
118
|
+
{
|
|
119
|
+
count++;
|
|
120
|
+
tmp = time_censored_array[i].x;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (count > 0)
|
|
124
|
+
{ //unique
|
|
125
|
+
if (time_censored_array[i].x != tmp)
|
|
126
|
+
{
|
|
127
|
+
count++;
|
|
128
|
+
tmp = time_censored_array[i].x;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
double* unique_uncensored_time = (double *) malloc(count * sizeof(double));
|
|
135
|
+
|
|
136
|
+
count = 0;
|
|
137
|
+
|
|
138
|
+
for (i = 0; i < size; i++)
|
|
139
|
+
{
|
|
140
|
+
if (time_censored_array[i].y < 0)
|
|
141
|
+
{
|
|
142
|
+
if (count == 0)
|
|
143
|
+
{
|
|
144
|
+
count++;
|
|
145
|
+
unique_uncensored_time[count] = time_censored_array[i].x;
|
|
146
|
+
tmp = time_censored_array[i].x;
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (count > 0)
|
|
151
|
+
{
|
|
152
|
+
if (time_censored_array[i].x != tmp)
|
|
153
|
+
{
|
|
154
|
+
unique_uncensored_time[count] = time_censored_array[i].x;
|
|
155
|
+
|
|
156
|
+
count++;
|
|
157
|
+
tmp = time_censored_array[i].x;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
int* uncensored_num = (int *) malloc(count * sizeof(int));
|
|
164
|
+
int* censored_num = (int *) malloc(count * sizeof(int));
|
|
165
|
+
|
|
166
|
+
//record current time point
|
|
167
|
+
time_at = unique_uncensored_time[0];
|
|
168
|
+
count_at = 0;
|
|
169
|
+
uncensored_num_at = 0;
|
|
170
|
+
censored_num_at = 0;
|
|
171
|
+
|
|
172
|
+
for (i = 0; i < size; i++)
|
|
173
|
+
{
|
|
174
|
+
if (time_censored_array[i].x <= time_at)
|
|
175
|
+
{
|
|
176
|
+
if (time_censored_array[i].y > 0)
|
|
177
|
+
censored_num_at++;
|
|
178
|
+
else
|
|
179
|
+
uncensored_num_at++;
|
|
180
|
+
|
|
181
|
+
if (i == size - 1)
|
|
182
|
+
{
|
|
183
|
+
uncensored_num[count_at] = uncensored_num_at;
|
|
184
|
+
censored_num[count_at] = censored_num_at;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
} else {
|
|
188
|
+
uncensored_num[count_at] = uncensored_num_at;
|
|
189
|
+
censored_num[count_at] = censored_num_at;
|
|
190
|
+
count_at++;
|
|
191
|
+
|
|
192
|
+
uncensored_num_at = 0;
|
|
193
|
+
censored_num_at = 0;
|
|
194
|
+
time_at = unique_uncensored_time[count_at];
|
|
195
|
+
//we need to update here
|
|
196
|
+
if (time_censored_array[i].y > 0)
|
|
197
|
+
censored_num_at++;
|
|
198
|
+
else
|
|
199
|
+
uncensored_num_at++;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
Group_N at_risk_result;
|
|
204
|
+
at_risk_result.uncensored = uncensored_num;
|
|
205
|
+
at_risk_result.censored = censored_num;
|
|
206
|
+
at_risk_result.size = count;
|
|
207
|
+
at_risk_result.time = unique_uncensored_time;
|
|
208
|
+
free(time_censored_array);
|
|
209
|
+
return at_risk_result;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
struct Group_N group_N_given_range(double* time, int* censored, int size, double* unique_time, int unique_time_size)
|
|
213
|
+
{
|
|
214
|
+
int i, count_at, uncensored_num_at, censored_num_at;
|
|
215
|
+
double time_at;
|
|
216
|
+
|
|
217
|
+
struct point* time_censored_array = (struct point*) malloc(size * sizeof(struct point));
|
|
218
|
+
|
|
219
|
+
for (i = 0; i < size; i++)
|
|
220
|
+
{
|
|
221
|
+
time_censored_array[i].x = time[i];
|
|
222
|
+
//not very fast here, prefer to define another point
|
|
223
|
+
if (censored[i] > 0)
|
|
224
|
+
time_censored_array[i].y = 1;
|
|
225
|
+
else
|
|
226
|
+
time_censored_array[i].y = -1;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
qsort(time_censored_array, size, sizeof(struct point), &point_compare_x);
|
|
230
|
+
|
|
231
|
+
int* uncensored_num = (int *) malloc(unique_time_size * sizeof(int));
|
|
232
|
+
int* censored_num = (int *) malloc(unique_time_size * sizeof(int));
|
|
233
|
+
|
|
234
|
+
for (i = 0; i < unique_time_size; i++)
|
|
235
|
+
{
|
|
236
|
+
uncensored_num[i] = 0;
|
|
237
|
+
censored_num[i] = 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
//record current time point
|
|
241
|
+
time_at = unique_time[0];
|
|
242
|
+
count_at = 0;
|
|
243
|
+
uncensored_num_at = 0;
|
|
244
|
+
censored_num_at = 0;
|
|
245
|
+
|
|
246
|
+
for (i = 0; i < size; i++)
|
|
247
|
+
{
|
|
248
|
+
if (time_censored_array[i].x <= time_at)
|
|
249
|
+
{
|
|
250
|
+
if (time_censored_array[i].y > 0)
|
|
251
|
+
censored_num_at++;
|
|
252
|
+
else
|
|
253
|
+
uncensored_num_at++;
|
|
254
|
+
|
|
255
|
+
if (i == size - 1)
|
|
256
|
+
{
|
|
257
|
+
uncensored_num[count_at] = uncensored_num_at;
|
|
258
|
+
censored_num[count_at] = censored_num_at;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
} else {
|
|
262
|
+
|
|
263
|
+
while (time_censored_array[i].x > time_at)
|
|
264
|
+
{
|
|
265
|
+
uncensored_num[count_at] = uncensored_num_at;
|
|
266
|
+
censored_num[count_at] = censored_num_at;
|
|
267
|
+
count_at++;
|
|
268
|
+
|
|
269
|
+
uncensored_num_at = 0;
|
|
270
|
+
censored_num_at = 0;
|
|
271
|
+
time_at = unique_time[count_at];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (time_censored_array[i].y > 0)
|
|
275
|
+
censored_num_at++;
|
|
276
|
+
else
|
|
277
|
+
uncensored_num_at++;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
Group_N at_risk_result;
|
|
282
|
+
at_risk_result.uncensored = uncensored_num;
|
|
283
|
+
at_risk_result.censored = censored_num;
|
|
284
|
+
at_risk_result.size = unique_time_size;
|
|
285
|
+
at_risk_result.time = unique_time;
|
|
286
|
+
|
|
287
|
+
free(time_censored_array);
|
|
288
|
+
|
|
289
|
+
return at_risk_result;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
#endif
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#ifndef _SSTAT_TYPE_DEF_H_
|
|
2
|
+
#define _SSTAT_TYPE_DEF_H_
|
|
3
|
+
|
|
4
|
+
//EPSILON here is set based on ruby float. we need to chagne it for other project
|
|
5
|
+
#define EPSILON 2.2204460492503131e-16
|
|
6
|
+
|
|
7
|
+
//The following constants are from ATMEL http://www.atmel.com/webdoc/
|
|
8
|
+
#define M_2_SQRTPI 1.12837916709551257390
|
|
9
|
+
#define M_SQRT1_2 0.70710678118654752440
|
|
10
|
+
#define M_1_SQRT2PI (M_2_SQRTPI * M_SQRT1_2 / 2.0)
|
|
11
|
+
#define M_SQRT2 1.41421356237309504880
|
|
12
|
+
#define SQRT32 (4.0 * M_SQRT2)
|
|
13
|
+
|
|
14
|
+
//GSL constants for gaussian distribution
|
|
15
|
+
#define GAUSS_XUPPER (8.572)
|
|
16
|
+
#define GAUSS_XLOWER (-37)
|
|
17
|
+
#define GAUSS_SCALE (16.0)
|
|
18
|
+
#define GAUSS_EPSILON 1e-12
|
|
19
|
+
|
|
20
|
+
typedef struct point{
|
|
21
|
+
double x;
|
|
22
|
+
double y;
|
|
23
|
+
} point;
|
|
24
|
+
|
|
25
|
+
typedef struct curve{
|
|
26
|
+
struct point* point_array;
|
|
27
|
+
int size;
|
|
28
|
+
} curve;
|
|
29
|
+
|
|
30
|
+
typedef struct array{
|
|
31
|
+
double* D_ptr;
|
|
32
|
+
int size;
|
|
33
|
+
} array;
|
|
34
|
+
|
|
35
|
+
#endif
|
data/ext/sstat/sstat.c
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#include "sstat.h"
|
|
2
|
+
|
|
3
|
+
static VALUE rb_percentile(VALUE self, VALUE array, VALUE target)
|
|
4
|
+
{
|
|
5
|
+
int size = RARRAY_LEN(array);
|
|
6
|
+
int i;
|
|
7
|
+
double _target = NUM2DBL(target);
|
|
8
|
+
double _percentile;
|
|
9
|
+
double* c_array = (double *)malloc(sizeof(double) * size);
|
|
10
|
+
|
|
11
|
+
for (i = 0; i < size; i++) {
|
|
12
|
+
c_array[i] = NUM2DBL(rb_ary_entry(array, i));
|
|
13
|
+
}
|
|
14
|
+
_percentile = precentile(c_array, size, _target);
|
|
15
|
+
free(c_array);
|
|
16
|
+
|
|
17
|
+
return DBL2NUM(_percentile);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static VALUE rb_index_less_equal(VALUE self, VALUE array, VALUE target)
|
|
21
|
+
{
|
|
22
|
+
int size = RARRAY_LEN(array);
|
|
23
|
+
int i;
|
|
24
|
+
int _index;
|
|
25
|
+
double _target = NUM2DBL(target);
|
|
26
|
+
double* c_array = (double *)malloc(sizeof(double) * size);
|
|
27
|
+
for (i = 0; i < size; i++) {
|
|
28
|
+
c_array[i] = NUM2DBL(rb_ary_entry(array, i));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_index = index_less_equal(c_array, size, _target);
|
|
32
|
+
|
|
33
|
+
free(c_array);
|
|
34
|
+
|
|
35
|
+
return INT2NUM(_index);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static VALUE rb_kaplan_meier(VALUE self, VALUE time, VALUE censored)
|
|
39
|
+
{
|
|
40
|
+
int size = RARRAY_LEN(time);
|
|
41
|
+
int i;
|
|
42
|
+
struct curve KM_curve;
|
|
43
|
+
VALUE result;
|
|
44
|
+
double* _time = (double *)malloc(sizeof(double) * size);
|
|
45
|
+
int* _censored = (int *)malloc(sizeof(int) * size);
|
|
46
|
+
for (i = 0; i < size; i++) {
|
|
47
|
+
_time[i] = NUM2DBL(rb_ary_entry(time, i));
|
|
48
|
+
|
|
49
|
+
_censored[i] = NUM2INT(rb_ary_entry(censored, i));
|
|
50
|
+
}
|
|
51
|
+
KM_curve = kaplan_meier(_time, _censored, size);
|
|
52
|
+
|
|
53
|
+
VALUE KM_x = rb_ary_new2(KM_curve.size);
|
|
54
|
+
VALUE KM_y = rb_ary_new2(KM_curve.size);
|
|
55
|
+
|
|
56
|
+
for (i = 0; i < KM_curve.size; i++)
|
|
57
|
+
{
|
|
58
|
+
rb_ary_store(KM_x, i, DBL2NUM(KM_curve.point_array[i].x));
|
|
59
|
+
rb_ary_store(KM_y, i, DBL2NUM(KM_curve.point_array[i].y));
|
|
60
|
+
}
|
|
61
|
+
result = rb_hash_new();
|
|
62
|
+
rb_hash_aset(result, rb_str_new2("time"), KM_x);
|
|
63
|
+
rb_hash_aset(result, rb_str_new2("prob"), KM_y);
|
|
64
|
+
|
|
65
|
+
free(_time);
|
|
66
|
+
free(_censored);
|
|
67
|
+
free(KM_curve.point_array);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static VALUE rb_log_rank_test(VALUE self, VALUE _time_1, VALUE _cens_1, VALUE _time_2, VALUE _cens_2)
|
|
72
|
+
{
|
|
73
|
+
int size_1 = RARRAY_LEN(_time_1);
|
|
74
|
+
int size_2 = RARRAY_LEN(_time_2);
|
|
75
|
+
|
|
76
|
+
int i;
|
|
77
|
+
double _Z;
|
|
78
|
+
|
|
79
|
+
double* time_1 = (double *)malloc(sizeof(double) * size_1);
|
|
80
|
+
double* time_2 = (double *)malloc(sizeof(double) * size_2);
|
|
81
|
+
int* cens_1 = (int *)malloc(sizeof(int) * size_1);
|
|
82
|
+
int* cens_2 = (int *)malloc(sizeof(int) * size_2);
|
|
83
|
+
|
|
84
|
+
for (i = 0; i < size_1; i++) {
|
|
85
|
+
time_1[i] = NUM2DBL(rb_ary_entry(_time_1, i));
|
|
86
|
+
cens_1[i] = NUM2INT(rb_ary_entry(_cens_1, i));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (i = 0; i < size_2; i++) {
|
|
90
|
+
time_2[i] = NUM2DBL(rb_ary_entry(_time_2, i));
|
|
91
|
+
cens_2[i] = NUM2INT(rb_ary_entry(_cens_2, i));
|
|
92
|
+
}
|
|
93
|
+
_Z = log_rank_test(time_1, cens_1, time_2, cens_2, size_1, size_2);
|
|
94
|
+
|
|
95
|
+
free(time_1);
|
|
96
|
+
free(time_2);
|
|
97
|
+
free(cens_1);
|
|
98
|
+
free(cens_2);
|
|
99
|
+
|
|
100
|
+
return DBL2NUM(_Z);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static VALUE rb_cdf_unormal_Q(VALUE self, VALUE x)
|
|
104
|
+
{
|
|
105
|
+
double Q = cdf_ugaussian_Q(NUM2DBL(x));
|
|
106
|
+
return DBL2NUM(Q);
|
|
107
|
+
}
|
data/ext/sstat/sstat.h
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#ifndef _SSTAT_H_
|
|
2
|
+
#define _SSTAT_H_
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include "lib/survival.h"
|
|
7
|
+
#include "lib/global_utility.h"
|
|
8
|
+
#include "lib/distribution.h"
|
|
9
|
+
|
|
10
|
+
static VALUE rb_percentile(VALUE self, VALUE arg, VALUE target);
|
|
11
|
+
static VALUE rb_index_less_equal(VALUE self, VALUE arg, VALUE target);
|
|
12
|
+
static VALUE rb_kaplan_meier(VALUE self, VALUE time, VALUE censor);
|
|
13
|
+
static VALUE rb_log_rank_test(VALUE self, VALUE time_1, VALUE censor_1,VALUE time_2, VALUE censor_2);
|
|
14
|
+
static VALUE rb_cdf_unormal_Q(VALUE self, VALUE x);
|
|
15
|
+
|
|
16
|
+
//rb_ary_storde(unmasked, i, INT2NUM(p ^ m));
|
|
17
|
+
void Init_sstat() {
|
|
18
|
+
VALUE sstat_module = rb_define_module("SStat");
|
|
19
|
+
VALUE basic_class = rb_define_class_under(sstat_module, "Basic", rb_cObject);
|
|
20
|
+
|
|
21
|
+
rb_define_method(basic_class, "percentile", rb_percentile, 2);
|
|
22
|
+
rb_define_method(basic_class, "index_less_equal", rb_index_less_equal, 2);
|
|
23
|
+
rb_define_method(basic_class, "kaplan_meier", rb_kaplan_meier, 2);
|
|
24
|
+
rb_define_method(basic_class, "log_rank_test", rb_log_rank_test, 4);
|
|
25
|
+
rb_define_method(basic_class, "cdf_unormal_Q", rb_cdf_unormal_Q, 1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#endif
|
data/lib/sstat.so
ADDED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sstat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Haipeng Li
|
|
@@ -19,7 +19,22 @@ extensions:
|
|
|
19
19
|
- ext/sstat/extconf.rb
|
|
20
20
|
extra_rdoc_files: []
|
|
21
21
|
files:
|
|
22
|
+
- bin/console
|
|
23
|
+
- bin/setup
|
|
24
|
+
- ext/sstat/Makefile
|
|
22
25
|
- ext/sstat/extconf.rb
|
|
26
|
+
- ext/sstat/lib/distribution.h
|
|
27
|
+
- ext/sstat/lib/global_utility.h
|
|
28
|
+
- ext/sstat/lib/survival.h
|
|
29
|
+
- ext/sstat/lib/survival_def.h
|
|
30
|
+
- ext/sstat/lib/survival_func.h
|
|
31
|
+
- ext/sstat/lib/survival_utility.h
|
|
32
|
+
- ext/sstat/lib/type_def.h
|
|
33
|
+
- ext/sstat/sstat.c
|
|
34
|
+
- ext/sstat/sstat.h
|
|
35
|
+
- lib/simple_statistics.rb
|
|
36
|
+
- lib/simple_statistics/version.rb
|
|
37
|
+
- lib/sstat.so
|
|
23
38
|
homepage:
|
|
24
39
|
licenses: []
|
|
25
40
|
metadata: {}
|