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.
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!
###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.RealMatrixRefandRealCubeRefare subclasses ofRealTensorRef, which additionally allow indexing into 2D or 3D arrays using the( )operator.Iteration through elements using
begin()andend(). Range-based for loops work, e.g. we could have usedfor (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
Printfor debugging (also through a C++ streams interface),massertmacro to replace C's standardassertand avoid killing the Mathematica kernel. - Calling
Message, setting a symbol to associate standard messages with - Argument passing and return using MathLink (
LinkObjectpassing) mlstream.hauxiliary 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
Printfor debugging (also through a C++ streams interface),massertmacro to replace C's standardassertand avoid killing the Mathematica kernel. - Calling
Message, setting a symbol to associate standard messages with - Argument passing and return using MathLink (
LinkObjectpassing) mlstream.hauxiliary 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.RealMatrixRefandRealCubeRefare subclasses ofRealTensorRef, which additionally allow indexing into 2D or 3D arrays using the( )operator.Iteration through elements using
begin()andend(). Range-based for loops work, e.g. we could have usedfor (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
Printfor debugging (also through a C++ streams interface),massertmacro to replace C's standardassertand avoid killing the Mathematica kernel. - Calling
Message, setting a symbol to associate standard messages with - Argument passing and return using MathLink (
LinkObjectpassing) mlstream.hauxiliary 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; }