Needs["CCompilerDriver`"];
Needs["GeneralUtilities`"];
LibraryLink`BoilerPlate[funname_String] :=
StringJoin["#include \"math.h\"
#include \"WolframRTL.h\"
static WolframCompileLibrary_Functions funStructCompile;
static mbool initialize = 1;
DLLEXPORT int Initialize_", funname, "(WolframLibraryData libData)
{
if( initialize)
{
funStructCompile = libData->compileLibraryFunctions;
initialize = 0;
}
return 0;
}
DLLEXPORT void Uninitialize_", funname, "(WolframLibraryData libData)
{
if( !initialize)
{
initialize = 1;
}
}
"]
funname = "writeRealMatrixToFile";
preamble = "
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;
";
code = StringJoin[
preambleStringJoin[preamble, "\n\n",
LibraryLink`BoilerPlate[funname],
"extern \"C\" DLLEXPORT int ", funname,
"(WolframLibraryData libData, mint Argc, MArgument * Args, \
MArgument Res)
{
int err = 0;
const char * file = MArgument_getUTF8String(Args[0]);
const MTensor a0 = MArgument_getMTensor(Args[1]);
const mreal * a = libData->MTensor_getRealData(a0);
const char * prefix = MArgument_getUTF8String(Args[2]);
const char * infix = MArgument_getUTF8String(Args[3]);
const char * suffix = MArgument_getUTF8String(Args[4]);
const char * linesep = MArgument_getUTF8String(Args[5]);
mint prec = MArgument_getInteger(Args[6]);
mint const* dims;
dims = libData->MTensor_getDimensions(a0);
mint i, j;
ofstream outputstream;
try
{
outputstream.open(file, ofstream::out | ofstream::app);
outputstream.precision(prec);
outputstream.setf(ios::fixed, ios::floatfield);
for( i=0; i < (dims[0]-1); i++)
{
outputstream << prefix;
for( j=0; j < dims[1]-1; j++)
{
outputstream << lexical_cast<string>(*a) << infix; \
a++;
}
outputstream << lexical_cast<string>(*a) << suffix;
a++;
outputstream << linesep;
}
{
outputstream << prefix;
for( j=0; j < dims[1]-1; j++)
{
outputstream << lexical_cast<string>(*a) << infix;
a++;
}
outputstream << lexical_cast<string>(*a) << suffix;
}
}
outputstream.close();
MArgument_setInteger(Res, err);
}
catch (...)
{
return LIBRARY_FUNCTION_ERROR;
}
return LIBRARY_NO_ERROR;
}
"];
Creating the library in a temporary directory. (If you'd like to reuse the library, just specify a value of choice for "TargetDirectory"
.) Since we require boost
and it is not located at a path that can be found automatically by the compiler, I also specify "IncludeDirectories"
.
libfile = CreateLibrary[
codeCreateLibrary[code, funname,
"Language" -> "C++",
"TargetDirectory" -> $TemporaryDirectory,
"IncludeDirectories" -> "/opt/local/include"
];
If[TrueQ[Head[writeRealMatrixToFile] === LibraryFunction],
LibraryFunctionUnload[writeRealMatrixToFile]];
ClearAll[writeRealMatrixToFile];
If[TrueQ[FindLibrary[libfile] =!= $Failed],
writeRealMatrixToFile = LibraryFunctionLoad[libfile, funname,
{
"UTF8String", {Real, 2, "Constant"}, "UTF8String", "UTF8String",
"UTF8String", "UTF8String", Integer
},
Integer]
];
Options[WriteRealMatrixToFile] = {
"Prefix" -> "",
"Infix" -> "\t",
"Suffix" -> "",
"RowSep" -> "\n",
"Precision" -> 16
};
WriteRealMatrixToFile[file_String,
A_?(MatrixQ[#, Developer`MachineRealQ] &), OptionsPattern[]] :=
writeRealMatrixToFile[file, A,
OptionValue["Prefix"],
OptionValue["Infix"],
OptionValue["Suffix"],
OptionValue["RowSep"],
OptionValue["Precision"]
];
0.618298668737
1.401475853
50.55112*10^-17
This is almost 25over 20 times faster than using Export
with "Table"
as export format:
Edit
New version employs boost::lexical_cast
on the C++ side for conversion of double
to string
, preventing a loss of relative precision.