Skip to main content
added 90 characters in body
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k

Can I create a function that takes an MTensor of unspecified type? No, LTemplate requires specifying the data type (but not the rank) of the MTensor. {Real, 2} is a valid type specifier and so is {Real, _}. {_, _} is not allowed in LTemplate, even though it's valid in standard LibraryLink. The same applies to MSparseArrays (mma::SparseArrayRef). However, RawArray and Image may be passed without an explicit element-type specification.

Can I create a function that takes an MTensor of unspecified type? No, LTemplate requires specifying the data type (but not the rank) of the MTensor. {Real, 2} is a valid type specifier and so is {Real, _}. {_, _} is not allowed in LTemplate, even though it's valid in standard LibraryLink. The same applies to MSparseArrays (mma::SparseArrayRef).

Can I create a function that takes an MTensor of unspecified type? No, LTemplate requires specifying the data type (but not the rank) of the MTensor. {Real, 2} is a valid type specifier and so is {Real, _}. {_, _} is not allowed in LTemplate, even though it's valid in standard LibraryLink. The same applies to MSparseArrays (mma::SparseArrayRef). However, RawArray and Image may be passed without an explicit element-type specification.

added 70 characters in body
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k

Note: The package comes with a tutorial and many more examples.The package comes with a tutorial and many more examples in its Documentation subdirectory.

The package is too large to present fully in a StackExchange post, so if you are interested, download it and read the tutorial, which has several moreand take a look at the many examples that come with the package!

Note: The package comes with a tutorial and many more examples.

The package is too large to present fully in a StackExchange post, so if you are interested, download it and read the tutorial, which has several more examples!

Note: The package comes with a tutorial and many more examples in its Documentation subdirectory.

The package is too large to present fully in a StackExchange post, so if you are interested, download it and read the tutorial, and take a look at the many examples that come with the package!

added 1320 characters in body
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k

###Here's how it works

Here's how it works

###Examples

Examples

LTemplate functions live in the mma C++ namespace. mma::RealTensorRef represents a reference to a Mathematica packed array of Reals. It is just a wrapper for the MTensor type. There may be more than one reference to the same array, so array creation and destruction must still be managed manually. A RealTensorRef allows convenient linear indexing into the array using the [ ] operator. RealMatrixRef and RealCubeRef are subclasses of  

RealTensorRef, which additionally allow indexing into 2D or 3D arrays using the (an alias for ( )TensorRef<double> operator.) has a number of convenience features:

  • Linear indexing into the array using the [ ] operator. RealMatrixRef and RealCubeRef are subclasses of RealTensorRef, which additionally allow indexing into 2D or 3D arrays using the ( ) operator.

  • Iteration through elements using begin() and end(). Range-based for loops work, e.g. we could have used for (auto &x : vec) sum += x;.

?MeanVariance class MeanVariance: Void compute({Real,Constant _List<Real, Constant}_>) Real mean() Real variance() 
  • Multiple related classes in the same template
  • Support for additional data types, such as SparseArray, RawArray, Image/Image3D
  • Pass another managed library expression to a function, and receive it as object reference on the C++ side (LExpressionID)
  • Format templates to be human-readable (FormatTemplate)
  • User-friendly error messages
  • Error handling through exceptions (mma::LibraryError); unknown exceptions are also caught to prevent killing the kernel when possible.
  • Calling Print for debugging (also through a C++ streams interface), massert macro to replace C's standard assert and avoid killing the Mathematica kernel.
  • Calling Message, setting a symbol to associate standard messages with
  • Argument passing and return using MathLink (LinkObject passing)
  • mlstream.h auxiliary header for easier LinkObject-based passing

###Questions and limitations

Questions and limitations

Why can't I use underscores in class or function names? LTemplate currently only supports names that are valid both in Mathematica and C++. This excludes underscores and \$ signs $ signs (even though *some* C++ compilers support `$`(even though some C++ compilers support $ in identifiers). This also helps avoid name conflicts with auxiliary functions LTemplate generates (which always have underscores).

  • The numerical type underlying tensors must be explicitly specified. Tensors without explicitly specified types are not supported. In the future tensors of unspecified types may be handled through C++ templates.

  • LibraryDataType[Image, ...] is not yet supported (MImage).

  • The support for LibraryDataType[SparseArray, ...] is still limited, but the basics are there.

  • There's no explicit support for library callback functions yet, but they can be used by accessing the standard LibraryLink API (function pointers in mma::libData).

###Feedback

Feedback

#define LTEMPLATE_MMA_VERSION 1120 #include "LTemplate.h" #include "LTemplateHelpers.h" #include "MeanVariance.h" namespace mma { WolframLibraryData libData; #define LTEMPLATE_MESSAGE_SYMBOL "LTemplate`LTemplate" #include "LTemplate.inc" } // namespace mma std::map<mint, MeanVariance *> MeanVariance_collection; DLLEXPORT void MeanVariance_manager_fun(WolframLibraryData libData, mbool mode, mint id) { if (mode == 0) { // create MeanVariance_collection[id] = new MeanVariance(); } else { // destroy if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return; } delete MeanVariance_collection[id]; MeanVariance_collection.erase(id); } } extern "C" DLLEXPORT int MeanVariance_get_collection(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::IntTensorRefTensorRef<mint> res = mma::detail::get_collection(MeanVariance_collection); mma::detail::setTensor<mint>(Res, res); return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT mint WolframLibrary_getVersion() { return WolframLibraryVersion;3; } extern "C" DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) { mma::libData = libData; { int err; err = (*libData->registerLibraryExpressionManager)("MeanVariance", MeanVariance_managerMeanVariance_manager_fun); if (err != LIBRARY_NO_ERROR) return err; } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) { (*libData->unregisterLibraryExpressionManager)("MeanVariance"); return; } extern "C" DLLEXPORT int MeanVariance_compute(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::detail::MOutFlushGuard flushguard; const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try  { mma::RealTensorRefTensorRef<double> var1 = mma::detail::getTensor<double>(Args[1]); (MeanVariance_collection[id])->compute(var1); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } catch (const std::exception & exc) { mma::detail::handleUnknownException(exc.what(), "MeanVariance::compute()"); return LIBRARY_FUNCTION_ERROR; } catch (...) { mma::detail::handleUnknownException(NULL, "MeanVariance::compute()");   return LIBRARY_FUNCTION_ERROR;  } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT int MeanVariance_mean(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::detail::MOutFlushGuard flushguard; const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try  { double res = (MeanVariance_collection[id])->mean(); MArgument_setReal(Res, res); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } catch (const std::exception & exc) {   mma::detail::handleUnknownException(exc.what(), "MeanVariance::mean()"); return LIBRARY_FUNCTION_ERROR;  } catch (...) { mma::detail::handleUnknownException(NULL, "MeanVariance::mean()"); return LIBRARY_FUNCTION_ERROR; } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT int MeanVariance_variance(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::detail::MOutFlushGuard flushguard; const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try  { double res = (MeanVariance_collection[id])->variance(); MArgument_setReal(Res, res); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } catch (const std::exception & exc) { mma::detail::handleUnknownException(exc.what(), "MeanVariance::variance()"); return LIBRARY_FUNCTION_ERROR; } catch (...) { mma::detail::handleUnknownException(NULL, "MeanVariance::variance()"); return LIBRARY_FUNCTION_ERROR; } return LIBRARY_NO_ERROR; } 

###Here's how it works

###Examples

LTemplate functions live in the mma C++ namespace. mma::RealTensorRef represents a reference to a Mathematica packed array of Reals. It is just a wrapper for the MTensor type. There may be more than one reference to the same array, so array creation and destruction must still be managed manually. A RealTensorRef allows convenient linear indexing into the array using the [ ] operator. RealMatrixRef and RealCubeRef are subclasses of RealTensorRef, which additionally allow indexing into 2D or 3D arrays using the ( ) operator.

?MeanVariance class MeanVariance: Void compute({Real, _, Constant}) Real mean() Real variance() 
  • Multiple related classes in the same template
  • Pass another managed library expression to a function, and receive it as object reference on the C++ side (LExpressionID)
  • Format templates to be human-readable (FormatTemplate)
  • User-friendly error messages
  • Error handling through exceptions (mma::LibraryError)
  • Calling Print for debugging (also through a C++ streams interface), massert macro to replace C's standard assert and avoid killing the Mathematica kernel.
  • Calling Message, setting a symbol to associate standard messages with
  • Argument passing and return using MathLink (LinkObject passing)
  • mlstream.h auxiliary header for

###Questions and limitations

Why can't I use underscores in class or function names? LTemplate currently only supports names that are valid both in Mathematica and C++. This excludes underscores and $ signs (even though *some* C++ compilers support `$` in identifiers). This also helps avoid name conflicts with auxiliary functions LTemplate generates (which always have underscores).

  • The numerical type underlying tensors must be explicitly specified. Tensors without explicitly specified types are not supported. In the future tensors of unspecified types may be handled through C++ templates.

  • LibraryDataType[Image, ...] is not yet supported (MImage).

  • The support for LibraryDataType[SparseArray, ...] is still limited, but the basics are there.

  • There's no explicit support for library callback functions yet, but they can be used by accessing the standard LibraryLink API (function pointers in mma::libData).

###Feedback

#include "LTemplate.h" #include "LTemplateHelpers.h" #include "MeanVariance.h" namespace mma { WolframLibraryData libData; #define LTEMPLATE_MESSAGE_SYMBOL "LTemplate`LTemplate" #include "LTemplate.inc" } // namespace mma std::map<mint, MeanVariance *> MeanVariance_collection; DLLEXPORT void MeanVariance_manager_fun(WolframLibraryData libData, mbool mode, mint id) { if (mode == 0) { // create MeanVariance_collection[id] = new MeanVariance(); } else { // destroy if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return; } delete MeanVariance_collection[id]; MeanVariance_collection.erase(id); } } extern "C" DLLEXPORT int MeanVariance_get_collection(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::IntTensorRef res = mma::detail::get_collection(MeanVariance_collection); mma::detail::setTensor<mint>(Res, res); return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT mint WolframLibrary_getVersion() { return WolframLibraryVersion; } extern "C" DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) { mma::libData = libData; { int err; err = (*libData->registerLibraryExpressionManager)("MeanVariance", MeanVariance_manager); if (err != LIBRARY_NO_ERROR) return err; } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) { (*libData->unregisterLibraryExpressionManager)("MeanVariance"); return; } extern "C" DLLEXPORT int MeanVariance_compute(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try { mma::RealTensorRef var1 = mma::detail::getTensor<double>(Args[1]); (MeanVariance_collection[id])->compute(var1); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT int MeanVariance_mean(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try { double res = (MeanVariance_collection[id])->mean(); MArgument_setReal(Res, res); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT int MeanVariance_variance(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try { double res = (MeanVariance_collection[id])->variance(); MArgument_setReal(Res, res); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } return LIBRARY_NO_ERROR; } 

Here's how it works

Examples

LTemplate functions live in the mma C++ namespace. mma::RealTensorRef represents a reference to a Mathematica packed array of Reals. It is just a wrapper for the MTensor type. There may be more than one reference to the same array, so array creation and destruction must still be managed manually. 

RealTensorRef (an alias for TensorRef<double>) has a number of convenience features:

  • Linear indexing into the array using the [ ] operator. RealMatrixRef and RealCubeRef are subclasses of RealTensorRef, which additionally allow indexing into 2D or 3D arrays using the ( ) operator.

  • Iteration through elements using begin() and end(). Range-based for loops work, e.g. we could have used for (auto &x : vec) sum += x;.

?MeanVariance class MeanVariance: Void compute(Constant List<Real, _>) Real mean() Real variance() 
  • Multiple related classes in the same template
  • Support for additional data types, such as SparseArray, RawArray, Image/Image3D
  • Pass another managed library expression to a function, and receive it as object reference on the C++ side (LExpressionID)
  • Format templates to be human-readable (FormatTemplate)
  • User-friendly error messages
  • Error handling through exceptions (mma::LibraryError); unknown exceptions are also caught to prevent killing the kernel when possible.
  • Calling Print for debugging (also through a C++ streams interface), massert macro to replace C's standard assert and avoid killing the Mathematica kernel.
  • Calling Message, setting a symbol to associate standard messages with
  • Argument passing and return using MathLink (LinkObject passing)
  • mlstream.h auxiliary header for easier LinkObject-based passing

Questions and limitations

Why can't I use underscores in class or function names? LTemplate currently only supports names that are valid both in Mathematica and C++. This excludes underscores and \$ signs (even though some C++ compilers support $ in identifiers). This also helps avoid name conflicts with auxiliary functions LTemplate generates (which always have underscores).

  • The numerical type underlying tensors must be explicitly specified. Tensors without explicitly specified types are not supported. In the future tensors of unspecified types may be handled through C++ templates.

  • There's no explicit support for library callback functions yet, but they can be used by accessing the standard LibraryLink API (function pointers in mma::libData).

Feedback

#define LTEMPLATE_MMA_VERSION 1120 #include "LTemplate.h" #include "LTemplateHelpers.h" #include "MeanVariance.h" #define LTEMPLATE_MESSAGE_SYMBOL "LTemplate`LTemplate" #include "LTemplate.inc" std::map<mint, MeanVariance *> MeanVariance_collection; DLLEXPORT void MeanVariance_manager_fun(WolframLibraryData libData, mbool mode, mint id) { if (mode == 0) { // create MeanVariance_collection[id] = new MeanVariance(); } else { // destroy if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return; } delete MeanVariance_collection[id]; MeanVariance_collection.erase(id); } } extern "C" DLLEXPORT int MeanVariance_get_collection(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::TensorRef<mint> res = mma::detail::get_collection(MeanVariance_collection); mma::detail::setTensor<mint>(Res, res); return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT mint WolframLibrary_getVersion() { return 3; } extern "C" DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) { mma::libData = libData; { int err; err = (*libData->registerLibraryExpressionManager)("MeanVariance", MeanVariance_manager_fun); if (err != LIBRARY_NO_ERROR) return err; } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) { (*libData->unregisterLibraryExpressionManager)("MeanVariance"); return; } extern "C" DLLEXPORT int MeanVariance_compute(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::detail::MOutFlushGuard flushguard; const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try  { mma::TensorRef<double> var1 = mma::detail::getTensor<double>(Args[1]); (MeanVariance_collection[id])->compute(var1); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } catch (const std::exception & exc) { mma::detail::handleUnknownException(exc.what(), "MeanVariance::compute()"); return LIBRARY_FUNCTION_ERROR; } catch (...) { mma::detail::handleUnknownException(NULL, "MeanVariance::compute()");   return LIBRARY_FUNCTION_ERROR;  } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT int MeanVariance_mean(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::detail::MOutFlushGuard flushguard; const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try  { double res = (MeanVariance_collection[id])->mean(); MArgument_setReal(Res, res); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } catch (const std::exception & exc) {   mma::detail::handleUnknownException(exc.what(), "MeanVariance::mean()"); return LIBRARY_FUNCTION_ERROR;  } catch (...) { mma::detail::handleUnknownException(NULL, "MeanVariance::mean()"); return LIBRARY_FUNCTION_ERROR; } return LIBRARY_NO_ERROR; } extern "C" DLLEXPORT int MeanVariance_variance(WolframLibraryData libData, mint Argc, MArgument * Args, MArgument Res) { mma::detail::MOutFlushGuard flushguard; const mint id = MArgument_getInteger(Args[0]); if (MeanVariance_collection.find(id) == MeanVariance_collection.end()) { libData->Message("noinst"); return LIBRARY_FUNCTION_ERROR; } try  { double res = (MeanVariance_collection[id])->variance(); MArgument_setReal(Res, res); } catch (const mma::LibraryError & libErr) { libErr.report(); return libErr.error_code(); } catch (const std::exception & exc) { mma::detail::handleUnknownException(exc.what(), "MeanVariance::variance()"); return LIBRARY_FUNCTION_ERROR; } catch (...) { mma::detail::handleUnknownException(NULL, "MeanVariance::variance()"); return LIBRARY_FUNCTION_ERROR; } return LIBRARY_NO_ERROR; } 
Bounty Awarded with 500 reputation awarded by xyz
added 33 characters in body
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k
Loading
added 184 characters in body
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k
Loading
added 1924 characters in body
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k
Loading
added 1924 characters in body
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k
Loading
Source Link
Szabolcs
  • 238.9k
  • 32
  • 653
  • 1.3k
Loading