0

In this post, I defined a function called soft. When I used sourceCpp to compile it, reported errors are

  • ZH was not declared in this scope
  • alpha0H was not declared in this scope
  • maxRankH was not declared in this scope

I have tried many approaches to solve the problem "... was not declared in this scope". However, I did not find the right way or why the error occurred. I guess it should be related with the if-else statement in the function, but not sure.

Do you have any good idea to address this issue? Thank you in advance!

By the way, I did not write Rcpp::NullableRcpp::LogicalMatrix Ome_ = R_NilValue, Rcpp::NullableRcpp::LogicalMatrix Ome1_ = R_NilValue, Rcpp::NullableRcpp::LogicalMatrix Ome2_ = R_NilValue in the arguments previously, but rather Rcpp::LogicalMatrix Ome, Rcpp::LogicalMatrix Ome1, Rcpp::LogicalMatrix Ome2. But one error was reported "default missing for ...arguments...", so I changed to Rcpp::NullableRcpp::LogicalMatrix.....

#include <RcppArmadillo.h>


// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::List dcSVD(arma::mat X) {
  arma::mat u, v;
  arma::vec d;
  arma::svd(u, d, v, X, "dc");
  return Rcpp::List::create(Rcpp::Named("u") = u,
                            Rcpp::Named("d") = d,
                            Rcpp::Named("v") = v);
  
}


// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
Rcpp::List soft(arma::mat X, Rcpp::Nullable<Rcpp::NumericMatrix> Z_ = R_NilValue, Rcpp::Nullable<Rcpp::LogicalMatrix> Ome_ = R_NilValue, Rcpp::Nullable<Rcpp::LogicalMatrix> Ome1_ = R_NilValue, Rcpp::Nullable<Rcpp::LogicalMatrix> Ome2_ = R_NilValue, Rcpp::Nullable<Rcpp::NumericVector> alpha0_ = R_NilValue, Rcpp::Nullable<Rcpp::NumericVector> maxRank_ = R_NilValue){
  
  
  if (Ome_.isNotNull() && Ome1_.isNotNull() && Ome2_.isNotNull()){
    
    Rcpp::LogicalMatrix Ome(Ome_);
    arma::umat Omega = Rcpp::as<arma::umat>(Ome);
    
    
    Rcpp::LogicalMatrix Ome1(Ome1_);
    arma::umat Omega1 = Rcpp::as<arma::umat>(Ome1);
    
    Rcpp::LogicalMatrix Ome2(Ome2_);
    arma::umat Omega2 = Rcpp::as<arma::umat>(Ome2);
    
    arma::mat X_0 = X % Omega;
    
    if (!Z_.isNotNull()){
      
      Rcpp::NumericMatrix ZH = Rcpp::wrap(X_0);
      
    }else{
      
      Rcpp::NumericMatrix ZH = Rcpp::as<Rcpp::NumericMatrix>(Z_);
    }
    
    
    if (!alpha0_.isNotNull()){
      
      Rcpp::List my_svd = dcSVD(X_0);
      arma::vec d = my_svd["d"];
      Rcpp::NumericVector alpha0H = d(1);
      
    }else{
      
      Rcpp::NumericVector alpha0H = Rcpp::as<Rcpp::NumericVector>(alpha0_);
    }
    
    if (!maxRank_.isNotNull()){
      
      Rcpp::NumericVector maxRankH = -1;
      
    }else{
      
      Rcpp::NumericVector maxRankH = Rcpp::as<Rcpp::NumericVector>(maxRank_);
    }
    
    
  }else{
    
    Rcpp::StringVector ZH = "NULL";
    Rcpp::StringVector alpha0H = "NULL";
    Rcpp::StringVector maxRankH = "NULL";
    
  }  
  
  return Rcpp::List::create(Rcpp::Named("ZH") = ZH, 
                            Rcpp::Named("alpha0H") = alpha0H, 
                            Rcpp::Named("maxRankH") = maxRankH);
  
}

Artem Sokolov
  • 13,196
  • 4
  • 43
  • 74
cheng
  • 85
  • 1
  • 11
  • c++ follows different scoping rules than R. In particular, `ZH` is not visible outside `{ }` where it is declared, like it would be in R. You may want to move your `NULL` declarations one level up, then have individual `if` statements overwrite the `NULL` defaults. – Artem Sokolov Sep 22 '20 at 04:43
  • @ArtemSokolov Thank you! That works. Can you help explain another error I often encounter **"static assertion failed: error: type mismatch or unsupported type"**? ? Thank you again! – cheng Sep 22 '20 at 04:58
  • I don't think that scoping would work in R, either. In general, I declare the variables in the beginning outside of any conditional, usually with a sane (and distinguishable) default value, so in case my `if` statements don't override it, they are defined and have something meaningful (e.g., some form of `NA` or `NULL`). – r2evans Sep 22 '20 at 05:05
  • @cheng That error often arises when you have a mismatch in the templated types (i.e., the type that goes between `<` and `>`). – Artem Sokolov Sep 22 '20 at 15:15
  • 1
    @r2evans Try `rm(y); if(TRUE) {y <- 5}; y`. Even though `y` is declared and defined inside an `if { }` scope, it is visible outside that scope. This would not be true in C++. – Artem Sokolov Sep 22 '20 at 15:18
  • 1
    Okay, I was thinking more `function` and `local`, I wasn't considering `if` and `for` loop in my original statement. In that sense ... R is a little more permissive, but it isn't global. *sigh* – r2evans Sep 22 '20 at 15:20

1 Answers1

2

The scoping rules of c++ make it so that variables declared inside { } are not visible outside that scope. Consider moving the default definitions up one level and then having individual if scopes overwrite those defaults:

Rcpp::List soft(...) {

    // Declare variables outside all {}
    //   to make them visible throughout the whole function
    Rcpp::NumericMatrix ZH = R_NilValue;

    // Overwrite the default values inside individual {}
    if (!Z_.isNotNull()){
      ZH = Rcpp::wrap(X_0);
    }else{
      ZH = Rcpp::as<Rcpp::NumericMatrix>(Z_);
    }

    // etc....
}
Artem Sokolov
  • 13,196
  • 4
  • 43
  • 74