Skip to main content
added 1 character in body
Source Link
Henrik Schumacher
  • 109.5k
  • 7
  • 186
  • 323

New version employs boost::lexical_caston on the C++ side for conversion of double to string, preventing a loss of relative precision.

New version employs boost::lexical_caston the C++ side for conversion of double to string, preventing a loss of relative precision.

New version employs boost::lexical_cast on the C++ side for conversion of double to string, preventing a loss of relative precision.

added 74 characters in body
Source Link
Henrik Schumacher
  • 109.5k
  • 7
  • 186
  • 323

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". Of course you have to make sure that boost is installed on your system.

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".

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". Of course you have to make sure that boost is installed on your system.

added 529 characters in body
Source Link
Henrik Schumacher
  • 109.5k
  • 7
  • 186
  • 323
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_caston the C++ side for conversion of double to string, preventing a loss of relative precision.

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>
  using namespace std;
  ";

code = StringJoin[
   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 << *a << infix; 
                a++;
            }
            outputstream << *a << suffix;
            a++;
            outputstream << linesep;
        }
        {
            outputstream << prefix;
            for( j=0; j < dims[1]-1; j++)
            {
                outputstream << *a << infix;
                a++;
            }
            outputstream << *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".)

libfile = CreateLibrary[
   code, funname,
   "Language" -> "C++",
   "TargetDirectory" -> $TemporaryDirectory
   ];
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.618298

1.40147

5.55112*10^-17

This is almost 25 times faster than using Export with "Table" as export format:

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[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 const* dims;
          dims = libData->MTensor_getDimensions(a0);
       mint i, j;
   
       ofstream outputstream;
   
       try
       {
           outputstream.open(file, ofstream::out | ofstream::app);
   
           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[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]
  ];

Options[WriteRealMatrixToFile] = {
   "Prefix" -> "",
   "Infix" -> "\t",
   "Suffix" -> "",
   "RowSep" -> "\n"
   };
WriteRealMatrixToFile[file_String, 
   A_?(MatrixQ[#, Developer`MachineRealQ] &), OptionsPattern[]] := 
  writeRealMatrixToFile[file, A,
   OptionValue["Prefix"],
   OptionValue["Infix"],
   OptionValue["Suffix"],
   OptionValue["RowSep"]
   ];

0.668737

1.5853

0.

This is over 20 times faster than using Export with "Table" as export format:

Edit

New version employs boost::lexical_caston the C++ side for conversion of double to string, preventing a loss of relative precision.

added 362 characters in body
Source Link
Henrik Schumacher
  • 109.5k
  • 7
  • 186
  • 323
Loading
added 362 characters in body
Source Link
Henrik Schumacher
  • 109.5k
  • 7
  • 186
  • 323
Loading
Source Link
Henrik Schumacher
  • 109.5k
  • 7
  • 186
  • 323
Loading