Combining C codes in the same R package - c++

Say I have two independent cpp codes in two different R packages:
(please do not take these examples literally, these are meant to be
a minimal version of my question).
#include <algorithm>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
using Eigen::VectorXf;
using Eigen::VectorXi;
using Eigen::RowVectorXf;
float Fmedian(VectorXf& x){
const int n=x.rows();
const int half=(n+1)/2-1;
float med;
std::nth_element(x.data(),x.data()+half,x.data()+x.size());
if((n%2)==1){
med=x(half);
} else {
float tmp0=x(half);
float tmp1=x.segment(half+1,half-1).minCoeff();
med=0.5*(tmp0+tmp1);
}
return med;
}
extern "C"{
void R_Fastmedian(int* n,float* X,int* fMet){
MatrixXf xi=Map<VectorXf>(X,*n);
float Um=Fmedian(xi);
*fMet=Um;
}
}
then, in another file, i have:
#include <algorithm>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
using Eigen::VectorXf;
using Eigen::VectorXi;
using Eigen::RowVectorXf;
float Fmedian(VectorXf& x){
const int n=x.rows();
const int half=(n+1)/2-1;
float med;
std::nth_element(x.data(),x.data()+half,x.data()+x.size());
if((n%2)==1){
med=x(half);
} else {
float tmp0=x(half);
float tmp1=x.segment(half+1,half-1).minCoeff();
med=0.5*(tmp0+tmp1);
}
return med;
}
float Fmad(VectorXf& x,float& med){
const int n=x.rows();
const int half=(n+1)/2-1;
float mad;
x-=med;
x=x.cwiseAbs();
std::nth_element(x.data(),x.data()+half,x.data()+x.size());
if((n%2)==1){
mad=x(half);
} else {
float tmp0=x(half);
float tmp1=x.segment(half+1,half-1).minCoeff();
mad=0.5*(tmp0+tmp1);
}
return(mad*1.4826);
}
extern "C"{
void R_Fastmad(int* n,float* X,int* fMet){
MatrixXf xi=Map<VectorXf>(X,*n);
float U1=Fmedian(xi);
float U2=Fmad(xi,U1);
*fMet=U2;
}
}
Now, i want to combine these two functions in a package. When i will compile
the second code using R CMD, i will get an error for Fmedian to the effect
that this function is already defined in the first file. What is the most
straightforward way to link these two files together?

If I'm reading correctly, your Fmedian implementations are exactly the same in both files. But the compiler doesn't actually know that, for it they may be different and cause ambiguity, hence the error. To fix it, you should unify both implementations into one.
One way to do that would be this:
// the first file
#include <algorithm>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
using Eigen::VectorXf;
using Eigen::VectorXi;
using Eigen::RowVectorXf;
// Forward-declare Fmedian as an external function.
// This means that its definition will be found
// in some other file (C++ translation unit) during compilation.
extern float Fmedian(VectorXf& x);
extern "C" {
void R_Fastmedian(int* n,float* X,int* fMet){
MatrixXf xi=Map<VectorXf>(X,*n);
float Um=Fmedian(xi);
*fMet=Um;
}
}
And your second file remains the same.
See also Externing functions in C++, How does the linker know where is the definition of an extern function?

Related

How to pass multi-dimensional array to header file in C++

I am trying to work with multi-dimensional arrays.
My goal is to have a separate file for my matrix functions, however I am having trouble with setting the value of V.
Error : ā€˜Vā€™ was not declared in this scope
Since this error statement is very broad, I could not find a satisfactory answer on my searches.
This is what I want to implement.
main.cpp
#include <bits/stdc++.h>
using namespace std;
#include "prims.h"
int main()
{ int V = 5;
int graph[V][V] = { {... },
{... },
{... },
{... },
{... } };
func1(graph);
func2(graph);
return 0;
}
prims.h
#ifndef PRIMS_H
#define PRIMS_H
#include <bits/stdc++.h>
using namespace std;
int func1(int graph[V][V]);
int func2(int graph[V][V]);
#endif
prims.cpp
#include <bits/stdc++.h>
using namespace std;
#include "prims.h"
int func1(int graph[V][V])
{
// function
}
int func2(int graph[V][V])
{
// function
}
Please comment below if more clarification is required.
Thank you.
Since you want to set the value from main, one alternative is to declare V as global variable in main and as extern const int in prims.h, so that it is visible in prmis.cpp as well.
prims.h
extern const int V;
main.cpp
const int V = 5; //declared as global in main
int main()
{
/* */
}

string return function not working - 'identifier is underfined'

Relearning C/C++ after 3 years of JavaScript (I've gotten way too comfortable..)
I'm building a test file with input.
The problem is within cTool, where the first function is not letting me return a string. I thought this was totally valid if the library is included in the header file? What am I overlooking here.
cTool.cpp
string getInfo(void) {
}
void parseInfo(void (*getInfo)()) {
}
float assessInfo(float number) {
}
...
cTool.h
#pragma once
#ifndef ASSESS_GRADE_H
#define ASSESS_GRADE_H
#include <string>
#include <stdio.h>
#include <iostream>
using namespace std;
string getInfo(void);
void parseInfo(void(*getInputFunc)());
float assessInfo(float number);
float assessInfo(char letter);
float assessInfo(int *array);
#endif
cMain.cpp
#include "cTool.h";
int main (void) {
// function call from cTool.cpp
return 0;
}
You need to add #include "cTool.h" to cTool.cpp, not just to cMain.cpp only. Otherwise, when compiling cTool.cpp, the compiler doesn't know what a string is since it doesn't see your #include <string> and using namespace std; statements (BTW, using namespace std; in a header file is a very bad idea).
cTool.cpp
#include "cTool.h" // <-- ADD THIS!
std::string getInfo(void) {
}
void parseInfo(void (*getInfo)()) {
}
float assessInfo(float number) {
}
...
cTool.h
#pragma once
#ifndef ASSESS_GRADE_H
#define ASSESS_GRADE_H
#include <string>
#include <iostream>
std::string getInfo(void);
void parseInfo(void(*getInputFunc)());
float assessInfo(float number);
float assessInfo(char letter);
float assessInfo(int *array);
#endif
cMain.cpp
#include "cTool.h";
int main (void) {
// function call from cTool.cpp
return 0;
}

out-of-line definition of 'function' does not match any declaration in 'Class'

So I'm working on an iOS project using OpenCV and am currently trying to import part of an existing c++ project into the iOS app, and this error has recently come up. I'm still quite new to both to C++ and objective C, so maybe I'm missing something painfully obvious.
I've noticed that attempting to define and implement any new functions in the Contour namespace results in the same error, and adding the virtual specifier does not seem to change this. The draw function does not experience the problem though. I've also tried quitting and restarting xcode as suggested in similar questions, but the problem persists.
The function writeToFile(string fname) is defined in the header file, as you can see below, yet in the implementation file the error complains that "out-of-line definition of 'writeToFile' does not match any declaration in 'Contour'":
2DContour.h:
#ifndef TWODCONTOUR_H
#define TWODCONTOUR_H
#include <vector>
using std::vector;
#include <opencv2/core.hpp>
using namespace cv;
class Contour
{
protected:
vector<Vec2f> points;
virtual void process(){} // virtual function interface for after-creation/edit processing (eg. refinement/validation)
public:
inline Vec2f at(int index){return points[index];}
inline void clear(){points.clear();}
inline void addPoint(Vec2f p){points.push_back(p);}
inline void finish(){process();}
inline void randomize(int num)
{
num--;
points.clear();
int cycles=6;//rand()%6+1;
float offset=(float)rand()/(float)RAND_MAX*2.0f*3.141592654f;
float noisemag=(float)rand()/(float)RAND_MAX;
for(int i=0;i<num;i++)
{
float a=(float)i/(float)num;
addPoint(
Vec2f(sin(a*2.0f*3.141592654f),cos(a*2.0f*3.141592654f))+
noisemag*Vec2f(sin(cycles*a*2.0f*3.141592654f+offset),cos(cycles*a*2.0f*3.141592654f+offset)));
}
addPoint(points.front());
process();
}
void writeToFile(String fname);
virtual Mat draw(Mat canvas, bool center=false, Scalar colour=Scalar(255,255,255), int thickness=1);
inline int numPoints(){return points.size();}
inline Vec2f getPoint(int i){return points[i];}
};
#endif
2DContour.cpp:
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <fstream>
#include "2DContour.h"
using namespace std;
using namespace cv;
//error occurs here
void Contour::writeToFile(string fname)
{
ofstream out;
out.open(fname.c_str());
for(unsigned int i=0;i<points.size();i++)
out << points[i][0]<<" "<<points[i][1]<<endl;
out.close();
std::cout<<"Wrote: "<<fname<<std::endl;
}
//draw() function does not experience the same error however
Mat Contour::draw(Mat canvas, bool center, Scalar colour, int thickness)
{
Mat r=canvas.clone();
cv::Point c(center?r.cols/2:0,center?r.rows/2:0);
for( unsigned int j = 0; j < points.size(); j++ )
{
line(r,c+ cv::Point(points[j]*50),c+ cv::Point(points[(j+1)%points.size()]*50),colour,thickness, 8 );
}
return r;
}
Any help would be appreciated.
Your declaration
void writeToFile(String fname);
does not match the implementation
void Contour::writeToFile(string fname)
The declaration used capital-S "String" while implementation had lowercase-s "string." Matching those up should fix it.

how to return multiple values in a function using "RcppEigen.package.skeleton"

Apologize if this question is naive.
I can successfully return multiple values (int, double and bool variable) in a function using pointer variable in C++ Eigen. But I do not know how to modify the function to return multiple variables in "RcppEigen.package.skeleton".
I can use "RcppEigen.package.skeleton" to install package "RSS", the C++ function like that, and it can run successfully.
#include <Rcpp.h>
#include <RcppEigen.h>
using namespace Rcpp;
using namespace RcppEigen;
using namespace std;
using Eigen::MatrixXd;
RcppExport SEXP getRSS(SEXP X0, SEXP Y0){
MatrixXd X=Rcpp::as<MatrixXd>(X0);
MatrixXd Y=Rcpp::as<MatrixXd>(Y0);
MatrixXd RSS=((Y-X*((X.transpose()*X).inverse()*X.transpose()*Y)).transpose())*(Y-X*((X.transpose()*X).inverse()*X.transpose()*Y));
return wrap(RSS.determinant());
}
Here is the C++ function where i want to return multiple variables. How could I modify this function to install package using "RcppEigen.package.skeleton". Any help will be very appreciated.
#include <Eigen/Dense>
#include <iostream>
#include <string>
using namespace std;
using namespace Eigen;
double getRSS(const MatrixXd& X, const MatrixXd& Y){
MatrixXd RSS=((Y-X*((X.transpose()*X).inverse()*X.transpose()*Y)).transpose())*(Y-X*((X.transpose()*X).inverse()*X.transpose()*Y));
return RSS.determinant();
}
void getPIcvalue(MatrixXd& Y, MatrixXd& Xf, MatrixXd& X0,double *keyV, int *keyP, bool *keyR){
bool valid;
double FitStat1;
FitStat1 = 1e+10;
int pointer;
double FitStat;
int n;
n=X0.rows();
MatrixXd X(n,X0.cols()+1);
for(int i=0;i<Xf.cols();i++){
X<<X0,Xf.col(i); //X: combine X0 and 1 column of Xf
FitStat=getRSS(X,Y); // calculate Residual Sum of Squares
valid=false;
if(FitStat<FitStat1){
FitStat1=FitStat; //get the minimum of FitStat
pointer=i; //get which column of Xf is the minimum of FitStat
valid=true;
}
}//for i
*keyV=FitStat1; //pointer return multiple variables
*keyP=FitStat1;
*keyR=FitStat1;
}

Error: variable needs stack frame

considering this code i put a bp at the end of roll(int n) and i had data in values array
and i put another one at the end of print and there was no data in the array.Why do I get this error: CXX0069: Error: variable needs stack frame?
die.h
#ifndef DIE_H
#define DIE_H
#include<iostream>
#include<time.h>
using namespace std;
class Die
{
private:
int number;
int values[6][2];
void roll();
public:
Die();
void Roll(int n);
int getNumber()const{return number;}
void printLastValue();
void printApearences();
~Die(){}
};
#endif
die.cpp
#include"die.h"
#include<iostream>
#include<time.h>
using namespace std;
Die::Die()
{
srand(static_cast<int>(time(NULL)));
number=0;
for(int j=0;j<6;j++)
{
values[j][0]=j+1;
values[j][1]=0;
}
}
void Die::roll()
{
number=1+rand()%6;
}
void Die::printLastValue()
{
cout<<number<<endl;
}
void Die::Roll(int n)
{
for(int j=0;j<6;j++)
{
values[j][0]=j+1;
values[j][1]=0;
}
for(int i=0;i<n;i++)
{
roll();
(values[number-1][1])++;
}
}
void Die::printApearences()
{
for(int i=0;i<6;i++)
{
cout<<values[i][0]<<" : "<<cout<<values[i][1]<<endl;
}
}
main.cpp
#include"die.h"
#include<iostream>
using namespace std;
int main()
{
Die d;
d.Roll(5);
d.printApearences();
}
What exactly is this:
cout<<values[i][0]<<" : "<<cout<<values[i][1]<<endl;
Specifically, why are you trying to extract cout to cout? Copy/paste can be a ruthless wench. Pretty sure you want:
cout << values[i][0] <<" : "<< values[i][1] << endl;
Next, your header declarations are quite-convoluted.
Do NOT place using namespace std in any of your header files. For information on why, refer this question and its various discussions. If your fingers tire of typing std:: there are some alternatives, but in-general slurping an entire namespace (especially one as large as std) can cause unintended consequences. The linked question is worth a review.
Do not bring #include's into a header unless the content therein is dependent on it (Die.h needs nothing you're #include'ing, for example).
List your headers ahead of system headers, including in your headers, to ensure you do not code an implicit include that your header by-itself doesn't fulfill.
Include standard library C++ headers if you're compiling in C++ (use <cstdio>, <cstdlib>, <ctime>, etc.
Applying the above your code becomes:
Die.h
#ifndef DIE_H
#define DIE_H
class Die
{
private:
int number;
int values[6][2];
void roll();
public:
Die();
void Roll(int n);
int getNumber()const{return number;}
void printLastValue();
void printApearences();
~Die(){}
};
#endif
Die.cpp (top of file, code eliminated for brevity)
#include "die.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
main.cpp (top of file, code eliminated for brevity)
#include "die.h"
The last one traditionally contains <iostream> as well, but you don't actually need it in your code as it is written.
You're static cast to int for sending time(NULL) as the random seed is not correct. The srand(unsigned int seed); API takes an unsigned int as the seed, not an int. Change your seeding to be
srand(static_cast<unsigned int>(time(NULL)));
I'd start with those, specifically the first two suggestions.
It doesn't recognize rand and srand. Add #include <stdlib.h> to your die.cpp file.
The debugger will display this error when the execution is at a point where the variable in question is out of scope, and therefore cannot be evaluated. Step into your code until you reach the scope of the variable, and the debugger will show you its value.