oldtimetrad
oldtimetrad

Reputation: 155

Working with R and .C to return dot product

I am trying to return the inner product of two vectors in .C with R. After this I want the function to return true if the inner product is equal to zero and false otherwise. I have written a small .cpp function that calculates the inner product correct. When I have a vector of length 2 e.g a <- c(5,-5) b <- c(5,5)

this returns 0 as the result and true as the result is equal to zero.

However when I increase the length of the vector in the R calling code e.g a <- c(5,-5,4) b <- c(5,5,4)

It returns 16 as the result which is fine but it returns true which is incorrect as the result is not equal to zero.

Can anybody help understand what I am doing wrong here?

The code is below for .C

#include <R.h>
extern "C" {
    void test(int * x1, int * x2, int * len, int * result, bool * tf)
    {
        int n = *len;
        *result = 0;
        for (int i = 0; i < n; i++)
        {
            *result = *result + x1[i] * x2[i];
            if (*result == 0)
            {
                *tf = TRUE;
            }
        }
    }
}

I have changed this to the code

#include <R.h>

extern "C" {

  void test (int * x1, int * x2, int * len, int * result, int * tf)
 // void test (int * x1, int * x2, int * result)
  {
    int n = *len ;
      *result = 0;
      for (int i = 0; i < n; i++)
         *result += x1[i] * x2[i]; 
      *tf = *result == 0;
    }
  }

and when i use R to call this as below

a <- c(-5,5,4)
b <- c(5,5,3)
len <- length(a)
c <- 0
ans <- FALSE

.C("test", x1 = as.integer(a), x2 = as.integer(b), 
   len = as.integer(length(a)),
   result = as.integer(c),
   tf = as.logical(ans))

The output is

$x1
[1] -5  5  4

$x2
[1] 5 5 3

$len
[1] 3

$result
[1] 12

$tf
[1] TRUE

Since Result is not 0 tf should be FALSE and it is when the vector is of length 1 or 2. Only when I increase it to length 3 or more does this happen. Can anyone help please?

Upvotes: 0

Views: 454

Answers (2)

Laurent Michel
Laurent Michel

Reputation: 405

Your code is buggy. Here is the fixed version:

#include <R.h>
extern "C" {
   void isOrthn (int * x1, int * x2, int * len, int * result, bool * tf)
   {
      int n = *len ;
      *result = 0;
      for (int i = 0; i < n; i++)
         *result += x1[i] * x2[i]; 
      *tf = *result == 0;
   }   
}

Basically, you could get out without ever initializing tf. By moving the test outside the loop, it is simpler, cleaner and one clearly sees that *tf's value is functionally dependent on the result being 0.

Upvotes: 1

Dirk is no longer here
Dirk is no longer here

Reputation: 368439

Briefly:

  • Do not use .C(), its use is discouraged in all new code (cf discussions on r-devel in the last few years).

  • Your code has a logic error in that it does not compute the full inner product before testing: complete the loop

Below is how I would write this in RcppArmadillo:

#include <RcppArmadillo.h>

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

// [[Rcpp::export]]
bool checkInner(const arma::vec a, const arma::vec b) {
  double ip = arma::as_scalar(a.t() * b);
  return ip == 0.0;
}

/*** R
checkInner( c(1,2), c(-2,1))
checkInner( 1:3, 2:4 )
*/

We just sourceCpp(...) the file, and it is compiled, linked, loaded and the R code at the bottom is run as well:

R> sourceCpp("/tmp/inner.cpp")

R> checkInner( c(1,2), c(-2,1))
[1] TRUE

R> checkInner( 1:3, 2:4 )
[1] FALSE
R> 

Upvotes: 2

Related Questions