diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b137d00 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +pcalg-Ex.R +src/*.o +src/*.so +src/symbols.rds +*~ + diff --git a/NAMESPACE b/NAMESPACE index f9cefed..4899863 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -105,6 +105,7 @@ export(trueCov, binCItest, ida, idaFast, + idaFastOpt, legal.path, plotSG, pc.cons.intern, diff --git a/R/pcalg.R b/R/pcalg.R index 4f03b75..e17945d 100644 --- a/R/pcalg.R +++ b/R/pcalg.R @@ -3207,6 +3207,35 @@ idaFast <- function(x.pos, y.pos.set, mcov, graphEst) beta.hat } + ## Purpose: Estimate the causal effect of x.pos.set on each element in the + ## graph using the local method; graphEst and correlation matrix + ## have to be precomputed; orient + ## undirected edges at x in a way so that no new collider is + ## introduced; if there is an undirected edge between x and y, both directions are considered; + ## i.e., y might be partent of x in which case the effect is 0. + ## ---------------------------------------------------------------------- + ## Arguments: + ## - x.pos.set: + ## - mcov: Covariance matrix that was used to estimate graphEst + ## - graphEst: Fit of PC Algorithm (semidirected) + ## ---------------------------------------------------------------------- + ## Value: list of causal values; one list element (matrix) for each element of + ## x.pos.set + ## ---------------------------------------------------------------------- + ## Author: Paula Perez, Date: 17 Jan 2017 + +idaFastOpt <- function(x.pos.set,mcov,graphEst) +{ + if(missing(x.pos.set)){ + x.pos.set = 1:ncol(mcov) + } + adjmat <- as.matrix(wgtMatrix(graphEst)) + .Call("idaFastC",(x.pos.set - 1) ,mcov,adjmat) +} + + + + ## -> ../man/legal.path.Rd ## only called in qreach() with only 'c' varying legal.path <- function(a,b,c, amat) diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdc1a2a --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# Pcalg fork + +## Description + + This is a fork from the `R` package `pcalg` +that implements a `C++` optimization of the +function idaFast, idaFastOpt. Using `C++` together +with the `Armadillo` library instead of `R` improves the +performance already. On top of that, the new implementation +seems to have reduced the complexity of the algorithm (see +Details and Benchmarks). + +* **Patch file**: `dataOpt/patch_pcalg.txt` + + +### Details + +Given a *completed partially directed acyclic graph* `pdag`, and +a given node `x`, we identify the unique parents `uniq_pa` and the +ambiguous parents `amb_pa`. From the set of `amb_pa`, we direct them +in all possible ways (`2``|amb_pa|`) checking first that +they introduce no new colliders. This implementation differs with +the original implementation in how "all possible ways" are examined. + +* **Original code:** A loop from 1 to the number of elements +in `amb_pa`, `|amb_pa|` is executed, and the function, + + ``pa.tmp <- combn(amb_pa,i,simplify = TRUE)`` + + is called where `i` is the variable in the loop. All sets of size `i` in `amb_pa` +are obtained. For every set, all parents in it are directed towards +`x`, the ones not in it outwards. If the configuration does not introduce a new +collider, the causal effects are computed, nothing is done otherwise. + +* **Optimization:** A loop from 0 until `2``|amb_pa| - 1` is executed, +where binary representation of `i` (loop variable, `long int`) is sweeping +over the half posibilities. For every `i` we create two subsets +`pa_1` and `pa_2` complementary to each other. `pa_1` (`pa_2`) contains the `jth` element +of `amb_pa` if the `jth` bit of `i` is 1 (0). In that way, we have covered all +possibilities if we first set `pa_1` to be directed towards `x`, `pa_2` outwards, +check for colliders, compute causal effects and then do the same reversing the roles +of `pa_1` and `pa_2.` + + + +### Benchmarks + + Comparison of performance of `idaFast` (original function of the package) +versus our implementation, `idaFastOpt`. We have used real data and created **cpdag** of +100,200,500,1000,5000 nodes. `idaFast` and `idaFastOpt` have then been run on these +graphs on a Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz. In the graph below, we can see +the performance of the two functions, in a log-log scale. + +We see not only that the runtime is significantly reduced, but also, and +for the **cpdag** we were testing the functions on, `idaFast` seemed to scale like +`O(n``3``)` whereas `idaFastOpt` like `O(n``2``)`. Note that +the scaling is not generalizable to all types of graphs. For different input graphs, +one can expect a different complexity. Nevertheless, it seems that the new implementation +has reduced it. + + +
+ +## Usage + +``idaFastOpt(x.pos.set = 1:N, mcov = cov(subDat), graphEst = l$cpdag_graph)`` + + +* **Arguments:** + - `x.pos.set`: (integer vector) optional argument. + Nodes on which the causal effects are going to + be computed. If not passed, the function computes + the causal effects on all nodes. Note a vector of positions + of the target variables is not passed as an argument, in contrast + to `idaFast` since in this function all nodes are going to be + targets. + - `mcov`: covariance matrix that was used to estimate `graphEst` + - `graphEst`: estimated **cpdag** from the function `pc`. If the output of + `pc` is `pc.fit`, then the estimated **cpdag** can be obtained by + `pc.fit@graph`. + +* **Output:** + list of causal values; one list element (matrix) for each element of + `x.pos.set` + +## Tests + + In the folder `dataOpt`, one can find a code example in `run_idaFast.R`, + where both functions, `idaFast`, `idaFastOpt`, are run for the **cpdag**'s + contained in `dataOpt/skeletonfiles`, and a profiling is performed. + + + In the same folder, the script `benchmarks.R` creates the plot shown in this README.md + file. diff --git a/dataOpt/01-005-00_Ergebnis_Uebersicht.csv b/dataOpt/01-005-00_Ergebnis_Uebersicht.csv new file mode 100644 index 0000000..76b3b81 --- /dev/null +++ b/dataOpt/01-005-00_Ergebnis_Uebersicht.csv @@ -0,0 +1,101 @@ +Sample Batch CD40L BCR IGF CpG IL10 Myc Number Viability S SubG1 size total RNA +1 1 1 0 0 0 0 1 8,4 94,9 47,6 2,7 604 343,63 +2 1 0 1 0 0 0 0 5,4 94,2 12,3 10,2 462 106,82 +3 1 0 0 0 0 0 0 5,6 93,0 4,4 3,9 433 133,7 +4 1 0 0 0 0 0 1 8,4 94,6 43,0 4,0 577 226,45 +5 1 0 1 1 1 1 1 8,0 97,4 63,0 2,8 638 356,71 +6 1 1 1 1 1 1 1 8,8 96,4 59,2 2,3 656 383,64 +7 1 1 1 0 1 0 1 7,7 94,5 54,2 2,7 655 399,47 +8 1 1 0 0 1 1 0 8,3 95,2 45,3 1,9 586 188,31 +9 1 0,2 1 1 0 1 0 6,8 92,3 24,4 2,2 557 164,12 +10 1 0 0 0 1 1 0 6,3 95,9 41,4 2,2 574 225,71 +11 2 0 1 0 0 0 1 8,4 93,9 42,4 5,3 543 311,88 +12 2 0 0 1 0 0 0 6,0 93,9 7,0 5,7 479 103,66 +13 2 0 0 0 0 0 0 5,6 92,1 6,2 6,8 461 131,53 +14 2 0 0 0 0 0 1 8,6 95,0 37,0 5,4 550 277,7 +15 2 0 1 0,2 0,2 0 1 8,5 95,9 42,2 4,1 528 364,36 +16 2 1 0,2 0,2 0 0 1 8,0 95,3 38,5 5,9 497 341,34 +17 2 1 1 1 1 0,2 1 8,6 96,3 57,9 4,1 564 420,51 +18 2 0,2 0,2 0,2 0,2 0,2 0 6,5 95,6 28,0 6,6 526 178,34 +19 2 1 0,2 0 0 1 0 5,9 92,0 20,3 4,8 541 185,92 +20 2 0,2 1 0,2 0 0,2 0 5,6 93,5 16,5 9,0 509 157,58 +21 3 0 0 1 0 0 1 9,4 93,1 37,9 4,2 512 246,07 +22 3 0 0 0 1 0 0 6,2 95,4 24,9 2,2 594 176,59 +23 3 0 0 0 0 0 0 6,2 92,8 4,9 2,5 515 135,29 +24 3 0 0 0 0 0 1 8,3 92,9 36,6 3,7 612 232,25 +25 3 0,2 0,2 0,2 0 0 1 8,9 95,2 38,1 3,2 707 300,09 +26 3 0,2 1 0 0 1 1 7,8 91,6 43,5 1,9 658 306,57 +27 3 1 0 0 1 1 1 8,4 94,3 54,9 2,3 714 362,05 +28 3 0,2 1 0,2 1 0 0 6,2 92,3 38,2 1,4 638 213,57 +29 3 0 0 0 0,2 1 0 6,4 91,8 28,7 1,5 582 187,55 +30 3 0,2 1 0,2 0,2 0,2 0 6,1 94,0 27,5 2,2 624 189,19 +31 4b 0 0 0 1 0 1 9,6 93,3 42,5 4,0 595 388,83 +32 4b 0 0 0 0 1 0 6,8 93,0 12,8 7,3 473 143,68 +33 4b 0 0 0 0 0 0 6,7 93,7 5,8 7,4 438 129,82 +34 4b 0 0 0 0 0 1 8,0 93,1 29,4 5,2 559 260,61 +35 4b 0,2 1 0,2 0,2 0,2 1 8,7 92,1 37,4 4,1 585 342,67 +36 4b 1 1 0,2 0,2 0 1 7,7 92,7 38,6 4,7 593 316,21 +37 4b 0,2 0 1 0,2 0 1 7,8 91,9 36,4 4,7 561 307,76 +38 4b 1 1 0,2 0,2 0 0 6,6 94,0 20,9 6,1 523 176,84 +39 4b 0,2 1 1 0,2 0 0 6,6 93,2 23,2 7,4 504 183,84 +40 4b 1 0 1 1 0,2 0 7,5 93,3 40,2 3,9 531 226,45 +41 5 0 0 0 0 1 1 8,2 93,5 38,0 5,0 488 300,33 +42 5 1 0 0 0 0 0 6,2 92,8 9,9 4,1 503 132,34 +43 5 0 0 0 0 0 0 6,0 93,0 4,8 4,6 498 128,24 +44 5 0 0 0 0 0 1 7,9 92,6 34,7 5,7 577 244,87 +45 5 0 0 0 1 1 1 9,7 92,3 49,0 3,7 535 269,28 +46 5 0,2 0,2 0 1 1 1 9,9 94,6 53,2 3,5 556 253,46 +47 5 0,2 0 0,2 1 0 1 9,2 93,0 40,7 3,3 582 262,22 +48 5 0,2 0,2 0,2 0 0 0 6,4 94,3 9,1 4,0 517 135,09 +49 5 0,2 1 0 0 1 0 6,5 93,6 16,9 3,7 534 151,39 +50 5 0,2 0 0,2 1 0 0 7,0 93,6 23,0 3,6 561 141,69 +51 6 1 0 0 0 0 1 8,1 96,4 37,8 2,9 555 283,87 +52 6 0 1 0 0 0 0 6,2 94,5 10,3 5,6 480 143,37 +53 6 0 0 0 0 0 0 6,6 95,2 4,3 4,2 449 130,24 +54 6 0 0 0 0 0 1 7,8 93,9 32,2 3,8 563 272,4 +55 6 0 0 0 0,2 1 1 9,5 94,3 49,6 3,1 579 319,45 +56 6 0,2 0,2 0,2 1 1 1 8,7 95,4 54,7 2,7 599 318,45 +57 6 0,2 1 1 0 0 1 9,4 93,2 36,8 4,1 547 241,83 +58 6 1 1 0 1 1 0 8,0 96,4 44,4 2,3 549 192,91 +59 6 1 1 1 1 1 0 7,4 93,2 45,5 2,1 572 225,32 +60 6 0,2 0 1 0,2 1 0 7,3 93,8 36,5 3,0 537 169,41 +61 7 0 1 0 0 0 1 9,0 92,3 31,2 3,1 564 283,97 +62 7 0 0 1 0 0 0 6,2 95,4 3,5 1,8 560 122,47 +63 7 0 0 0 0 0 0 6,2 93,2 3,5 2,9 555 143,99 +64 7 0 0 0 0 0 1 7,7 93,8 26,4 6,0 498 256,14 +65 7 0,2 1 1 0 1 1 10,3 91,5 31,2 4,0 582 223,09 +66 7 1 0,2 0 0 1 1 9,6 93,8 29,7 4,8 591 219,84 +67 7 1 1 0 1 1 1 8,4 93,9 51,6 1,9 610 323,49 +68 7 0 0,2 0 0,2 1 0 6,8 93,4 21,7 1,5 677 153,95 +69 7 1 1 1 1 0,2 0 7,2 95,6 34,1 1,5 662 247,39 +70 7 1 1 0 1 0 0 6,7 94,5 32,4 0,6 642 162,63 +71 8 0 0 1 0 0 1 8,9 94,6 43,5 2,9 623 230,06 +72 8 0 0 0 1 0 0 6,0 93,0 28,4 4,3 564 160,84 +73 8 0 0 0 0 0 0 6,0 94,4 7,7 6,5 504 139,93 +74 8 0 0 0 0 0 1 9,6 97,0 39,1 5,2 610 270,27 +75 8 0 0,2 0 0,2 1 1 9,8 97,0 43,6 4,4 657 295,49 +76 8 0,2 0,2 0,2 0,2 0,2 1 9,4 98,1 43,2 4,0 644 289,11 +77 8 0,2 1 0,2 0 0,2 1 9,0 95,8 46,3 4,5 651 316,74 +78 8 0 1 1 1 1 0 7,0 97,5 42,2 4,9 607 219,33 +79 8 0,2 0,2 0 1 1 0 7,5 96,2 39,0 4,4 633 205,68 +80 8 0,2 0,2 0,2 1 1 0 7,2 95,2 42,7 4,0 623 246,05 +81 9 0 0 0 1 0 1 8,4 94,0 39,1 6,9 611 347,9 +82 9 0 0 0 0 1 0 5,7 95,0 12,7 4,3 514 159,7 +83 9 0 0 0 0 0 0 6,3 95,9 5,0 6,1 476 144 +84 9 0 0 0 0 0 1 7,9 92,3 32,2 5,4 578 271,96 +85 9 0,2 1 1 0,2 0 1 8,8 95,1 29,5 5,4 621 315,52 +86 9 0,2 0,2 1 0 0,2 1 8,7 93,5 35,2 4,6 600 293,6 +87 9 1 0 1 1 0,2 1 8,4 95,5 46,4 4,4 644 319,79 +88 9 0 1 0,2 0,2 0 0 5,7 95,5 27,7 6,2 521 150,34 +89 9 0,2 0,2 1 0 0,2 0 6,8 94,5 17,2 4,2 538 141,63 +90 9 1 0 1 0,2 0 0 6,6 95,3 28,0 3,7 555 155,49 +91 10 0 0 0 0 1 1 8,7 93,3 34,6 7,1 661 254,27 +92 10 1 0 0 0 0 0 6,3 95,5 7,7 4,7 539 129,75 +93 10 0 0 0 0 0 0 6,2 94,5 3,9 8,8 530 142,34 +94 10 0 0 0 0 0 1 8,5 91,9 29,9 7,6 618 217,24 +95 10 1 0 1 0,2 0 1 9,0 93,4 42,0 3,6 686 256,26 +96 10 0,2 1 0,2 1 0 1 8,1 95,7 48,0 4,2 743 295,8 +97 10 0,2 0 1 0,2 1 1 9,1 94,1 47,7 3,5 721 294,99 +98 10 0,2 1 1 0 0 0 6,2 92,8 14,2 9,0 545 185,25 +99 10 0,2 0 1 0,2 0 0 6,5 95,1 25,4 5,0 560 157,29 +100 10 1 0,2 0,2 0 0 0 6,3 92,1 10,3 5,6 540 139,9 diff --git a/dataOpt/benchmarks.R b/dataOpt/benchmarks.R new file mode 100644 index 0000000..1123aef --- /dev/null +++ b/dataOpt/benchmarks.R @@ -0,0 +1,51 @@ +# This script creates a graph with the timings of idaFast +timings <- read.csv("timings.csv", stringsAsFactors=FALSE) + + +fast <- timings[which(timings$optimized==TRUE & timings$Myc == "Low"), ] +slow <- timings[which(timings$optimized==FALSE & timings$Myc == "Low"), ] + + + +png("timings.png", width=400, height=400, units ="px") + +r_slow <- lm(log(slow[,2]) ~ log(slow[,1]) ) +r_fast <- lm(log(fast[,2]) ~ log(fast[,1]) ) + + +plot(slow[,1:2],col="red", xlab = "Anzahl von Genen", + ylab = " Laufzeit (Sekunden)", pch=16, cex=1.4, xaxt= "n") +points(fast[,1:2],col="blue",pch= 8, lwd=2) + +axis(1,slow[,1],slow[,1]) +legend("topleft",legend = c("urspruengliche Funktion", + "optimierte Funktion"), pch = c(16,8), + pt.cex = c(1.4,1), pt.lwd=c(1,2), col = c("red","blue")) + #lwd= c(1,2), cex=c(1.4,1),col = c("red","blue")) + +mtext("200", at =c(250), line = -20.55 ) + +dev.off() + +png("timings_log.png", width=400, height=400, units ="px") + +x <- c(1:5000) +y <- x^(r_slow$coefficients[2])*exp(r_slow$coefficients[1]) +plot(slow[,1:2],col="red", xlab = "Number of genes, n", + ylab = " Time, t (sec)", ylim = c(0.01,50000), pch=16, cex=1.4, yaxt= "n", log = "xy") +lines(x,y,lty=2, col="lightgray",lwd=2) +x <- c(1:5000) +y <- x^(r_fast$coefficients[2])*exp(r_fast$coefficients[1]) +lines(x,y,lty=2, col="lightgray",lwd=2) +points(fast[,1:2],col="blue",pch= 8, lwd=2) +axis(2,c(0.01,0.1,1,10,100,1000,10000),c("0.01","0.1","1","10","100","1000","10000"), las = 2) +legend("topleft",legend = c("idaFast", + "idaFastOpt"), pch = c(16,8), + pt.cex = c(1.4,1), pt.lwd=c(1,2), col = c("red","blue")) + #lwd= c(1,2), cex=c(1.4,1),col = c("red","blue")) +slope <- sprintf("%.02f", r_slow$coefficients[2]) +text(200,10,bquote( 't ~ '~ O(n^.(slope)) ),srt=38) +slope <- sprintf("%.02f", r_fast$coefficients[2]) +text(200,0.17,bquote( 't ~ '~ O(n^.(slope)) ), srt=25) + +dev.off() diff --git a/dataOpt/patch_pcalg.txt b/dataOpt/patch_pcalg.txt new file mode 100644 index 0000000..815244b --- /dev/null +++ b/dataOpt/patch_pcalg.txt @@ -0,0 +1,348 @@ +Index: src/cpdag.cpp +=================================================================== +--- src/cpdag.cpp (revision 0) ++++ src/cpdag.cpp (revision 0) +@@ -0,0 +1,189 @@ ++/* This program is free software: you can redistribute it and/or modify ++* it under the terms of the GNU General Public License as published by ++* the Free Software Foundation, either version 2 of the License, or ++* (at your option) any later version. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License ++* along with this program. If not, see . ++* ++*/ ++ ++#include "pcalg/cpdag.hpp" ++ ++//Constructor ++cpdag::cpdag(arma::sp_imat adjmat_input, arma::mat covmat_input): ++ adjmat(adjmat_input), covmat(covmat_input) { ++ nodes = adjmat.n_rows; ++ skeleton = (adjmat + adjmat.t()); ++ unique = (adjmat - adjmat.t()); ++ for(arma::uword i=0; i1) skeleton(i,j)=1; ++ if(unique(i,j)<0) unique(i,j)=0; ++ } ++ } ++ ambiguous = adjmat - unique ; ++ // Sparse matrices are sorted by columns, so we ++ // have to take the counterintuitive convention ++ // of working with the transpose matrices. ++ unique_t = unique.t(); ++} ++ ++ ++ ++// idaFast as it is in the R function ++arma::mat cpdag::idaFast(uint32_t x ){ ++ //std::cout << "idaFast: computation of causal effects.\n" ; ++ // Las sparse matrices estan ordenada por columnas ++ // asi que hemos tomado la traspuesta arriba. ++ arma::mat beta; ++ arma::irowvec uniq_pa, amb_pa; ++ uniq_pa.set_size(nodes); ++ amb_pa.set_size(nodes); ++ arma::uword p = 0; ++ for (uint32_t col=0; col 64){ ++ printf ("The number of ambiguous parents is too high"); ++ exit (EXIT_FAILURE); ++ } ++ arma::irowvec amb_pa_1, amb_pa_2;% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% + ++ arma::uword n = amb_pa.size(); ++ uint64_t L = (1 << (n-1)); ++ for (uint64_t bits = 0; bits < L; bits++){ ++ directArrows(amb_pa_1,amb_pa_2,amb_pa,bits,n); ++ if( !hasNewCollider(uniq_pa,amb_pa_1,amb_pa_2,x) ){ ++ beta.insert_rows(cbeta++,getCausal(uniq_pa,amb_pa_1,x)); ++ } ++ if( !hasNewCollider(uniq_pa,amb_pa_2,amb_pa_1,x) ){ ++ beta.insert_rows(cbeta++,getCausal(uniq_pa,amb_pa_2,x)); ++ } ++ } ++ } ++ return (beta.t()); ++} ++ ++ ++bool cpdag::hasNewCollider(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, ++ arma::irowvec amb_pa_f, arma::uword x){ ++ arma::irowvec::iterator uniqst, uniqen, amb_tst,amb_ten, amb_fst, amb_fen; ++ uniqst = uniq_pa.begin(); uniqen = uniq_pa.end(); ++ amb_tst = amb_pa_t.begin(); amb_ten = amb_pa_t.end(); ++ amb_fst = amb_pa_f.begin(); amb_fen = amb_pa_f.end(); ++ if ( amb_pa_t.size() > 0 ){ ++ // Check whether all amb_pa_t and uniq_pa are connected. If not --> collider. ++ if ( uniq_pa.size() > 0 ){ ++ for (arma::irowvec::iterator it1 = uniqst; it1 < uniqen; it1++){ ++ for (arma::irowvec::iterator it2=amb_tst; it2 < amb_ten; it2++){ ++ if ( skeleton((*it1),(*it2)) == 0 ) return true; ++ } ++ } ++ } ++ // Check whether all amb_pa_t are connected among each other. If not --> collider. ++ if ( amb_pa_t.size() > 1 ){ ++ for ( arma::irowvec::iterator it1=amb_tst; it1 < amb_ten; it1++ ){ ++ for ( arma::irowvec::iterator it2=it1+1; it2 < amb_ten; it2++ ){ ++ if ( skeleton((*it1),(*it2)) == 0 ) return true; ++ } ++ } ++ } ++ } ++ // if any of the uniq parents of amb_pa_f is NOT directly connected to x --> collider. ++ if ( amb_pa_f.size() > 0 ){ ++ arma::irowvec papa; ++ papa.set_size(nodes); ++ arma::uword p=0; ++ for (arma::uword i = 0; i < nodes; i++ ){ ++ if( i != x ){ ++ for (arma::irowvec::iterator it=amb_fst; it < amb_fen; it++){ ++ if( unique((*it),i) ){ ++ papa[p++] = i; break; ++ } ++ } ++ } ++ } ++ papa.resize(p); ++ if (p > 0){ ++ for (arma::irowvec::iterator it=papa.begin(); it < papa.end(); it++){ ++ if( skeleton(x,(*it)) == 0 ) return true; ++ } ++ } ++ } ++ return false; ++} ++ ++arma::rowvec cpdag::getCausal(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, arma::uword x){ ++ arma::uword n_uniq, n_amb, n_all; ++ n_uniq = uniq_pa.size(); ++ n_amb = amb_pa_t.size(); ++ n_all = n_uniq + n_amb + 1; ++ arma::irowvec all_pa; ++ all_pa.set_size(n_all); ++ all_pa(0) = x; ++ if ( n_uniq > 0) memcpy(all_pa.begin()+ 1, uniq_pa.begin(),n_uniq*sizeof(long)); ++ if ( n_amb > 0) memcpy(all_pa.begin()+ n_uniq + 1, amb_pa_t.begin(),n_amb*sizeof(long)); ++ arma::mat A,Y,M; ++ A.set_size(n_all,n_all); ++ Y.set_size(n_all,nodes); ++ arma::irowvec::iterator start = all_pa.begin(); ++ arma::irowvec::iterator end = all_pa.end(); ++ for (arma::irowvec::iterator it1 = start ; it1 < end; it1++){ ++ arma::uword row = it1-start; ++ Y.row(row) = covmat.row((*it1)); ++ for (arma::irowvec::iterator it2 = start ; it2 < end; it2++){ ++ arma::uword col = it2 - start; ++ A(row,col) = covmat((*it1),(*it2)); ++ } ++ } ++ M = solve(A,Y); ++ for (arma::irowvec::iterator it1 = start+1 ; it1 < end; it1++){ ++ M(0,(*it1)) = 0.0; ++ } ++ return M.row(0); ++} ++ ++ ++// Divide the vector amb_pa into two vectors, following the partition k ++void cpdag::directArrows(arma::irowvec &pa_1, arma::irowvec &pa_2, ++ arma::irowvec amb_pa, uint64_t bits, arma::uword n){ ++ uint8_t i, idx1, idx2; ++ uint8_t k; ++ idx1 = 0; idx2=0; ++ k = __builtin_popcount(bits); ++ pa_1.resize(k); ++ pa_2.resize(n-k); ++ for (i=0; i < n ; i++ ){ ++ if ( bits & (1 << i) ){ ++ pa_1(idx1++) = amb_pa(i); ++ } else { ++ pa_2(idx2++) = amb_pa(i); ++ } ++ } ++} ++ +Index: src/gies.cpp +=================================================================== +--- src/gies.cpp (revision 407) ++++ src/gies.cpp (working copy) +@@ -21,6 +21,7 @@ + #include "pcalg/constraint.hpp" + #include "pcalg/score.hpp" + #include "pcalg/greedy.hpp" ++#include "pcalg/cpdag.hpp" + #define DEFINE_GLOBAL_DEBUG_STREAM + #include "pcalg/gies_debug.hpp" + +@@ -645,3 +646,23 @@ + END_RCPP + } + ++RcppExport SEXP idaFastC(SEXP xpos, SEXP argMcov, ++ SEXP argAdjMatrix) ++{ ++ // Exception handling ++ BEGIN_RCPP ++ arma::mat covmat = (Rcpp::as(argMcov)); ++ arma::irowvec x = Rcpp::as(xpos); ++ arma::uword N = x.n_elem; ++ arma::mat adjmat_tmp = (Rcpp::as(argAdjMatrix)); ++ arma::sp_imat adjmat; ++ adjmat = arma::conv_to::from(adjmat_tmp); ++ cpdag graph_pd(adjmat,covmat); ++ Rcpp::List to_return(N); ++ arma::uword i=0; ++ for (arma::irowvec::iterator it=x.begin(); it < x.end(); it++){ ++ to_return[i++] = graph_pd.idaFast(*it); ++ } ++ return to_return; ++ END_RCPP ++} +Index: NAMESPACE +=================================================================== +--- NAMESPACE (revision 407) ++++ NAMESPACE (working copy) +@@ -105,6 +105,7 @@ + binCItest, + ida, + idaFast, ++ idaFastOpt, + legal.path, + plotSG, + pc.cons.intern, +Index: R/pcalg.R +=================================================================== +--- R/pcalg.R (revision 407) ++++ R/pcalg.R (working copy) +@@ -3207,6 +3207,15 @@ + beta.hat + } + ++idaFastOpt <- function(x.pos.set,mcov,graphEst) ++{ ++ if(missing(x.pos.set)){ ++ x.pos.set = 1:ncol(mcov) ++ } ++ adjmat <- as.matrix(wgtMatrix(graphEst)) ++ .Call("idaFastC",(x.pos.set - 1) ,mcov,adjmat) ++} ++ + ## -> ../man/legal.path.Rd + ## only called in qreach() with only 'c' varying + legal.path <- function(a,b,c, amat) +Index: inst/include/pcalg/cpdag.hpp +=================================================================== +--- inst/include/pcalg/cpdag.hpp (revision 0) ++++ inst/include/pcalg/cpdag.hpp (revision 0) +@@ -0,0 +1,45 @@ ++/* This program is free software: you can redistribute it and/or modify ++* it under the terms of the GNU General Public License as published by ++* the Free Software Foundation, either version 2 of the License, or ++* (at your option) any later version. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License ++* along with this program. If not, see . ++* ++*/ ++ ++#ifndef DIFFEXP_H ++#define DIFFEXP_H ++ ++#include ++#include ++#include ++ ++ ++class cpdag{ ++ private: ++ arma::uword nodes; ++ arma::mat covmat; // Covariance matrix ++ arma::sp_imat adjmat; // Adjacency matrix CPDAG ++ arma::sp_imat skeleton; // Undirected adjacency matrix ++ arma::sp_imat ambiguous; // Ambiguous parents ++ arma::sp_imat unique; // Unique parents ++ arma::sp_imat unique_t; // Unique parents transposed (used for computations) ++ public: ++ cpdag(arma::sp_imat adjmat_input, arma::mat covmat_input); ++ ~cpdag() {} ++ arma::mat idaFast(uint32_t x); ++ bool hasNewCollider(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, ++ arma::irowvec amb_pa_f, arma::uword x); ++ arma::rowvec getCausal(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, arma::uword x); ++ void directArrows(arma::irowvec &pa_1, arma::irowvec &pa_2, ++ arma::irowvec amb_pa, uint64_t k, arma::uword n); ++ ++}; ++#endif //cpdag.h ++ diff --git a/dataOpt/run_idaFast.R b/dataOpt/run_idaFast.R new file mode 100644 index 0000000..3cdd3ee --- /dev/null +++ b/dataOpt/run_idaFast.R @@ -0,0 +1,54 @@ +# We run original idaFast on our skeleton files +require(devtools) +require(graph) +load_all("../../pcalg/", + quiet=T,reset=T,export_all=T) +message(date()," >> Rversion: ") +print(version) + +Ngenes <- c(100, 200, 500, 1000, 2000, 5000) +Ngenes <- c(200) +############################################# + +# Read the design, so that we can separate Myc high from Myc Low +designFile <- paste0("01-005-00_Ergebnis_Uebersicht.csv") +descr.mat <- read.csv(designFile,header = TRUE, + sep = "\t", dec = ",",row.names=1) +# get samples with Myc low and Myc high +myc_samples <- data.frame( High=as.numeric(rownames(descr.mat[descr.mat$Myc==1,])), Low = as.numeric(rownames(descr.mat[descr.mat$Myc==0,]))) + + +tiempoOPT <- c() +tiempo <- c() +i = 1 +for (Ng in Ngenes){ + bigVarGenes <- readRDS(paste0("var_genes/Ng",Ng,"alpha0p5.rds")) + for (myc in c("Low","High")){ + skel_file <- paste0("skeleton_files/Ng", + Ng,".it001.Myc",myc,".alpha0p5.rds") + + MycHighLow <- bigVarGenes[myc_samples[,myc], ] + l <- readRDS(skel_file) + subDat <- MycHighLow[l$ind,] + Ns <- nrow(MycHighLow) # number of samples + subSize <- floor(Ns/2) + tiempoOPT <- c(tiempoOPT,Sys.time()) + message(Sys.time()) + mysol <- idaFastOpt(mcov=cov(subDat),graphEst=l$cpdag_graph) + message(Sys.time()) + tiempoOPT[i] <- Sys.time() - tiempoOPT[i] + tiempo <- c(tiempo,Sys.time()) + oldsol <- list() + for (j in 1:Ng){ + oldsol[[j]] <- idaFast(j,1:Ng,cov(subDat),l$cpdag_graph) + } + message(Sys.time()) + tiempo[i] <- Sys.time() - tiempo[i] + cat(Ng," Myc",myc,"idaFastOpt:", tiempoOPT[i], + attr(tiempoOPT[i],"units"),"\n") + cat(Ng," Myc",myc,"idaFast:", tiempo[i], + attr(tiempo[i],"units"),"\n") + i <- i + 1 + } +} + diff --git a/dataOpt/skeleton_files/Ng100.it001.MycHigh.alpha0p5.rds b/dataOpt/skeleton_files/Ng100.it001.MycHigh.alpha0p5.rds new file mode 100644 index 0000000..c80bcb8 Binary files /dev/null and b/dataOpt/skeleton_files/Ng100.it001.MycHigh.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng100.it001.MycLow.alpha0p5.rds b/dataOpt/skeleton_files/Ng100.it001.MycLow.alpha0p5.rds new file mode 100644 index 0000000..c137a3b Binary files /dev/null and b/dataOpt/skeleton_files/Ng100.it001.MycLow.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng1000.it001.MycHigh.alpha0p5.rds b/dataOpt/skeleton_files/Ng1000.it001.MycHigh.alpha0p5.rds new file mode 100644 index 0000000..00cd76f Binary files /dev/null and b/dataOpt/skeleton_files/Ng1000.it001.MycHigh.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng1000.it001.MycLow.alpha0p5.rds b/dataOpt/skeleton_files/Ng1000.it001.MycLow.alpha0p5.rds new file mode 100644 index 0000000..837175d Binary files /dev/null and b/dataOpt/skeleton_files/Ng1000.it001.MycLow.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng200.it001.MycHigh.alpha0p5.rds b/dataOpt/skeleton_files/Ng200.it001.MycHigh.alpha0p5.rds new file mode 100644 index 0000000..b75b15d Binary files /dev/null and b/dataOpt/skeleton_files/Ng200.it001.MycHigh.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng200.it001.MycLow.alpha0p5.rds b/dataOpt/skeleton_files/Ng200.it001.MycLow.alpha0p5.rds new file mode 100644 index 0000000..732e611 Binary files /dev/null and b/dataOpt/skeleton_files/Ng200.it001.MycLow.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng2000.it001.MycHigh.alpha0p5.rds b/dataOpt/skeleton_files/Ng2000.it001.MycHigh.alpha0p5.rds new file mode 100644 index 0000000..6b5b29e Binary files /dev/null and b/dataOpt/skeleton_files/Ng2000.it001.MycHigh.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng2000.it001.MycLow.alpha0p5.rds b/dataOpt/skeleton_files/Ng2000.it001.MycLow.alpha0p5.rds new file mode 100644 index 0000000..e222380 Binary files /dev/null and b/dataOpt/skeleton_files/Ng2000.it001.MycLow.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng500.it001.MycHigh.alpha0p5.rds b/dataOpt/skeleton_files/Ng500.it001.MycHigh.alpha0p5.rds new file mode 100644 index 0000000..bab4766 Binary files /dev/null and b/dataOpt/skeleton_files/Ng500.it001.MycHigh.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng500.it001.MycLow.alpha0p5.rds b/dataOpt/skeleton_files/Ng500.it001.MycLow.alpha0p5.rds new file mode 100644 index 0000000..13d8d01 Binary files /dev/null and b/dataOpt/skeleton_files/Ng500.it001.MycLow.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng5000.it001.MycHigh.alpha0p5.rds b/dataOpt/skeleton_files/Ng5000.it001.MycHigh.alpha0p5.rds new file mode 100644 index 0000000..6e27996 Binary files /dev/null and b/dataOpt/skeleton_files/Ng5000.it001.MycHigh.alpha0p5.rds differ diff --git a/dataOpt/skeleton_files/Ng5000.it001.MycLow.alpha0p5.rds b/dataOpt/skeleton_files/Ng5000.it001.MycLow.alpha0p5.rds new file mode 100644 index 0000000..ab192e2 Binary files /dev/null and b/dataOpt/skeleton_files/Ng5000.it001.MycLow.alpha0p5.rds differ diff --git a/dataOpt/timings_log.png b/dataOpt/timings_log.png new file mode 100644 index 0000000..fd6ada1 Binary files /dev/null and b/dataOpt/timings_log.png differ diff --git a/dataOpt/timings_log_Low.png b/dataOpt/timings_log_Low.png new file mode 100644 index 0000000..3f132f2 Binary files /dev/null and b/dataOpt/timings_log_Low.png differ diff --git a/dataOpt/var_genes/Ng1000alpha0p5.rds b/dataOpt/var_genes/Ng1000alpha0p5.rds new file mode 100644 index 0000000..61b65ea Binary files /dev/null and b/dataOpt/var_genes/Ng1000alpha0p5.rds differ diff --git a/dataOpt/var_genes/Ng100alpha0p5.rds b/dataOpt/var_genes/Ng100alpha0p5.rds new file mode 100644 index 0000000..551df35 Binary files /dev/null and b/dataOpt/var_genes/Ng100alpha0p5.rds differ diff --git a/dataOpt/var_genes/Ng2000alpha0p5.rds b/dataOpt/var_genes/Ng2000alpha0p5.rds new file mode 100644 index 0000000..ada5329 Binary files /dev/null and b/dataOpt/var_genes/Ng2000alpha0p5.rds differ diff --git a/dataOpt/var_genes/Ng200alpha0p5.rds b/dataOpt/var_genes/Ng200alpha0p5.rds new file mode 100644 index 0000000..71e8201 Binary files /dev/null and b/dataOpt/var_genes/Ng200alpha0p5.rds differ diff --git a/dataOpt/var_genes/Ng5000alpha0p5.rds b/dataOpt/var_genes/Ng5000alpha0p5.rds new file mode 100644 index 0000000..0bd804f Binary files /dev/null and b/dataOpt/var_genes/Ng5000alpha0p5.rds differ diff --git a/dataOpt/var_genes/Ng500alpha0p5.rds b/dataOpt/var_genes/Ng500alpha0p5.rds new file mode 100644 index 0000000..d8a830e Binary files /dev/null and b/dataOpt/var_genes/Ng500alpha0p5.rds differ diff --git a/inst/include/pcalg/cpdag.hpp b/inst/include/pcalg/cpdag.hpp new file mode 100644 index 0000000..ffb76cb --- /dev/null +++ b/inst/include/pcalg/cpdag.hpp @@ -0,0 +1,45 @@ +/* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +*/ + +#ifndef DIFFEXP_H +#define DIFFEXP_H + +#include +#include +#include + + +class cpdag{ + private: + arma::uword nodes; + arma::mat covmat; // Covariance matrix + arma::sp_imat adjmat; // Adjacency matrix CPDAG + arma::sp_imat skeleton; // Undirected adjacency matrix + arma::sp_imat ambiguous; // Ambiguous parents + arma::sp_imat unique; // Unique parents + arma::sp_imat unique_t; // Unique parents transposed (used for computations) + public: + cpdag(arma::sp_imat adjmat_input, arma::mat covmat_input); + ~cpdag() {} + arma::mat idaFast(uint32_t x); + bool hasNewCollider(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, + arma::irowvec amb_pa_f, arma::uword x); + arma::rowvec getCausal(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, arma::uword x); + void directArrows(arma::irowvec &pa_1, arma::irowvec &pa_2, + arma::irowvec amb_pa, uint64_t k, arma::uword n); + +}; +#endif //cpdag.h + diff --git a/src/cpdag.cpp b/src/cpdag.cpp new file mode 100644 index 0000000..ab4aef1 --- /dev/null +++ b/src/cpdag.cpp @@ -0,0 +1,191 @@ +/* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +*/ + +#include "pcalg/cpdag.hpp" + +//Constructor +cpdag::cpdag(arma::sp_imat adjmat_input, arma::mat covmat_input): + adjmat(adjmat_input), covmat(covmat_input) { + nodes = adjmat.n_rows; + skeleton = (adjmat + adjmat.t()); + unique = (adjmat - adjmat.t()); + for(arma::uword i=0; i1) skeleton(i,j)=1; + if(unique(i,j)<0) unique(i,j)=0; + } + } + ambiguous = adjmat - unique ; + // Sparse matrices are sorted by columns, so we + // have to take the counterintuitive convention + // of working with the transpose matrices. + unique_t = unique.t(); +} + + + +// idaFast as it is in the R function +arma::mat cpdag::idaFast(uint32_t x ){ + //std::cout << "idaFast: computation of causal effects.\n" ; + // Las sparse matrices estan ordenada por columnas + // asi que hemos tomado la traspuesta arriba. + arma::mat beta; + arma::irowvec uniq_pa, amb_pa; + uniq_pa.set_size(nodes); + amb_pa.set_size(nodes); + arma::uword p = 0; + // Count the number of unambiguous parents + for (uint32_t col=0; col 64){ + printf ("The number of ambiguous parents is too high"); + exit (EXIT_FAILURE); + } + arma::irowvec amb_pa_1, amb_pa_2; + arma::uword n = amb_pa.size(); + uint64_t L = (1 << (n-1)); + for (uint64_t bits = 0; bits < L; bits++){ + directArrows(amb_pa_1,amb_pa_2,amb_pa,bits,n); + if( !hasNewCollider(uniq_pa,amb_pa_1,amb_pa_2,x) ){ + beta.insert_rows(cbeta++,getCausal(uniq_pa,amb_pa_1,x)); + } + if( !hasNewCollider(uniq_pa,amb_pa_2,amb_pa_1,x) ){ + beta.insert_rows(cbeta++,getCausal(uniq_pa,amb_pa_2,x)); + } + } + } + return (beta.t()); +} + + +bool cpdag::hasNewCollider(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, + arma::irowvec amb_pa_f, arma::uword x){ + arma::irowvec::iterator uniqst, uniqen, amb_tst,amb_ten, amb_fst, amb_fen; + uniqst = uniq_pa.begin(); uniqen = uniq_pa.end(); + amb_tst = amb_pa_t.begin(); amb_ten = amb_pa_t.end(); + amb_fst = amb_pa_f.begin(); amb_fen = amb_pa_f.end(); + if ( amb_pa_t.size() > 0 ){ + // Check whether all amb_pa_t and uniq_pa are connected. If not --> collider. + if ( uniq_pa.size() > 0 ){ + for (arma::irowvec::iterator it1 = uniqst; it1 < uniqen; it1++){ + for (arma::irowvec::iterator it2=amb_tst; it2 < amb_ten; it2++){ + if ( skeleton((*it1),(*it2)) == 0 ) return true; + } + } + } + // Check whether all amb_pa_t are connected among each other. If not --> collider. + if ( amb_pa_t.size() > 1 ){ + for ( arma::irowvec::iterator it1=amb_tst; it1 < amb_ten; it1++ ){ + for ( arma::irowvec::iterator it2=it1+1; it2 < amb_ten; it2++ ){ + if ( skeleton((*it1),(*it2)) == 0 ) return true; + } + } + } + } + // if any of the uniq parents of amb_pa_f is NOT directly connected to x --> collider. + if ( amb_pa_f.size() > 0 ){ + arma::irowvec papa; + papa.set_size(nodes); + arma::uword p=0; + for (arma::uword i = 0; i < nodes; i++ ){ + if( i != x ){ + for (arma::irowvec::iterator it=amb_fst; it < amb_fen; it++){ + if( unique((*it),i) ){ + papa[p++] = i; break; + } + } + } + } + papa.resize(p); + if (p > 0){ + for (arma::irowvec::iterator it=papa.begin(); it < papa.end(); it++){ + if( skeleton(x,(*it)) == 0 ) return true; + } + } + } + return false; +} + +arma::rowvec cpdag::getCausal(arma::irowvec uniq_pa, arma::irowvec amb_pa_t, arma::uword x){ + arma::uword n_uniq, n_amb, n_all; + n_uniq = uniq_pa.size(); + n_amb = amb_pa_t.size(); + n_all = n_uniq + n_amb + 1; + arma::irowvec all_pa; + all_pa.set_size(n_all); + all_pa(0) = x; + if ( n_uniq > 0) memcpy(all_pa.begin()+ 1, uniq_pa.begin(),n_uniq*sizeof(long)); + if ( n_amb > 0) memcpy(all_pa.begin()+ n_uniq + 1, amb_pa_t.begin(),n_amb*sizeof(long)); + arma::mat A,Y,M; + A.set_size(n_all,n_all); + Y.set_size(n_all,nodes); + arma::irowvec::iterator start = all_pa.begin(); + arma::irowvec::iterator end = all_pa.end(); + for (arma::irowvec::iterator it1 = start ; it1 < end; it1++){ + arma::uword row = it1-start; + Y.row(row) = covmat.row((*it1)); + for (arma::irowvec::iterator it2 = start ; it2 < end; it2++){ + arma::uword col = it2 - start; + A(row,col) = covmat((*it1),(*it2)); + } + } + M = solve(A,Y); + for (arma::irowvec::iterator it1 = start+1 ; it1 < end; it1++){ + M(0,(*it1)) = 0.0; + } + return M.row(0); +} + + +// Divide the vector amb_pa into two vectors, following the partition k +void cpdag::directArrows(arma::irowvec &pa_1, arma::irowvec &pa_2, + arma::irowvec amb_pa, uint64_t bits, arma::uword n){ + uint8_t i, idx1, idx2; + uint8_t k; + idx1 = 0; idx2=0; + k = __builtin_popcount(bits); + pa_1.resize(k); + pa_2.resize(n-k); + for (i = 0; i < n ; i++ ){ + if ( bits & (1 << i) ){ + pa_1(idx1++) = amb_pa(i); + } else { + pa_2(idx2++) = amb_pa(i); + } + } +} + diff --git a/src/gies.cpp b/src/gies.cpp index f2cae50..08b8589 100644 --- a/src/gies.cpp +++ b/src/gies.cpp @@ -21,6 +21,7 @@ typedef boost::adjacency_list Undi #include "pcalg/constraint.hpp" #include "pcalg/score.hpp" #include "pcalg/greedy.hpp" +#include "pcalg/cpdag.hpp" #define DEFINE_GLOBAL_DEBUG_STREAM #include "pcalg/gies_debug.hpp" @@ -645,3 +646,27 @@ RcppExport SEXP estimateSkeleton( END_RCPP } + +RcppExport SEXP idaFastC(SEXP xpos, SEXP argMcov, + SEXP argAdjMatrix) +{ + // Exception handling + BEGIN_RCPP + arma::mat covmat = (Rcpp::as(argMcov)); + arma::irowvec x = Rcpp::as(xpos); + arma::uword N = x.n_elem; + arma::mat adjmat_tmp = (Rcpp::as(argAdjMatrix)); + arma::sp_imat adjmat; + adjmat = arma::conv_to::from(adjmat_tmp); + cpdag graph_pd(adjmat,covmat); + Rcpp::List to_return(N); + arma::uword i=0; + for (arma::irowvec::iterator it=x.begin(); it < x.end(); it++){ + to_return[i++] = graph_pd.idaFast(*it); + } + return to_return; + END_RCPP +} + + +