rcppcore / rcpp-gallery Goto Github PK
View Code? Open in Web Editor NEWSource code for the Rcpp Gallery website
Home Page: http://gallery.rcpp.org
License: Other
Source code for the Rcpp Gallery website
Home Page: http://gallery.rcpp.org
License: Other
Here's the Rcpp gallery post I promised in RcppCore/Rcpp#828 on call-stack-free versions of Rcpp::stop
and Rcpp::warning
:
https://gist.github.com/michaelweylandt/d0c53047229a5351affdb6c163b27cbc
Suggest adding this to Rcpp gallery:
@jjallaire Can you spare a few minutes? The CSS formatting has code for <p>
to increase the point size / font size, but we missed the bulleted lists, see eg this recent post. I knew there was an overall default outside of <p>
but I can't recall how to set it. Blame it on being at the tail end of some traveling...
title: Coercion of matrix to sparse matrix (dgCMatrix) and maintaining dimnames.
author: Søren Højsgaard
license: GPL (>= 2)
tags: RcppEigen matrix
Consider the following matrix
nr <- nc <- 6
set.seed <- 123
m <- matrix(sample(c(rep(0,9), 1),nr*nc, replace=T), nrow=nr, ncol=nc)
sum(m)/length(m)
dimnames(m) <- list(letters[1:nr], letters[1:nc])
m
This matrix can be coerced to a sparse matrix with
library("Matrix")
M1 <- as(m, "dgCMatrix")
M1
str(M1)
Using Eigen via
RcppEigen we
can obtain the coercion as:
// [[Rcpp::depends(RcppEigen)]]
#include <RcppEigen.h>
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
SEXP asdgCMatrix_( SEXP XX_ ){
typedef Eigen::SparseMatrix<double> SpMat;
typedef Eigen::Map<Eigen::MatrixXd> MapMatd; // Input: must be double
MapMatd X(Rcpp::as<MapMatd>(XX_));
SpMat Xsparse = X.sparseView(); // Output: sparse matrix
S4 Xout(wrap(Xsparse)); // Output: as S4 object
NumericMatrix Xin(XX_); // Copy dimnames
Xout.slot("Dimnames") = clone(List(Xin.attr("dimnames")));
return(Xout);
}
(M2 <- asdgCMatrix_(m * 1.0))
str(M2)
identical(M1, M2)
Compare the performance:
cols <- c("test", "replications", "elapsed", "relative", "user.self", "sys.self")
rbenchmark::benchmark(asdgCMatrix_(m * 1.0), as(m, "dgCMatrix"),
columns=cols, order="relative", replications=1000)
For larger matrices the difference in performance gain is smaller:
## 100 x 100 matrix
nr <- nc <- 100
set.seed <- 123
m <- matrix(sample(c(rep(0,9), 1),nr*nc, replace=T), nrow=nr, ncol=nc)
rbenchmark::benchmark(asdgCMatrix_(m * 1.0), as(m, "dgCMatrix"),
columns=cols, order="relative", replications=1000)
## 1000 x 1000 matrix
nr <- nc <- 1000
set.seed <- 123
m <- matrix(sample(c(rep(0,9), 1),nr*nc, replace=T), nrow=nr, ncol=nc)
rbenchmark::benchmark(asdgCMatrix_(m * 1.0), as(m, "dgCMatrix"),
columns=cols, order="relative", replications=100)
## 3000 x 3000 matrix
nr <- nc <- 3000
set.seed <- 123
m <- matrix(sample(c(rep(0,9), 1),nr*nc, replace=T), nrow=nr, ncol=nc)
rbenchmark::benchmark(asdgCMatrix_(m * 1.0), as(m, "dgCMatrix"),
columns=cols, order="relative", replications=100)
I am working on a package called rdoxygen (lead by @nevrome), of which the purpose is to easily add Doxygen documentation for the C++ code to the R package containing it. Among other features, the package allows the Doxygen docs to be wrapped in an R vignette, so as to be easily accessible by the package users.
We believe these functionalities would be useful to many R/C++ package developers, and thus would like to contribute a small tutorial to Rcpp Gallery. Would you be open to such a contribution, even though the article isn't exactly about Rcpp?
Sorry, I am too pitiful with git to do a pull request. Here's the file that I'm trying to pull.
2020-07-18-accessing-3d-array.cpp
/**
* @title Accessing entries of a three-dimensional array
* @author Rodney Sparapani
* @license GPL (>= 2)
* @tags array
* @summary An example of how to access the entries of an array
* since generic (i, j, k)-like operators don't exist.
*/
#include <Rcpp.h>
// [[Rcpp::export]]
using namespace Rcpp;
IntegerVector get3d(IntegerVector x, IntegerVector args) {
IntegerVector rc(1), dim=x.attr("dim");
rc[0]=R_NaN;
const size_t K=args.size();
if(K!=dim.size()) return rc;
size_t i;
if(K==1) {
i=args[0]-1;
if(i>=0 && i<dim[0]) rc[0]=x[i];
}
else if(K==2) {
i=(args[1]-1)*dim[0]+args[0]-1;
if(i>=0 && i<(dim[0]*dim[1])) rc[0]=x[i];
}
else if(K==3) {
i=((args[2]-1)*dim[1]+(args[1]-1))*dim[0]+args[0]-1;
if(i>=0 && i<(dim[0]*dim[1]*dim[2])) rc[0]=x[i];
}
return rc;
}
/**
* This function returns the entry corresponding to "args" from "x" which
* is either a 1, 2 or 3-dimensional arrays. Since the `(i, j, k)` operator
* doesn't exist, we resort to "args" which is an integer vector.
*/
/*** R
library(Rcpp)
b = array(1:8, dim=8)
c = array(1:8, dim=c(2, 4))
a <- array(1:24, dim=c(2, 3, 4))
get3d(b, 3)
b[3]
for(k in 1:8) print(b[k]-get3d(b, k))
get3d(c, c(2, 1))
c[2, 1]
for(i in 1:2)
for(k in 1:4) print(c[i, k]-get3d(c, c(i, k)))
get3d(a, c(2, 1, 1))
a[2, 1, 1]
for(i in 1:2)
for(j in 1:3)
for(k in 1:4)
print(a[i, j, k]-get3d(a, c(i, j, k)))
*/
Sparse matrix examples from 2012 and 2013 (links below) are outdated and should probably be removed.
http://gallery.rcpp.org/articles/armadillo-sparse-matrix/
https://github.com/RcppCore/rcpp-gallery/blob/gh-pages/src/2012-12-25-armadillo-sparse-matrix.cpp
http://gallery.rcpp.org/articles/as-and-wrap-for-sparse-matrices/
https://github.com/RcppCore/rcpp-gallery/blob/gh-pages/src/2013-08-05-as-and-wrap-for-sparse-matrices.cpp
The above rcpp-gallery examples have several problems. They use internal (non-public) armadillo functionality that is marked as deprecated, ie. arma::memory::acquire_chunked(). This function will be removed. The examples also directly create an armadillo sparse matrix by poking the SpMat arrays without taking into account the state of the internal cache. This is dangerous, as the example promotes dangerous use (ie. people may simply copy and paste the code, and then modify it without thinking).
To construct a sparse matrix from existing CSC arrays, it's far safer and simpler to use the appropriate sparse matrix constructor:
sp_mat(rowind, colptr, values, n_rows, n_cols)
Hi,
I am trying the code from this example and it fails with:
g++ -I/usr/share/R/include -DNDEBUG -I"/home/vspinu/.lib/R/Rcpp/include" -std=c++11 -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -g -c sort.cpp -o sort.o
sort.cpp: In constructor ‘IndexComparator<16>::IndexComparator(const CharacterVector&)’:
sort.cpp:24:71: error: cannot convert ‘Rcpp::Vector<16>::const_iterator {aka Rcpp::internal::Proxy_Iterator<Rcpp::internal::const_string_proxy<16> >}’ to ‘SEXPREC* const*’ in initialization
IndexComparator( const CharacterVector& data_ ) : data(data_.begin()){}
^
There should probably be a small change to make it work again. Thanks.
We still seem to have an explained weirdness in that Modules code does not survive the knitr / jekyll treatment.
The new Rcpp gallery stuff is very cool. But I don't see any way to provide feedback on articles, either directly to the author or as a comment. Is that something that could be added? It looks like the only channel available is to fork it & submit a pull request, but there's no mention of that, nor facilitating link, that I can see.
It is not obvious how to instantiate DateVector
and DatetimeVector
using Rcpp in C++ code.
Eg. this does not work:
DateVector d = DateVector::create("2010-12-31", "2011-01-01", "2011-05-29");
Currently there is only one article available which mainly focuses on how to work with non-vectorized Date
s and Datetime
s or using an existing DatetimeVector
passed to the example function: https://gallery.rcpp.org/articles/parsing-datetimes/
Add a new article (or modify the existing article) to show examples how to instantiate DateVector
and DatetimeVector
.
// assumes an origin as base for counting the days (risky)
DateVector d = DateVector::create(14974, 14975, 15123);
// uses constructors (shows different ways to create the date elements)
DateVector d = DateVector::create(Date("2010-12-31"), Date("01.01.2011", "%d.%m.%Y"), Date(2011, 05, 29));
Rcpp for everyone: Ch 16 - Dates
SO question on how to create a new DateVector
from dates as strings
Hello, I test Rcpp on Debian/64bit, compiled "Rcpp_test.cpp" without any warnnings.
but got "segmentation fault" when launched.
//Rcpp_test.cpp
using namespace Rcpp;
int main(int argc, char const* argv[])
{
Rcpp::NumericVector xx(10);
return 0;
}
C.f. https://github.com/lsilvest/data.table_at_c_level per discussion in DavZim/RITCH#14 (comment)
Dear JJ Allaire, please include my article speed chain ladder analysis using Rcpp https://gist.github.com/ActiveAnalytics/27ad99f108a6b0c18787 in the Rcpp gallery
Thanks
Chibisi
I made RcppGSL better in the summer--no more explicit free()
on the objects etc pp so I should update the three posts. I can't quite figure out what I want: just the new (better) approach? New and old for comparison? Thoughs...
Hi guys,
I put together an article on faster factor generation with Rcpp, as well as an example inspired by R's tapply. Take a look:
https://gist.github.com/cdrv/5045531
Thanks!
-Kevin
Hi,
Dirk asked whether I wanted to write up an entry based on an answer I posted on StackOverflow, here it is: https://gist.github.com/fabian-s/9665846
Best wishes & thanks for the great work you all are doing with Rcpp,
Fabian
Dirk recently send around an email encouraging previous authors to update their posts using the new features. The original version of my post actually included formulas and figures so I was happy to hear that they are now supported. The updated gist is here and the original link in the Gallery is here.
Hello,
Over the last year or so I've been trying to teach myself Rcpp and C++. At some point I made my own cheat sheet and at some point I thought to format it for the Rcpp Gallery in case people thought it may be an appropriate contribution. You can find it here:
Is this the sort of material you would like to include in your gallery? Have I learned reasonable ways of working with Rcpp?
Thank you!
Brian
Here is an updated version of 2013-07-13-dmvnorm_arma.Rmd: https://gist.github.com/boennecd/db36747096e0d8a996a06e571f181ede
dmvnrm_arma
now yields a reduction in computation time relative to dMvn
of ~44% compared to ~10% before and dmvnorm_arma
yields a reduction in computation time of ~22% compared to an increase of ~97% before.
I have also added a remark about the numerical stability.
Hello, I found random_shufle()
used in STL random_shuffle for permutations was not available in C++17. The following code returns the same result, and I thought it would be helpful for other users. Since this is a minor change to the article, I opened this issue instead of sending a pull request.
#include <Rcpp.h>
inline int randWrapper(const int n) { return floor(unif_rand()*n); }
// [[Rcpp::export]]
Rcpp::NumericVector randomShuffle(Rcpp::NumericVector a) {
// clone a into b to leave a alone
Rcpp::NumericVector b = Rcpp::clone(a);
int n = b.size();
int j;
// Fisher-Yates Shuffle Algorithm
for (int i = 0; i < n - 1; i++)
{
j = i + randWrapper(n - i);
std::swap(b[i], b[j]);
}
return b;
}
sourceCpp(code =
'
#include <Rcpp.h>
inline int randWrapper(const int n) { return floor(unif_rand()*n); }
// [[Rcpp::export]]
Rcpp::NumericVector randomShuffle_1(Rcpp::NumericVector a) { // Currently on Rcpp Gallery
// clone a into b to leave a alone
Rcpp::NumericVector b = Rcpp::clone(a);
std::random_shuffle(b.begin(), b.end(), randWrapper);
return b;
}
// [[Rcpp::export]]
Rcpp::NumericVector randomShuffle_2(Rcpp::NumericVector a) {
// clone a into b to leave a alone
Rcpp::NumericVector b = Rcpp::clone(a);
int n = b.size();
int j;
// Fisher-Yates Shuffle Algorithm
for (int i = 0; i < n - 1; i++)
{
j = i + randWrapper(n - i);
std::swap(b[i], b[j]);
}
return b;
}
'
)
a <- 1:8
set.seed(42)
randomShuffle_1(a)
#> [1] 8 1 4 2 7 5 3 6
set.seed(42)
randomShuffle_2(a)
#> [1] 8 1 4 2 7 5 3 6
While reading through _posts/2013-12-02-plyr-c-to-rcpp.md trying to make sense of the C++ code and the intended output of the split_indices
function, I may have found a small bug. I ended up running the function to get an idea of the output it generated and was surprised by the result.
Currently, it appears that unless the IntegerVector x
passed into the function is presorted from min to max, or n = max(x)
, then the list returned by the function is truncated by ids.resize(x[i])
to a length that is the value of the final element of x
. For example, split_indices(sample(100))
typically results in lists that are less than 100 elements long despite no replacement, whereas split_indices(sample(100), n = 100)
returns the value I would expect.
I'm not really sure what the intended output is supposed to be, but rather than:
if (x[i] > n) {
ids.resize(x[i]);
}
perhaps the code should be:
if (x[i] > ids.size()) {
ids.resize(x[i]);
}
Then the length of ids
will only be extended via resize
rather than possibly truncated in the situation where x[i] > n
but x[i] < ids.size()
.
Additionally, there are two references to out
in the second bullet point under the example C++ code which should probably be changed to ids
.
Thanks
It seems that cdb37c6 wiped out clean half of this article.
Can we have, e.g. something like Disqus in gallery article. So that people can leave feedback, etc ...
We just need to add this code in post.html
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'rcppgallery'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
Can I push this ?
@rbresearch I just made a change to the Gallery which causes articles to fail if they stop with an error. After doing this I noticed that the following expression from your sorting article was failing it's test
# check that the nth sorted elements of the vectors are equal
stopifnot(all.equal(stl_nth_element(x, 43)[43], sort(x, partial=43)[43]))
I temporarily removed the code so that the Gallery would build: f3de013
However it seems worth pursuing why the test is failing (it may have never worked in the first place but the error was just printed and we never noticed it).
I wrote up a small article on using Rcpp to go back and forth between CharacterVector's and std::vector< std::string >s. The format is in .Rmd
Maybe it was the last Jekyll update at GitHub ... but right now the rendered pages look suboptimal:
I am not much of a CSS writer. Can we get help? Ideas, @jjallaire -- maybe calling out to @yihui ?
@jjallaire shall we aim fore moving this over as you once suggested?
Hello,
I tried to build the rcpp-gallery locally on ubuntu 13.04 and found some missing dependencies in the https://github.com/jjallaire/rcpp-gallery/wiki/Local-Development-Configuration.
There is 1 more package required to build the project: RcppGSL
Here is my shell script to install the dependencies and R packages:
apt-get build-deps r-cran-rgl # sensitivity requires rgl
apt-get install libgsl0-dev libgmp-dev # RcppGSL requires gsl and some packages requires gmp
install.packages(c("Rcpp",
"RcppEigen",
"RcppArmadillo",
"RcppProgress",
"BcppGSL",
"xts",
"BH",
"bigmemory",
"knitr",
"benchmark",
"rbenchmark",
"sensitivity"))
Hope them help
Here is the gist with the Rmd file following the stackoverflow discussion here. Let me know if anything is missing.
Hi guys,
I made a short example showing how we might use BOOST_FOREACH with Rcpp.
https://gist.github.com/4677510
Let me know what you think,
-Kevin
Hi guys,
I put together an example of using R's C API together with Rcpp to recurse through lists, and dynamically wrap R objects after determining their internal R type. It's a question that's been occasionally asked on the mailing lists and wanted to offer an example solution.
https://gist.github.com/cdrv/5332743
Let me know if you have any comments.
-Kevin
Possibly update the Armadillo subset post with:
"Pythagoras" is misspelled here: https://github.com/RcppCore/rcpp-gallery/blob/gh-pages/src/2012-12-20-simulating-pi.cpp#L16
Do you want a pull request?
The gallery has a page on subsetting:
One "trivial" example is missing: Subsetting with an index range (like R does with x[10:20]
).
There is an answer for that at SO which also strives for good performance by avoiding object copies:
https://stackoverflow.com/questions/46668257/rcpp-subsetting-contiguous-stringvector
This code snippet code be the base for extending the subsetting article in the gallery:
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::StringVector in_range(Rcpp::StringVector &x, int i, int j) {
return x[Rcpp::Range(i - 1, j - 1)]; // zero indexed
}
Edit: I guess int i
and int j
should be replaced by R_xlen_t
...
Edit 2: i
and j
are also not validated against the vector size...
Hi guys,
I made an interesting example showing how one might use 'sourceCpp' in a similar manner to 'inline' to generate C++ apply functions on the fly.
https://gist.github.com/4567244
Also, something that was a bit surprising -- it seems like it may be faster to perform a column apply on the transpose of a matrix, rather than a row apply. At least for the test cases I run, on my machine, etc... but I was surprised!
Let me know what you think,
-Kevin
Hello,
I suggest adding these two articles to the Rcpp gallery:
The markdowns can be found here: https://github.com/nextlevelanalytics/nextlevelanalytics.github.io/tree/master/_posts
Thanks
In rendering #136 I noticed inline math was broken. A quick look around lead to one well-meaning and written post on mathjax in jekyll that, sadly, did not work.
But following the standard documentation does (ha!) so PR forthcoming in a minute.
Hi!
First of all, thank you for the library and the Rcpp Gallery articles!
While reading I've noticed that there's a broken link in the "Parallel Version" section of the parallel-vector-sum
article: http://gallery.rcpp.org/articles/parallel-vector-sum/#parallel-version
Namely, attempting to follow the previous article
hyperlink leads to the following URL (resulting in a 404): http://gallery.rcpp.org/articles/parallel-vector-sum/2014-06-29-parallel-matrix-transform.cpp
Seems too trivial for a PR (I presume? just in case, I'm going to make one, too), so here's a proposed fix:
[previous article](2014-06-29-parallel-matrix-transform.cpp)
[previous article](http://gallery.rcpp.org/articles/parallel-matrix-transform/)
/*
Following the working example at: https://github.com/jjallaire/rcpp-gallery/blob/gh-pages/src/2014-07-15-parallel-inner-product.cpp
which links to: https://github.com/jjallaire/rcpp-gallery/blob/gh-pages/src/2014-06-29-parallel-vector-sum.cpp
living at: http://gallery.rcpp.org/articles/parallel-vector-sum/
using: [parallel-vector-sum](http://gallery.rcpp.org/articles/parallel-vector-sum/)
Comparing: https://github.com/jjallaire/rcpp-gallery/blob/gh-pages/src/2014-06-29-parallel-vector-sum.cpp
which attempts to link to: https://github.com/jjallaire/rcpp-gallery/blob/gh-pages/src/2014-06-29-parallel-matrix-transform.cpp
living at: http://gallery.rcpp.org/articles/parallel-matrix-transform/
using: [previous article](2014-06-29-parallel-matrix-transform.cpp)
*/
After performing a local build, I noticed that the following R packages were required, but not specified on the "Local Development Configuration" wiki:
Furthermore, the benchmark package listed in the dependencies seems to be archived on CRAN.
Lastly, I think it might be nice to give wiki readers an install.packages()
line they can copy to their R environment, similar to what's provided with the sudo apt-get install ...
lines. Consider including something like
install.packages( c("Rcpp", "RcppEigen", ...) )
devtools::install_github( "RcppCore/RcppNT2" )
devtools::install_github( "dcdillon/RcppHoney" )
If you are interested, I could contribute an article on RcppArrayFire, e.g. along the lines of http://www.daqana.org/rcpparrayfire/articles/RcppArrayFire.html. Or as an extension of the recent article on put options using something like
#include <RcppArrayFire.h>
// [[Rcpp::depends(RcppArrayFire)]]
using af::array;
using af::log;
using af::erfc;
using std::sqrt;
using std::exp;
array normcdf(array x) {
return erfc(-x / sqrt(2.0)) / 2.0;
}
// [[Rcpp::export]]
array put_option_pricer_af(RcppArrayFire::typed_array<f32> s, double k, double r, double y, double t, double sigma) {
array d1 = (log(s / k) + (r - y + sigma * sigma / 2.0) * t) / (sigma * sqrt(t));
array d2 = d1 - sigma * sqrt(t);
return normcdf(-d2) * k * exp(-r * t) - s * exp(-y * t) * normcdf(-d1);
}
Caveat is of course that it complicates building the gallery due to dependence on the ArrayFire library.
I ran the code here and the R version and the Rcpp versions give different results.
stopifnot(identical(gerber.correlation(HIST_RETURN, LOOKBACK), GERBER_CORRELATION(HIST_RETURN, LOOKBACK)))
Hello,
I wrote a small article for the Rcpp Gallery following the suggestion of Dirk. The .Rmd file can be found here https://gist.github.com/bobthecat/6509321
Thanks,
David
Hello
I ran the following code but I get different results
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadilloExtensions/sample.h>
using namespace Rcpp ;
// [[Rcpp::export]]
CharacterVector csample_char( CharacterVector x,
int size,
bool replace,
NumericVector prob = NumericVector::create()
) {
CharacterVector ret = RcppArmadillo::sample(x, size, replace, prob) ;
return ret ;
}
/*** R
N <- 10
set.seed(7)
sample.r <- sample(letters, N, replace=T)
print(sample.r)
set.seed(7)
sample.c <- csample_char(letters, N, replace=T)
print(sample.c)
print(identical(sample.r, sample.c))
*/
Here is what I get:
> N <- 10
> set.seed(7)
> sample.r <- sample(letters, N, replace=T)
> print(sample.r)
[1] "j" "s" "g" "b" "o" "z" "v" "h" "x" "c"
> set.seed(7)
> sample.c <- csample_char(letters, N, replace=T)
> print(sample.c)
[1] "z" "k" "d" "b" "g" "u" "i" "z" "e" "l"
> print(identical(sample.r, sample.c))
[1] FALSE
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.