Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using C API from Rcpp package #55

Open
slwu89 opened this issue Apr 22, 2021 · 7 comments
Open

using C API from Rcpp package #55

slwu89 opened this issue Apr 22, 2021 · 7 comments

Comments

@slwu89
Copy link

slwu89 commented Apr 22, 2021

Hello network team!

I am writing a package relying in C++ which is compiled and linked against using Rcpp. I'd like to use the C API of network to interact with "network" class objects within the C++ code, using the extern keyword to make sure the C++ code knows what C function to use, following an example similar to https://github.com/r-pkg-examples/rcpp-and-c. The "network" vignette remarks that the current version implements R's template for registering C routines, so I thought that adding the LinkingTo: network line in my package's DESCRIPTION and including the headers from "network" should work but compiling gives a multiple definition error: multiple definition ofnetRegisterFunctions'`.

My example package is here: https://github.com/slwu89/individual.network

I'd really appreciate any help anyone could provide about how to properly link to network. Thanks!

@CarterButts
Copy link
Contributor

Hi, @slwu89 . It's nice to see someone using this functionality - it was first built in ancient days of yore, and (despite being very fast!) ended up not being used. As such, it has not been actively maintained, and the R folks seem to have been making aggressive changes to how this stuff works that may have broken it. The upshot of this is that I will need to do some digging and look into it. I've not yet started playing with linking to the C backend from Rcpp (being only a recent and somewhat reluctant C++ user - Rcpp inlining was the "killer app" that started seducing me to the dark side), but that is something that would be very useful to support, so this seems like the time to figure it out. :-)

@knapply
Copy link
Contributor

knapply commented Apr 26, 2021

I modified the #includes to limit what gets pulled into /src/net.h: https://github.com/knapply/individual.network

Happy to PR, but you can get the gist by looking at the diff here: slwu89/individual.network@main...knapply:main

# remotes::install_github("knapply/individual.network")

m <- matrix(rbinom(25,1,.4),5,5)
diag(m) <- 0
g <- network::network(m, directed=FALSE)
g
#>  Network attributes:
#>   vertices = 5 
#>   directed = FALSE 
#>   hyper = FALSE 
#>   loops = FALSE 
#>   multiple = FALSE 
#>   bipartite = FALSE 
#>   total edges= 3 
#>     missing edges= 0 
#>     non-missing edges= 3 
#> 
#>  Vertex attribute names: 
#>     vertex.names 
#> 
#> No edge attributes

individual.network::rnbernexp_CPP(g, 0.5, 0.5, 0.5) # I just plugged in some args to confirm it runs...
#>  Network attributes:
#>   vertices = 5 
#>   directed = FALSE 
#>   hyper = FALSE 
#>   loops = FALSE 
#>   multiple = FALSE 
#>   bipartite = FALSE 
#>   FirstOnsetTime = 0.4029905 
#>   LastTerminationTime = 1.456397 
#>   total edges= 7 
#>     missing edges= 0 
#>     non-missing edges= 7 
#> 
#>  Vertex attribute names: 
#>     FirstOnsetTime LastTerminationTime vertex.names 
#> 
#>  Edge attribute names: 
#>     OnsetTime TerminationTime

@slwu89
Copy link
Author

slwu89 commented Apr 26, 2021

Hello @CarterButts and @knapply!

Thanks so much for the quick help, I really appreciate it. Fixing where the network headers should be included according to @knapply's help, I wrote a working minimal example package with an explanation of the steps required to use the C API from Rcpp code on a fork of the repo here:

https://github.com/slwu89/network/tree/example_rcpp_pkg/inst/examples/networkRcppExample

If you think it's useful I'd be happy to submit a PR.

@knapply
Copy link
Contributor

knapply commented Apr 28, 2021

Just my 2 cents: this seems more appropriate as a standalone repo -- maybe to point to from a vignette?

Another option to consider would be something analogous to Rcpp::Rcpp.package.skeleton()/RcppEigen::RcppEigen.package.skeleton()/RcppArmadillo::RcppArmadillo.package.skeleton().

image

I'm a huge fan of Rcpp (and coauthor {RcppSimdJson} with Dirk) -- @CarterButts, if you haven't considered it already, it'd be extremely appealing as a downstream {network} user to be able to tap into a network object class at the C++ level. This is super contrived, but this sort of behavior would be wildly convenient...

RcppNetwork.cpp:

#include <Rcpp.h>

// hypothetical RcppNetwork.hpp
namespace RcppNetwork {

class Network {
  Rcpp::List g;
  bool directed;

public:
  Network(const Rcpp::List g_) : g(g_) {
    const Rcpp::List gal = this->g["gal"];
    const Rcpp::LogicalVector directed = gal["directed"];
    this->directed = directed[0];
  };

  bool is_directed() const {
    return this->directed;
  }
};

} // namespace RcppNetwork
// hypothetical RcppNetwork.hpp



// [[Rcpp::export]]
bool is_directed(const Rcpp::List x) {
  const auto g = RcppNetwork::Network(x);
  return g.is_directed();
}


/*** R
m <- matrix(rbinom(25,1,.4),5,5)
g <- network::network(m, directed=FALSE)

is_directed(g)
*/
Rcpp::sourceCpp('~/r-projects/RcppNetwork.cpp')
##> m <- matrix(rbinom(25,1,.4),5,5)
##> g <- network::network(m, directed=FALSE)

##> is_directed(g)
##> [1] FALSE

@slwu89
Copy link
Author

slwu89 commented Apr 28, 2021

Sure @knapply, I have no strong opinions on where, if anywhere it should live. I was looking at what RcppProgress did for their "sample" packages https://github.com/kforner/rcpp_progress/tree/master/inst/examples , but it looks like the statenet org has room for sample packages.

Is your suggestion to use Rcpp Attributes to export some header from network that Rcpp users can easily include? I agree that would be wildly convenient, but also looks like a lot of refactoring work on yours/ @CarterButts end? I'd be happy to help in a few months, but for now the method in the networkRcppExample package has helped me get off the ground for using network in my project.

@knapply
Copy link
Contributor

knapply commented Apr 28, 2021

I'm just a guest here. It's totally up to @CarterButts and the Statnet team.

@slwu89
Copy link
Author

slwu89 commented Apr 28, 2021

Ah understood. Thanks for helping out another guest!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants