Skip to content

Commit

Permalink
Computed column fixes (#5676)
Browse files Browse the repository at this point in the history
* Handle TRUE/FALSE better in compute columns

Fixes jasp-stats/jasp-issues#2927

* dont require jaspBase for computed columns etc

Do this by including the R-files with "friendly functions" from jaspBase into Engine and then passing that as an init-script to the engine.
Fixes jasp-stats/INTERNAL-jasp#2653

* actually fix the problem
  • Loading branch information
JorisGoosen authored Sep 25, 2024
1 parent 78b4564 commit 072b045
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,6 @@ Desktop/utilities/simplecryptkey.h
Desktop/modules/activemodules.h
Common/appinfo.cpp
QMLComponents/utilities/appdirs.h
Engine/jaspBase_distributionSamplers.h
Engine/jaspBase_friendlyConstructorFunctions.h
Engine/jaspBase_transformFunctions.h
4 changes: 4 additions & 0 deletions Engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ if(LINUX)

endif()

make_includable(jaspBase/R/distributionSamplers.R jaspBase_distributionSamplers.h)
make_includable(jaspBase/R/friendlyConstructorFunctions.R jaspBase_friendlyConstructorFunctions.h)
make_includable(jaspBase/R/transformFunctions.R jaspBase_transformFunctions.h)

file(GLOB HEADER_FILES "${CMAKE_CURRENT_LIST_DIR}/*.h")
file(GLOB SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/*.cpp")

Expand Down
18 changes: 16 additions & 2 deletions Engine/rbridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ void rbridge_setEngine(Engine * engine)
rbridge_engine = engine;
}

const std::string jaspBaseDistributionSamplersR =
#include "jaspBase_distributionSamplers.h"
;

const std::string jaspBaseFriendlyConstructorFunctionsR =
#include "jaspBase_friendlyConstructorFunctions.h"
;

const std::string jaspBaseTransformFunctionsR =
#include "jaspBase_transformFunctions.h"
;

void rbridge_init(Engine * engine, sendFuncDef sendToDesktopFunction, pollMessagesFuncDef pollMessagesFunction, ColumnEncoder * extraEncoder, const char * resultFont)
{
JASPTIMER_SCOPE(rbridge_init);
Expand Down Expand Up @@ -103,6 +115,7 @@ void rbridge_init(Engine * engine, sendFuncDef sendToDesktopFunction, pollMessag
JASPTIMER_START(jaspRCPP_init);

static std::string tempDirStatic = TempFiles::createTmpFolder();
static std::string initRCode = jaspBaseDistributionSamplersR + "\n" + jaspBaseFriendlyConstructorFunctionsR + "\n" + jaspBaseTransformFunctionsR;

Log::log() << "Entering jaspRCPP_init." << std::endl;
jaspRCPP_init( AppInfo::getBuildYear() .c_str(),
Expand All @@ -115,7 +128,8 @@ void rbridge_init(Engine * engine, sendFuncDef sendToDesktopFunction, pollMessag
rbridge_system,
rbridge_moduleLibraryFixer,
resultFont,
tempDirStatic.c_str()
tempDirStatic.c_str(),
initRCode.c_str()
);
JASPTIMER_STOP(jaspRCPP_init);

Expand Down Expand Up @@ -760,7 +774,7 @@ std::string rbridge_evalRComputedColumn(const std::string &rCode, const std::str

jaspRCPP_resetErrorMsg();

std::string rCode64( "library(jaspBase);\n" + rbridge_encodeColumnNamesInScript(rCode));
std::string rCode64(rbridge_encodeColumnNamesInScript(rCode));

try { R_FunctionWhiteList::scriptIsSafe(rCode64); }
catch(filterException & e) { jaspRCPP_setErrorMsg(e.what()); return std::string("R code is not safe because of: ") + e.what(); }
Expand Down
30 changes: 19 additions & 11 deletions R-Interface/jasprcpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ extern "C" {
void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCallBacks* callbacks,
sendFuncDef sendToDesktopFunction, pollMessagesFuncDef pollMessagesFunction,
logFlushDef logFlushFunction, logWriteDef logWriteFunction, systemDef systemFunc,
libraryFixerDef libraryFixerFunc, const char* resultFont, const char * tempDir)
libraryFixerDef libraryFixerFunc, const char* resultFont, const char * tempDir, const char * initFriendlyFunctionsRCode)
{
_logFlushFunction = logFlushFunction;
_logWriteFunction = logWriteFunction;
Expand Down Expand Up @@ -172,9 +172,12 @@ void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCa
rInside[".ppi"] = 300;

jaspRCPP_parseEvalQNT("library(methods)");

jaspRCPP_logString("Loading friendly R functions for computed columns and filters.");
jaspRCPP_parseEvalQNT(initFriendlyFunctionsRCode);

_R_HOME = jaspRCPP_parseEvalStringReturn("R.home('')");
jaspRCPP_logString("R_HOME is: " + _R_HOME + "\n");
jaspRCPP_logString("jaspRCPP_init is done, R_HOME is: " + _R_HOME + "\n");

}

Expand Down Expand Up @@ -230,16 +233,11 @@ void STDCALL jaspRCPP_init_jaspBase()
//Load it
jaspRCPP_logString("Initializing jaspBase.\n");
jaspRCPP_parseEvalQNT("library(jaspBase)");

// if we have a separate engine for each module then we should move these kind of hacks to the .onAttach() of each module (instead of loading BayesFactor when Descriptives is requested).
// jaspRCPP_logString("initEnvironment().\n");
// jaspRCPP_parseEvalQNT("initEnvironment()");

jaspRCPP_logString("initializeDoNotRemoveList().\n");
jaspRCPP_parseEvalQNT("jaspBase:::.initializeDoNotRemoveList()");

jaspRCPP_logString("Finished initializing jaspBase.\n");

}

void STDCALL jaspRCPP_junctionHelper(bool collectNotRestore, const char * modulesFolder, const char * linkFolder, const char * junctionsFilePath)
Expand Down Expand Up @@ -823,15 +821,25 @@ bool jaspRCPP_setColumnDataAsNominal(const std::string & columnName, Rcpp::RObje
bool _jaspRCPP_setColumnDataAndType(const std::string & columnName, Rcpp::RObject data, columnType colType)
{
static Rcpp::Function asNumeric("as.numeric");
Rcpp::Vector<STRSXP> strData = Rf_isNull(data) ? Rcpp::Vector<STRSXP>() : Rcpp::as<Rcpp::Vector<STRSXP>>(data);
Rcpp::Vector<REALSXP> dblData = Rf_isNull(data) ? Rcpp::NumericVector() : Rcpp::NumericVector(asNumeric(Rcpp::_["x"] = data));
static Rcpp::Function asCharacter("as.character");

Rcpp::Vector<STRSXP> strData = Rf_isNull(data) ? Rcpp::CharacterVector() : Rcpp::CharacterVector(asCharacter(Rcpp::_["x"] = data));
Rcpp::Vector<REALSXP> dblData = Rf_isNull(data) ? Rcpp::NumericVector() : Rcpp::NumericVector( asNumeric( Rcpp::_["x"] = data));

std::vector<std::string> convertedStrings(strData.begin(), strData.end());
stringvec convertedStrings(strData.begin(), strData.end());

const char ** nominals = new const char*[convertedStrings.size()]();

for(size_t i=0; i<convertedStrings.size(); i++)
nominals[i] = std::isnan(dblData[i]) && convertedStrings[i] == "NA" ? "" : convertedStrings[i].c_str();
{
bool isNA = convertedStrings[i] == "NA",
isLgl = convertedStrings[i] == "TRUE" || convertedStrings[i] == "FALSE",
isNan = std::isnan(dblData[i]);

nominals[i] = std::isnan(dblData[i]) // If the string could not be converted to a number its not TRUE or FALSE, but it might be NA. We do not want that as a result!
? (!isNA ? convertedStrings[i].c_str() : "")
: (!isLgl ? convertedStrings[i].c_str() : convertedStrings[i] == "TRUE" ? "1" : "0"); //Also getting TRUE or FALSE is not ideal
}

return dataSetColumnDataAndType(columnName.c_str(), nominals, static_cast<size_t>(strData.size()), int(colType));
}
Expand Down
2 changes: 1 addition & 1 deletion R-Interface/jasprcpp_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ typedef size_t (*logWriteDef) (const void * buf, size_t len);


// Calls from rbridge to jaspRCPP
RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCallBacks *calbacks, sendFuncDef sendToDesktopFunction, pollMessagesFuncDef pollMessagesFunction, logFlushDef logFlushFunction, logWriteDef logWriteFunction, systemDef systemFunc, libraryFixerDef libraryFixerFunc, const char* resultFont, const char * tempDir);
RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCallBacks *calbacks, sendFuncDef sendToDesktopFunction, pollMessagesFuncDef pollMessagesFunction, logFlushDef logFlushFunction, logWriteDef logWriteFunction, systemDef systemFunc, libraryFixerDef libraryFixerFunc, const char* resultFont, const char * tempDir, const char * friendlyRFunctionsInit);
RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_init_jaspBase();
RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_setDecimalSettings(int numDecimals, bool fixedDecimals, bool normalizedNotation, bool exactPValues);
RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_setFontAndPlotSettings(const char * resultFont, const int ppi, const char* imageBackground);
Expand Down

0 comments on commit 072b045

Please sign in to comment.