Added LTemplate files.

This commit is contained in:
v1j4y 2022-06-23 14:25:05 +02:00
parent d55ac90d9e
commit 732ab6f600
44 changed files with 157888 additions and 0 deletions

13
LTemplate.m Normal file
View File

@ -0,0 +1,13 @@
(* ::Package:: *)
(* This is a traditional package that uses BeginPackage instead of Package.
It loads LTemplate into the correct context. *)
BeginPackage["TestPackage`"]
Print[$InputFileName]
Get["`LTemplate`LTemplatePrivate`"];
ConfigureLTemplate["MessageSymbol" -> TestPackageSym, "LazyLoading" -> False]
EndPackage[]

View File

@ -0,0 +1,116 @@
#include <LTemplate.h>
// Let Armadillo print to Mathematica notebooks by default
#define ARMA_COUT_STREAM mma::mout
#define ARMA_CERR_STREAM mma::mout
#include <armadillo>
// We start by defining conversion functions to/from Armadillo's basic datatypes:
// matrices, column vectors and sparse matrices.
// Armadillo stores matrices in column major order, while Mathematica uses row-major order.
// It is thus fastest to convert an MTensor to/from its transposed Armadillo equivalent.
// Convert from Mathematica matrix to the transposed Armadillo equivalent without copying any data.
template<typename T>
arma::Mat<T> toArmaTransposed(mma::MatrixRef<T> m) {
// wrap MTensor with arma::mat without copying
// See the "Advanced Constructors" documentation http://arma.sourceforge.net/docs.html#Mat
return arma::Mat<T>(m.data(), m.cols(), m.rows(), false /* do not copy */, false /* until resized */);
}
// Convert from Armadillo matrix to transposed Mathematica matrix.
// This time the data must be copied.
template<typename T>
mma::TensorRef<T> fromArmaTransposed(const arma::Mat<T> &m) {
return mma::makeMatrix<T>(m.n_cols, m.n_rows, m.memptr());
}
// Convert from Mathematica vector to Armadillo column vector without copying.
template<typename T>
arma::Col<T> toArmaVec(mma::TensorRef<T> v) {
return arma::Col<T>(v.data(), v.size(), false /* do not copy */, false /* until resized */);
}
// Convert from Armadillo column vector to Mathematica vector with copying.
template<typename T>
mma::TensorRef<T> fromArmaVec(const arma::Col<T> &v) {
return mma::makeVector<T>(v.size(), v.memptr());
}
// Convert from Mathematica sparse matrix to Armadillo sparse matrix.
template<typename T>
arma::SpMat<T> toArmaSparseTransposed(mma::SparseMatrixRef<T> sm) {
return arma::SpMat<T>(
// Column indices and row pointers must be explicitly converted
// because Armadillo uses unsigned integers while Mathematica uses signed ones.
arma::conv_to<arma::uvec>::from(toArmaVec(sm.columnIndices())) - 1, // convert to 0-based indices; Mathematica uses 1-based ones.
arma::conv_to<arma::uvec>::from(toArmaVec(sm.rowPointers())),
toArmaVec(sm.explicitValues()),
sm.cols(), sm.rows()
);
}
// Convert from Armadillo sparse matrix to Mathematica SparseArray.
template<typename T>
mma::SparseMatrixRef<T> fromArmaSparse(const arma::SpMat<T> &am) {
// there are am.n_nonzero explicitly stored elements in am
auto pos = mma::makeMatrix<mint>(am.n_nonzero, 2); // positions array
auto vals = mma::makeVector<double>(am.n_nonzero); // values array
// iterate through all explicitly stored elements in the Armadillo sparse matrix and
// fill out the positions and values arrays to be used in the creation of a Mathematica SparseArray
mint i = 0;
for (typename arma::SpMat<T>::const_iterator it = am.begin();
it != am.end();
++it, ++i)
{
vals[i] = *it;
pos(i,0) = it.row() + 1; // convert 0-based index to 1-based
pos(i,1) = it.col() + 1;
}
auto mm = mma::makeSparseMatrix(pos, vals, am.n_rows, am.n_cols);
pos.free();
vals.free();
return mm;
}
class Arma {
public:
// Matrix inverse
mma::RealMatrixRef inv(mma::RealMatrixRef mat) {
arma::mat m = toArmaTransposed(mat);
return fromArmaTransposed<double>(arma::inv(m));
}
// The first k complex eigenvalues of a sparse matrix
mma::ComplexTensorRef eigs(mma::SparseMatrixRef<double> sm, mint k) {
return fromArmaVec<mma::complex_t>(arma::eigs_gen(toArmaSparseTransposed(sm), k));
}
// Random sparse matrix
mma::SparseMatrixRef<double> sprandu(mint i, mint j, double dens) {
return fromArmaSparse(arma::sprandu<arma::sp_mat>(i, j, dens));
}
// Solve a linear equation
mma::RealTensorRef solve(mma::RealMatrixRef mat, mma::RealTensorRef vec) {
return fromArmaVec<double>(
arma::solve(toArmaTransposed(mat).t(), // transpose back to match mat
toArmaVec(vec))
);
}
// Print an Armadillo matrix
void print(mma::RealMatrixRef mat) {
mma::mout << toArmaTransposed(mat).t();
}
// Print an Armadillo sparse matrix
void printSparse(mma::SparseMatrixRef<double> sm) {
mma::mout << toArmaSparseTransposed(sm);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
#include <LTemplate.h>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/isomorphism.hpp>
#include <boost/graph/boyer_myrvold_planar_test.hpp>
#include <vector>
// Graph class based on the Boost Graph Library
class BGraph {
using graph = boost::adjacency_list<
boost::vecS, boost::vecS, boost::undirectedS,
boost::property<boost::vertex_index_t, mint>,
boost::property<boost::edge_index_t, mint>
>;
using edge_iterator = boost::graph_traits<graph>::edge_iterator;
using edge_descriptor = boost::graph_traits<graph>::edge_descriptor;
graph g; // for simplicity, initialize with an empty graph
public:
// Set vertices and edges.
// Expected input: edge list with 0-based vertex indices.
void set(mint vcount, mma::IntMatrixRef elist) {
if (elist.cols() != 2)
throw mma::LibraryError("The edge list must be an n-by-2 matrix.");
g = graph(vcount); // create graph with appropriate number of edges
auto e_index = get(boost::edge_index, g);
for (int i=0; i < elist.rows(); ++i) {
auto aer = boost::add_edge(elist(i,0), elist(i,1), g); // add edge
put(e_index, aer.first, i); // initialize the interior edge index
}
}
// Vertex count.
mint vcount() const { return boost::num_vertices(g); }
// Edge count.
mint ecount() const { return boost::num_edges(g); }
// Retrive edge list.
// Output: edge list with 0-based vertex indices.
mma::IntMatrixRef edgeList() const {
auto elist = mma::makeMatrix<mint>(ecount(), 2);
edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
const auto i = get(boost::edge_index, g, *ei);
elist(i,0) = source(*ei, g);
elist(i,1) = target(*ei, g);
}
return elist;
}
// Isomorphism test
bool isomorphicQ(const BGraph &bg) const { return boost::isomorphism(g, bg.g); }
// Compute Kuratowski subdivison of non-planar graph
mma::IntTensorRef kuratowskiSubdivision() const {
std::vector<edge_descriptor> kuratowski_edges;
boost::boyer_myrvold_planarity_test(
boost::boyer_myrvold_params::graph = g,
boost::boyer_myrvold_params::kuratowski_subgraph = std::back_inserter(kuratowski_edges)
);
auto edge_indices = mma::makeVector<mint>(kuratowski_edges.size());
std::transform(
kuratowski_edges.begin(), kuratowski_edges.end(),
edge_indices.begin(),
[this] (edge_descriptor ed) { return get(boost::edge_index, g, ed); }
);
return edge_indices;
}
};

View File

@ -0,0 +1,985 @@
Notebook[{
Cell[CellGroupData[{
Cell["Interfacing with the Boost Graph Library", "Section",
ExpressionUUID -> "aa884a08-8724-4a0b-bbe5-6894c36af936"],
Cell["\<\
This example shows how to create a class that represents a graph, and run \
various algorithms on it using the Boost Graph Library.\
\>", "Text",
ExpressionUUID -> "0ef29b79-5af8-4918-8a14-11a8a85e43d4"],
Cell[BoxData[{
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}], ";"}]}], "Input",
ExpressionUUID -> "978a9ae9-dee6-4995-ac77-77a4bd3103c3"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=", "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{"\"\<BGraph\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<set\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{",
RowBox[{"Integer", " ",
RowBox[{"(*", " ",
RowBox[{"vertex", " ", "count"}], " ", "*)"}], ",",
"\[IndentingNewLine]",
RowBox[{"{",
RowBox[{"Integer", ",", "2", ",", "\"\<Constant\>\""}], "}"}]}],
" ",
RowBox[{"(*", " ",
RowBox[{"0", "-",
RowBox[{"based", " ", "indexed", " ", "edge", " ", "list"}]}],
" ", "*)"}], "}"}], ",", "\[IndentingNewLine]", "\"\<Void\>\""}],
"\[IndentingNewLine]", "]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<vcount\>\"", ",",
RowBox[{"{", "}"}], ",", "Integer"}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<ecount\>\"", ",",
RowBox[{"{", "}"}], ",", "Integer"}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<edgeList\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Integer", ",", "2"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<isomorphicQ\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{",
RowBox[{"LExpressionID", "[", "\"\<BGraph\>\"", "]"}], " ",
RowBox[{"(*", " ",
RowBox[{"the", " ", "other", " ", "graph"}], " ", "*)"}], "}"}],
",", "\[IndentingNewLine]",
RowBox[{"True", "|", "False"}]}], "\[IndentingNewLine]", "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<kuratowskiSubdivision\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Integer", ",", "1"}], "}"}]}], " ",
RowBox[{"(*", " ",
RowBox[{"edge", " ", "indices"}], " ", "*)"}], "]"}]}],
"\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]", "]"}]}],
";"}]], "Input",
ExpressionUUID -> "72378522-fb62-4f9c-8d3f-92fbc6288650"],
Cell["\<\
To compile this example, it is necessary to indicate the location of the \
Boost headers. Adjust this according to your system.\
\>", "Text",
ExpressionUUID -> "d6d6fe8c-81d4-4580-9546-8cc36aaa6eda"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"CompileTemplate", "[",
RowBox[{"template", ",", "\[IndentingNewLine]",
RowBox[{"\"\<IncludeDirectories\>\"", "\[Rule]",
RowBox[{"{", "\"\</opt/local/include\>\"", "}"}]}]}], " ",
RowBox[{"(*", " ",
RowBox[{"Boost", " ", "location"}], " ", "*)"}], "\[IndentingNewLine]",
"]"}]], "Input",
ExpressionUUID -> "a8045402-4022-4ecb-8598-fadac4343f5b"],
Cell[CellGroupData[{
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Current directory is: \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/\
Examples/BGraph\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Current directory is: ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
BGraph",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "26b4ea99-649a-4493-8698-93dea00ec109"],
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Unloading library \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"BGraph\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\" ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Unloading library ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["BGraph",
RGBColor[0, 0,
Rational[2, 3]]],
Style[" ...",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "26b4ea99-649a-4493-8698-93dea00ec109"],
Cell[BoxData[
StyleBox["\<\"Generating library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "26b4ea99-649a-4493-8698-93dea00ec109"],
Cell[BoxData[
StyleBox["\<\"Compiling library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "26b4ea99-649a-4493-8698-93dea00ec109"]
}, Open ]],
Cell[BoxData["\<\"/Users/szhorvat/Library/Mathematica/SystemFiles/\
LibraryResources/MacOSX-x86-64/BGraph.dylib\"\>"], "Output",
ExpressionUUID -> "840d4b10-2e8f-4954-8708-8fc124ee6fa1"]
}, Open ]],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "b54a2e2b-71f0-4352-8b31-66e687bf008f"],
Cell[CellGroupData[{
Cell["Create graphs", "Subsubsection",
ExpressionUUID -> "d5c63930-33b8-4220-9037-dab8375a7462"],
Cell["\<\
Since LTemplate does not currently support passing arguments to constructors, \
the BGraph object is created in two steps:\
\>", "Text",
ExpressionUUID -> "0f5ba9c6-8c9c-4b01-a9df-1db10ffa1d04"],
Cell[CellGroupData[{
Cell["Create an empty graph", "Item",
ExpressionUUID -> "15fefd58-434d-4b4d-98a1-284f858116e0"],
Cell["Set edges and vertices", "Item",
ExpressionUUID -> "5dbaf41d-e438-46c3-bde4-3ab1a12605fe"]
}, Open ]],
Cell["\<\
The following function handles all of this. We will use only this function to \
create BGraphs to ensure that they have been correctly initialized.\
\>", "Text",
ExpressionUUID -> "443e6f8a-3657-4581-a2fe-f79b14b13a8c"],
Cell["\<\
IndexGraph is not particularly fast, but we shall use it for the sake of \
simplicity. The set function expects zero-based indices, therefore we must \
subtract 1.\
\>", "Text",
ExpressionUUID -> "863c26ce-b730-467b-aa20-a4496c915d92"],
Cell[BoxData[
RowBox[{
RowBox[{"makeBGraph", "[",
RowBox[{"g_", "?", "UndirectedGraphQ"}], "]"}], ":=",
"\[IndentingNewLine]",
RowBox[{"Block", "[",
RowBox[{
RowBox[{"{",
RowBox[{"bg", "=",
RowBox[{"Make", "[", "BGraph", "]"}]}], "}"}], ",",
"\[IndentingNewLine]",
RowBox[{
RowBox[{"bg", "@",
RowBox[{"\"\<set\>\"", "[",
RowBox[{
RowBox[{"VertexCount", "[", "g", "]"}], ",",
RowBox[{
RowBox[{"List", "@@@",
RowBox[{"EdgeList", "@",
RowBox[{"IndexGraph", "[", "g", "]"}]}]}], "-", "1"}]}], "]"}]}],
";", "\[IndentingNewLine]", "bg"}]}], "\[IndentingNewLine]",
"]"}]}]], "Input",
ExpressionUUID -> "a97ac584-7bf7-4cb1-aa00-ee13e8d901c1"],
Cell["Let\[CloseCurlyQuote]s convert the following graph to a BGraph:", "Text",
ExpressionUUID -> "a3d5cb7d-ea6c-4e07-8c71-0841fe32fed4"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"pg", "=",
RowBox[{"PetersenGraph", "[", "]"}]}]], "Input",
ExpressionUUID -> "34e4f8f6-0463-4722-8961-331d8f3e32d9"],
Cell[BoxData[
GraphicsBox[
NamespaceBox["NetworkGraphics",
DynamicModuleBox[{Typeset`graph = HoldComplete[
Graph[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {
Null, {{1, 3}, {1, 4}, {1, 6}, {2, 4}, {2, 5}, {2, 7}, {3, 5}, {3, 8}, {
4, 9}, {5, 10}, {6, 7}, {6, 10}, {7, 8}, {8, 9}, {9, 10}}}, {
VertexCoordinates -> {{0.9510565162951535, 0.30901699437494745`}, {
0.5877852522924732, -0.8090169943749473}, {-0.587785252292473, \
-0.8090169943749476}, {-0.9510565162951536,
0.30901699437494723`}, {-2.4492935982947064`*^-16, 1.}, {
1.902113032590307, 0.6180339887498949}, {
1.1755705045849465`, -1.6180339887498947`}, {-1.175570504584946, \
-1.6180339887498951`}, {-1.9021130325903073`,
0.6180339887498945}, {-4.898587196589413*^-16, 2.}}}]]},
TagBox[
GraphicsGroupBox[
GraphicsComplexBox[{{0.9510565162951535, 0.30901699437494745`}, {
0.5877852522924732, -0.8090169943749473}, {-0.587785252292473, \
-0.8090169943749476}, {-0.9510565162951536,
0.30901699437494723`}, {-2.4492935982947064`*^-16, 1.}, {
1.902113032590307, 0.6180339887498949}, {
1.1755705045849465`, -1.6180339887498947`}, {-1.175570504584946, \
-1.6180339887498951`}, {-1.9021130325903073`,
0.6180339887498945}, {-4.898587196589413*^-16, 2.}}, {
{Hue[0.6, 0.7, 0.5], Opacity[0.7],
{Arrowheads[0.], ArrowBox[{1, 3}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{1, 4}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{1, 6}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{2, 4}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{2, 5}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{2, 7}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{3, 5}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{3, 8}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{4, 9}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{5, 10}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{6, 7}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{6, 10}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{7, 8}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{8, 9}, 0.03574187784409402]},
{Arrowheads[0.], ArrowBox[{9, 10}, 0.03574187784409402]}},
{Hue[0.6, 0.2, 0.8], EdgeForm[{GrayLevel[0], Opacity[0.7]}],
DiskBox[1, 0.03574187784409402], DiskBox[2, 0.03574187784409402],
DiskBox[3, 0.03574187784409402], DiskBox[4, 0.03574187784409402],
DiskBox[5, 0.03574187784409402], DiskBox[6, 0.03574187784409402],
DiskBox[7, 0.03574187784409402], DiskBox[8, 0.03574187784409402],
DiskBox[9, 0.03574187784409402], DiskBox[10, 0.03574187784409402]}}]],
MouseAppearanceTag["NetworkGraphics"]],
AllowKernelInitialization->False]],
DefaultBaseStyle->{
"NetworkGraphics", FrontEnd`GraphicsHighlightColor -> Hue[0.8, 1., 0.6]},
FrameTicks->None,
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]]]], "Output",
ExpressionUUID -> "2728ee8c-fc48-4a9d-9129-9d80455b0b70"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"bg", "=",
RowBox[{"makeBGraph", "[", "pg", "]"}]}]], "Input",
ExpressionUUID -> "82e12ead-05f1-41e9-8ae1-4523e471cf24"],
Cell[BoxData[
RowBox[{"BGraph", "[", "1", "]"}]], "Output",
ExpressionUUID -> "8d1730d3-d6fb-4f22-8435-71fc4923c556"]
}, Open ]]
}, Open ]],
Cell[CellGroupData[{
Cell["Retrieve basic properties", "Subsubsection",
ExpressionUUID -> "ea7843fc-c17b-4122-b1bb-45dc2250980f"],
Cell["How many vertices does it have?", "Text",
ExpressionUUID -> "1a73c6c9-f664-476f-9973-ff8a64c0d1b4"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"bg", "@",
RowBox[{"\"\<vcount\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "20a28eb0-555f-40c7-8308-e0773b60bb58"],
Cell[BoxData["10"], "Output",
ExpressionUUID -> "fa8d3a82-3793-43d0-845a-8114d20da8ab"]
}, Open ]],
Cell["How many edges does it have?", "Text",
ExpressionUUID -> "cca07f74-dd9d-40c6-80d7-dafddcd8a719"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"bg", "@",
RowBox[{"\"\<ecount\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "742a3af0-a9dc-4fa9-a297-e7d4f89885c6"],
Cell[BoxData["15"], "Output",
ExpressionUUID -> "2ba271ae-d759-45eb-97ab-c93ad3fd0c55"]
}, Open ]],
Cell["Retrieve the edge list.", "Text",
ExpressionUUID -> "77d0c741-8d01-4279-b7d4-cbcb6c98a16c"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"bg", "@",
RowBox[{"\"\<edgeList\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "077bae0c-1dbb-4829-902a-86b4d8068303"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"0", ",", "2"}], "}"}], ",",
RowBox[{"{",
RowBox[{"0", ",", "3"}], "}"}], ",",
RowBox[{"{",
RowBox[{"0", ",", "5"}], "}"}], ",",
RowBox[{"{",
RowBox[{"1", ",", "3"}], "}"}], ",",
RowBox[{"{",
RowBox[{"1", ",", "4"}], "}"}], ",",
RowBox[{"{",
RowBox[{"1", ",", "6"}], "}"}], ",",
RowBox[{"{",
RowBox[{"2", ",", "4"}], "}"}], ",",
RowBox[{"{",
RowBox[{"2", ",", "7"}], "}"}], ",",
RowBox[{"{",
RowBox[{"3", ",", "8"}], "}"}], ",",
RowBox[{"{",
RowBox[{"4", ",", "9"}], "}"}], ",",
RowBox[{"{",
RowBox[{"5", ",", "6"}], "}"}], ",",
RowBox[{"{",
RowBox[{"5", ",", "9"}], "}"}], ",",
RowBox[{"{",
RowBox[{"6", ",", "7"}], "}"}], ",",
RowBox[{"{",
RowBox[{"7", ",", "8"}], "}"}], ",",
RowBox[{"{",
RowBox[{"8", ",", "9"}], "}"}]}], "}"}]], "Output",
ExpressionUUID -> "7fab54c6-d92f-43ad-a525-a0d1e3db563d"]
}, Open ]],
Cell["\<\
Convert to a Mathematica Graph with vertices labelled from 1 (instead of 0).\
\>", "Text",
ExpressionUUID -> "bb99f19b-3ddb-47d7-b9e8-e647810ef431"],
Cell[BoxData[
RowBox[{
RowBox[{"fromBGraph", "[", "bg_BGraph", "]"}], ":=", "\[IndentingNewLine]",
RowBox[{"Graph", "[",
RowBox[{
RowBox[{"Range", "[",
RowBox[{"bg", "@",
RowBox[{"\"\<vcount\>\"", "[", "]"}]}], "]"}], ",",
RowBox[{"1", "+",
RowBox[{"bg", "@",
RowBox[{"\"\<edgeList\>\"", "[", "]"}]}]}], ",",
RowBox[{"DirectedEdges", "\[Rule]", "False"}]}], "]"}]}]], "Input",
ExpressionUUID -> "d48948ea-3ba1-4e1b-af8c-70946e65dca9"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"fromBGraph", "[", "bg", "]"}]], "Input",
ExpressionUUID -> "d20d883e-2eae-4153-a2fa-3ac7cd828056"],
Cell[BoxData[
GraphicsBox[
NamespaceBox["NetworkGraphics",
DynamicModuleBox[{Typeset`graph = HoldComplete[
Graph[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {
Null, {{1, 3}, {1, 4}, {1, 6}, {2, 4}, {2, 5}, {2, 7}, {3, 5}, {3, 8}, {
4, 9}, {5, 10}, {6, 7}, {6, 10}, {7, 8}, {8, 9}, {9, 10}}}]]},
TagBox[
GraphicsGroupBox[
GraphicsComplexBox[{{1.8750105837989297`, 0.733244241062911}, {
1.8415650123658316`, 1.3620813936125686`}, {1.1749364294125422`,
0.39951830930753657`}, {0.9014384102184719, 0.9286633426597406}, {
1.8190275035455308`, 0.09019481978361599}, {1.2929028389366695`,
1.1785381450163794`}, {1.0513121542102433`, 1.9864048777087877`}, {
0.27259657017746486`, 1.2771371290432734`}, {0.,
0.48128666421627553`}, {0.8106136635018724, 0.}}, {
{Hue[0.6, 0.7, 0.5], Opacity[0.7],
{Arrowheads[0.], ArrowBox[{1, 3}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{1, 4}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{1, 6}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{2, 4}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{2, 5}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{2, 7}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{3, 5}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{3, 8}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{4, 9}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{5, 10}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{6, 7}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{6, 10}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{7, 8}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{8, 9}, 0.02250105963782012]},
{Arrowheads[0.], ArrowBox[{9, 10}, 0.02250105963782012]}},
{Hue[0.6, 0.2, 0.8], EdgeForm[{GrayLevel[0], Opacity[0.7]}],
DiskBox[1, 0.02250105963782012], DiskBox[2, 0.02250105963782012],
DiskBox[3, 0.02250105963782012], DiskBox[4, 0.02250105963782012],
DiskBox[5, 0.02250105963782012], DiskBox[6, 0.02250105963782012],
DiskBox[7, 0.02250105963782012], DiskBox[8, 0.02250105963782012],
DiskBox[9, 0.02250105963782012], DiskBox[10, 0.02250105963782012]}}]],
MouseAppearanceTag["NetworkGraphics"]],
AllowKernelInitialization->False]],
DefaultBaseStyle->{
"NetworkGraphics", FrontEnd`GraphicsHighlightColor -> Hue[0.8, 1., 0.6]},
FrameTicks->None,
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]]]], "Output",
ExpressionUUID -> "d2a5a57b-d954-4d4d-823c-a3e6f55586e9"]
}, Open ]],
Cell["\<\
Verify that it is indeed the same graph, with the same edge ordering:\
\>", "Text",
ExpressionUUID -> "44e63c1f-4e60-443b-9f21-179f10cc5a1b"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{"EdgeList", "[",
RowBox[{"fromBGraph", "[", "bg", "]"}], "]"}], "===",
RowBox[{"EdgeList", "@",
RowBox[{"IndexGraph", "[", "pg", "]"}]}]}]], "Input",
ExpressionUUID -> "b78cf826-1a21-49e5-af94-3bc3bfc6491a"],
Cell[BoxData["True"], "Output",
ExpressionUUID -> "353d8e39-9b8d-42f9-8651-4b8448051f4a"]
}, Open ]]
}, Open ]],
Cell[CellGroupData[{
Cell["Run graph algorithms", "Subsubsection",
ExpressionUUID -> "006201b5-7775-4b41-b5cb-e0a1aa4a1371"],
Cell["Run the isomorphism algorithm.", "Text",
ExpressionUUID -> "7128c8bd-c750-4132-b4f7-c9c7a25bd5e5"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"bg2", "=",
RowBox[{"makeBGraph", "[",
RowBox[{"GraphData", "[", "\"\<PetersenGraph\>\"", "]"}], "]"}]}]], "Input",
ExpressionUUID -> "5ada7d10-ff87-4af2-99f5-da05449dc9e1"],
Cell[BoxData[
RowBox[{"BGraph", "[", "2", "]"}]], "Output",
ExpressionUUID -> "5393bb6b-e8ad-4ddb-90b9-b991bc601566"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"bg", "@",
RowBox[{"\"\<isomorphicQ\>\"", "[",
RowBox[{"ManagedLibraryExpressionID", "[", "bg2", "]"}], "]"}]}]], "Input",
ExpressionUUID -> "ccda914c-ccd5-4de5-93a5-32f6976820b9"],
Cell[BoxData["True"], "Output",
ExpressionUUID -> "5fadbaa2-c984-4a51-b088-b1bdb4a7d663"]
}, Open ]],
Cell["\<\
Wrap the function for convenient isomorphism checking of Mathematica Graphs.\
\>", "Text",
ExpressionUUID -> "3f76d1e0-bb97-48ba-935a-037e49f98985"],
Cell[BoxData[
RowBox[{
RowBox[{"isomorphicQ", "[",
RowBox[{
RowBox[{"g1_", "?", "UndirectedGraphQ"}], ",",
RowBox[{"g2_", "?", "UndirectedGraphQ"}]}], "]"}], ":=",
"\[IndentingNewLine]",
RowBox[{"Block", "[",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"bg1", "=",
RowBox[{"makeBGraph", "[", "g1", "]"}]}], ",",
RowBox[{"bg2", "=",
RowBox[{"makeBGraph", "[", "g2", "]"}]}]}], "}"}], ",",
"\[IndentingNewLine]",
RowBox[{"bg1", "@",
RowBox[{"\"\<isomorphicQ\>\"", "[",
RowBox[{"ManagedLibraryExpressionID", "[", "bg2", "]"}], "]"}]}]}],
"\[IndentingNewLine]", "]"}]}]], "Input",
ExpressionUUID -> "f1de92a5-ee30-47b7-9e51-06430b8ab0e3"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"isomorphicQ", "[",
RowBox[{
RowBox[{"Graph", "[",
RowBox[{"{",
RowBox[{
RowBox[{"1", "\[UndirectedEdge]", "2"}], ",",
RowBox[{"2", "\[UndirectedEdge]", "3"}]}], "}"}], "]"}], ",",
RowBox[{"Graph", "[",
RowBox[{"{",
RowBox[{
RowBox[{"1", "\[UndirectedEdge]", "3"}], ",",
RowBox[{"2", "\[UndirectedEdge]", "3"}]}], "}"}], "]"}]}],
"]"}]], "Input",
ExpressionUUID -> "4499c911-4c58-4bbb-abb7-0237457b0473"],
Cell[BoxData["True"], "Output",
ExpressionUUID -> "a02d2212-e6fe-4e70-b330-f78e3a203c0f"]
}, Open ]],
Cell["\<\
Let us compute a Kuratowski subdivision of a non-planar graph.\
\>", "Text",
ExpressionUUID -> "4c3bc4d3-c457-46c1-a5c0-e8d2d0e63fb9"],
Cell[BoxData[
RowBox[{
RowBox[{"kuratowskiSubdivision", "[",
RowBox[{"g_", "?", "UndirectedGraphQ"}], "]"}], ":=",
"\[IndentingNewLine]",
RowBox[{"Block", "[",
RowBox[{
RowBox[{"{",
RowBox[{"bg", "=",
RowBox[{"makeBGraph", "[", "g", "]"}]}], "}"}], ",",
"\[IndentingNewLine]",
RowBox[{"Part", "[",
RowBox[{
RowBox[{"EdgeList", "[", "g", "]"}], ",",
RowBox[{"1", "+",
RowBox[{"bg", "@",
RowBox[{"\"\<kuratowskiSubdivision\>\"", "[", "]"}]}]}]}], "]"}]}],
"\[IndentingNewLine]", "]"}]}]], "Input",
ExpressionUUID -> "296d406b-a5ec-4462-b98f-104ed144c9f5"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"npg", "=",
RowBox[{"GraphData", "[",
RowBox[{"{",
RowBox[{"\"\<Cone\>\"", ",",
RowBox[{"{",
RowBox[{"4", ",", "7"}], "}"}]}], "}"}], "]"}]}]], "Input",
ExpressionUUID -> "c263174f-c3e5-4bf3-997e-29138e40b539"],
Cell[BoxData[
GraphicsBox[
NamespaceBox["NetworkGraphics",
DynamicModuleBox[{Typeset`graph = HoldComplete[
Graph[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {Null,
SparseArray[
Automatic, {11, 11}, 0, {
1, {{0, 9, 18, 27, 36, 40, 44, 48, 52, 56, 60, 64}, {{2}, {4}, {5}, {
6}, {7}, {8}, {9}, {10}, {11}, {1}, {3}, {5}, {6}, {7}, {8}, {9}, {
10}, {11}, {2}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {1}, {
3}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {1}, {2}, {3}, {4}, {1}, {
2}, {3}, {4}, {1}, {2}, {3}, {4}, {1}, {2}, {3}, {4}, {1}, {2}, {
3}, {4}, {1}, {2}, {3}, {4}, {1}, {2}, {3}, {4}}}, Pattern}]}]]},
TagBox[
GraphicsGroupBox[
GraphicsComplexBox[{{0.780774697805059, 1.199409711066857}, {
1.1999525032799427`, 0.8319430146461535}, {0.8200678462633789,
0.7964395160694195}, {1.1631489624818339`, 1.2336554432233262`}, {
1.436385194178687, 1.9305572632126569`}, {0., 1.2362392592240465`}, {
1.9812731165155193`, 1.2361258172872176`}, {0.9886961315621108, 0.}, {
1.7894534978737644`, 0.3840372833294744}, {0.5527059960246021,
1.932547584373542}, {0.18951736097760385`, 0.3902718952492563}}, {
{Hue[0.6, 0.7, 0.5], Opacity[0.7],
{Arrowheads[0.], ArrowBox[{1, 2}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 4}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 5}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 6}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 7}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 8}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 9}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 10}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{1, 11}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 3}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 5}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 6}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 7}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 8}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 9}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 10}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{2, 11}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 4}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 5}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 6}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 7}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 8}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 9}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 10}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{3, 11}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{4, 5}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{4, 6}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{4, 7}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{4, 8}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{4, 9}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{4, 10}, 0.02245933508462397]},
{Arrowheads[0.], ArrowBox[{4, 11}, 0.02245933508462397]}},
{Hue[0.6, 0.2, 0.8], EdgeForm[{GrayLevel[0], Opacity[0.7]}],
DiskBox[1, 0.02245933508462397], DiskBox[2, 0.02245933508462397],
DiskBox[3, 0.02245933508462397], DiskBox[4, 0.02245933508462397],
DiskBox[5, 0.02245933508462397], DiskBox[6, 0.02245933508462397],
DiskBox[7, 0.02245933508462397], DiskBox[8, 0.02245933508462397],
DiskBox[9, 0.02245933508462397], DiskBox[10, 0.02245933508462397],
DiskBox[11, 0.02245933508462397]}}]],
MouseAppearanceTag["NetworkGraphics"]],
AllowKernelInitialization->False]],
DefaultBaseStyle->{
"NetworkGraphics", FrontEnd`GraphicsHighlightColor -> Hue[0.8, 1., 0.6]},
FrameTicks->None,
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]]]], "Output",
ExpressionUUID -> "21ac32cf-65f2-4897-aa63-dbc1bfa803be"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"kuratowskiSubdivision", "[", "npg", "]"}]], "Input",
ExpressionUUID -> "505b1e60-9260-43b2-98e3-382c63076f42"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"1", "\[UndirectedEdge]", "2"}], ",",
RowBox[{"2", "\[UndirectedEdge]", "5"}], ",",
RowBox[{"2", "\[UndirectedEdge]", "6"}], ",",
RowBox[{"2", "\[UndirectedEdge]", "7"}], ",",
RowBox[{"3", "\[UndirectedEdge]", "5"}], ",",
RowBox[{"3", "\[UndirectedEdge]", "6"}], ",",
RowBox[{"3", "\[UndirectedEdge]", "7"}], ",",
RowBox[{"4", "\[UndirectedEdge]", "5"}], ",",
RowBox[{"4", "\[UndirectedEdge]", "6"}], ",",
RowBox[{"4", "\[UndirectedEdge]", "7"}]}], "}"}]], "Output",
ExpressionUUID -> "f85fa7a7-747b-471e-8058-d86250add82f"]
}, Open ]],
Cell["\<\
The function returns it as a list of edge indices, which we transform to an \
edge list in Mathematica. Let us visualize it.\
\>", "Text",
ExpressionUUID -> "187c2fe1-68a5-4036-bcfc-6616ddc9bfc9"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"HighlightGraph", "[",
RowBox[{"npg", ",",
RowBox[{"Subgraph", "[",
RowBox[{"npg", ",",
RowBox[{"kuratowskiSubdivision", "[", "npg", "]"}]}], "]"}]}],
"]"}]], "Input",
ExpressionUUID -> "6c3bf6da-8056-4946-94f3-93d61584acbf"],
Cell[BoxData[
GraphicsBox[
NamespaceBox["NetworkGraphics",
DynamicModuleBox[{Typeset`graph = HoldComplete[
Graph[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {Null,
SparseArray[
Automatic, {11, 11}, 0, {
1, {{0, 9, 18, 27, 36, 40, 44, 48, 52, 56, 60, 64}, {{2}, {4}, {5}, {
6}, {7}, {8}, {9}, {10}, {11}, {1}, {3}, {5}, {6}, {7}, {8}, {9}, {
10}, {11}, {2}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {1}, {
3}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {1}, {2}, {3}, {4}, {1}, {
2}, {3}, {4}, {1}, {2}, {3}, {4}, {1}, {2}, {3}, {4}, {1}, {2}, {
3}, {4}, {1}, {2}, {3}, {4}, {1}, {2}, {3}, {4}}}, Pattern}]}, {
GraphHighlight -> {
UndirectedEdge[5, 4],
UndirectedEdge[2, 3],
UndirectedEdge[7, 4],
UndirectedEdge[1, 5],
UndirectedEdge[5, 3],
UndirectedEdge[7, 3], 1,
UndirectedEdge[2, 6], 6, 5,
UndirectedEdge[2, 7],
UndirectedEdge[1, 7],
UndirectedEdge[1, 4],
UndirectedEdge[6, 4],
UndirectedEdge[1, 2],
UndirectedEdge[1, 6], 7, 2,
UndirectedEdge[6, 3],
UndirectedEdge[3, 4],
UndirectedEdge[2, 5], 4, 3}}]]},
TagBox[
GraphicsGroupBox[
GraphicsComplexBox[{{0.780774697805059, 1.199409711066857}, {
1.1999525032799427`, 0.8319430146461535}, {0.8200678462633789,
0.7964395160694195}, {1.1631489624818339`, 1.2336554432233262`}, {
1.436385194178687, 1.9305572632126569`}, {0., 1.2362392592240465`}, {
1.9812731165155193`, 1.2361258172872176`}, {0.9886961315621108, 0.}, {
1.7894534978737644`, 0.3840372833294744}, {0.5527059960246021,
1.932547584373542}, {0.18951736097760385`, 0.3902718952492563}}, {
{Hue[0.6, 0.7, 0.5], Opacity[0.7],
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
1.1999525032799427`, 0.8319430146461535}}, 0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
1.1631489624818339`, 1.2336554432233262`}},
0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
1.436385194178687, 1.9305572632126569`}},
0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {0.,
1.2362392592240465`}}, 0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
1.9812731165155193`, 1.2361258172872176`}},
0.02245933508462397]}},
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
0.9886961315621108, 0.}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
1.7894534978737644`, 0.3840372833294744}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
0.5527059960246021, 1.932547584373542}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{0.780774697805059, 1.199409711066857}, {
0.18951736097760385`, 0.3902718952492563}},
0.02245933508462397]},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {
0.8200678462633789, 0.7964395160694195}},
0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {
1.436385194178687, 1.9305572632126569`}},
0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {0.,
1.2362392592240465`}}, 0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {
1.9812731165155193`, 1.2361258172872176`}},
0.02245933508462397]}},
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {
0.9886961315621108, 0.}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {
1.7894534978737644`, 0.3840372833294744}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {
0.5527059960246021, 1.932547584373542}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{1.1999525032799427`, 0.8319430146461535}, {
0.18951736097760385`, 0.3902718952492563}},
0.02245933508462397]},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {
1.1631489624818339`, 1.2336554432233262`}},
0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {
1.436385194178687, 1.9305572632126569`}},
0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {0.,
1.2362392592240465`}}, 0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {
1.9812731165155193`, 1.2361258172872176`}},
0.02245933508462397]}},
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {
0.9886961315621108, 0.}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {
1.7894534978737644`, 0.3840372833294744}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {
0.5527059960246021, 1.932547584373542}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{0.8200678462633789, 0.7964395160694195}, {
0.18951736097760385`, 0.3902718952492563}},
0.02245933508462397]},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{1.1631489624818339`, 1.2336554432233262`}, {
1.436385194178687, 1.9305572632126569`}},
0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{1.1631489624818339`, 1.2336554432233262`}, {0.,
1.2362392592240465`}}, 0.02245933508462397]}},
{Hue[1, 1, 0.7], Opacity[1],
{Arrowheads[0.],
ArrowBox[{{1.1631489624818339`, 1.2336554432233262`}, {
1.9812731165155193`, 1.2361258172872176`}},
0.02245933508462397]}},
{Arrowheads[0.],
ArrowBox[{{1.1631489624818339`, 1.2336554432233262`}, {
0.9886961315621108, 0.}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{1.1631489624818339`, 1.2336554432233262`}, {
1.7894534978737644`, 0.3840372833294744}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{1.1631489624818339`, 1.2336554432233262`}, {
0.5527059960246021, 1.932547584373542}}, 0.02245933508462397]},
{Arrowheads[0.],
ArrowBox[{{1.1631489624818339`, 1.2336554432233262`}, {
0.18951736097760385`, 0.3902718952492563}}, 0.02245933508462397]}},
{Hue[0.6, 0.2, 0.8], EdgeForm[{GrayLevel[0], Opacity[0.7]}],
{Hue[1, 1, 0.7], EdgeForm[{Hue[1, 1, 0.7], Opacity[1]}],
DiskBox[1, 0.02245933508462397]},
{Hue[1, 1, 0.7], EdgeForm[{Hue[1, 1, 0.7], Opacity[1]}],
DiskBox[2, 0.02245933508462397]},
{Hue[1, 1, 0.7], EdgeForm[{Hue[1, 1, 0.7], Opacity[1]}],
DiskBox[3, 0.02245933508462397]},
{Hue[1, 1, 0.7], EdgeForm[{Hue[1, 1, 0.7], Opacity[1]}],
DiskBox[4, 0.02245933508462397]},
{Hue[1, 1, 0.7], EdgeForm[{Hue[1, 1, 0.7], Opacity[1]}],
DiskBox[5, 0.02245933508462397]},
{Hue[1, 1, 0.7], EdgeForm[{Hue[1, 1, 0.7], Opacity[1]}],
DiskBox[6, 0.02245933508462397]},
{Hue[1, 1, 0.7], EdgeForm[{Hue[1, 1, 0.7], Opacity[1]}],
DiskBox[7, 0.02245933508462397]}, DiskBox[8, 0.02245933508462397],
DiskBox[9, 0.02245933508462397], DiskBox[10, 0.02245933508462397],
DiskBox[11, 0.02245933508462397]}}]],
MouseAppearanceTag["NetworkGraphics"]],
AllowKernelInitialization->False]],
DefaultBaseStyle->{
"NetworkGraphics", FrontEnd`GraphicsHighlightColor -> Hue[0.8, 1., 0.6]},
FrameTicks->None,
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]]]], "Output",
ExpressionUUID -> "4581a286-c75f-4757-8653-4b6d4378c180"]
}, Open ]],
Cell["For planar graphs, the function returns the empty list.", "Text",
ExpressionUUID -> "cf1d13e4-9d78-4d46-92cf-0ee99f6206d2"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"kuratowskiSubdivision", "[",
RowBox[{"CycleGraph", "[", "5", "]"}], "]"}]], "Input",
ExpressionUUID -> "2647bdf5-f0b8-4a77-a554-893f75eea34e"],
Cell[BoxData[
RowBox[{"{", "}"}]], "Output",
ExpressionUUID -> "6b676bec-d857-4cfb-a509-467344ec6278"]
}, Open ]]
}, Open ]]
}, Open ]]
},
WindowSize->{808, 755},
WindowMargins->{{302, Automatic}, {Automatic, 40}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
TrackCellChangeTimes->False,
FrontEndVersion->"10.3 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 10, \
2015)",
StyleDefinitions->"Default.nb"
]

View File

@ -0,0 +1,21 @@
#include <LTemplate.h>
#include <complex>
struct Basics {
// Add two real numbers.
double add(double x, double y) {
return x+y;
}
// How many times does z -> z^2 + c need to be iterated before abs(z) > 2?
mint mandel(mma::complex_t c, mint max_iter) {
mint iter = 0;
mma::complex_t z = 0;
while (std::abs(z) < 2 && iter < max_iter) {
z = z*z + c;
iter++;
}
return iter;
}
};

View File

@ -0,0 +1,723 @@
Notebook[{
Cell[CellGroupData[{
Cell["Basic LTemplate usage", "Section"],
Cell[TextData[{
"This notebook demonstrates basic LTemplate usage with ",
Cell[BoxData["Integer"]],
", ",
Cell[BoxData["Real"]],
" and ",
Cell[BoxData["Complex"]],
" numerical arguments."
}], "Text"],
Cell[BoxData[{
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}], ";"}]}], "Input"],
Cell["Start by creating a template specification:", "Text"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=", "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{"\"\<Basics\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<add\>\"", ",",
RowBox[{"{",
RowBox[{"Real", ",", "Real"}], "}"}], ",", "Real"}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<mandel\>\"", ",",
RowBox[{"{",
RowBox[{"Complex", " ",
RowBox[{"(*", " ", "c", " ", "*)"}], ",", "Integer"}], " ",
RowBox[{"(*", " ", "max_iter", " ", "*)"}], "}"}], ",", "Integer"}],
"]"}]}], "\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]",
"]"}]}], ";"}]], "Input"],
Cell["\<\
The corresponding C++ code is in Basics.h, in the same directory.\
\>", "Text"],
Cell[BoxData[
RowBox[{"SystemOpen", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}]], "Input"],
Cell["Compile the library:", "Text"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"CompileTemplate", "[", "template", "]"}]], "Input"],
Cell[CellGroupData[{
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Current directory is: \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/\
Examples/Basics\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Current directory is: ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
Basics",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print"],
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Unloading library \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"Basics\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\" ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Unloading library ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["Basics",
RGBColor[0, 0,
Rational[2, 3]]],
Style[" ...",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print"],
Cell[BoxData[
StyleBox["\<\"Generating library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print"],
Cell[BoxData[
StyleBox["\<\"Compiling library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print"]
}, Open ]],
Cell[BoxData["\<\"/Users/szhorvat/Library/Mathematica/SystemFiles/\
LibraryResources/MacOSX-x86-64/Basics.dylib\"\>"], "Output"]
}, Open ]],
Cell["Load the template:", "Text"],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template", "]"}]], "Input"],
Cell["Create a class instance on which to call member functions:", "Text"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "=",
RowBox[{"Make", "[", "Basics", "]"}]}]], "Input"],
Cell[BoxData[
RowBox[{"Basics", "[", "1", "]"}]], "Output"]
}, Open ]],
Cell["Add two real numbers, obtaining a real result:", "Text"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<add\>\"", "[",
RowBox[{"42", ",", "137.2"}], "]"}]}]], "Input"],
Cell[BoxData["179.2`"], "Output"]
}, Open ]],
Cell["Passing in the wrong type of argument results in an error:", "Text"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<add\>\"", "[",
RowBox[{"I", ",", "1"}], "]"}]}]], "Input"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LibraryFunction", "::", "cfsa"}], "MessageName"],
RowBox[{
":", " "}], "\<\"Argument \[NoBreak]\\!\\(\[ImaginaryI]\\)\[NoBreak] at \
position \[NoBreak]\\!\\(2\\)\[NoBreak] should be a \
\[NoBreak]\\!\\(\\\"machine-size real number\\\"\\)\[NoBreak]. \
\\!\\(\\*ButtonBox[\\\"\[RightSkeleton]\\\", ButtonStyle->\\\"Link\\\", \
ButtonFrame->None, ButtonData:>\\\"paclet:ref/LibraryFunction\\\", ButtonNote \
-> \\\"LibraryFunction::cfsa\\\"]\\)\"\>"}]], "Message", "MSG"],
Cell[BoxData[
RowBox[{
InterpretationBox[
RowBox[{
TagBox["LibraryFunction",
"SummaryHead"], "[",
DynamicModuleBox[{Typeset`open$$ = False},
PanelBox[
PaneSelectorBox[{False->GridBox[{
{
PaneBox[
ButtonBox[
DynamicBox[FEPrivate`FrontEndResource[
"FEBitmaps", "SquarePlusIconMedium"],
ImageSizeCache->{12., {0., 12.}}],
Appearance->None,
ButtonFunction:>(Typeset`open$$ = True),
Evaluator->Automatic,
Method->"Preemptive"],
Alignment->{Center, Center},
ImageSize->
Dynamic[{
Automatic, 3.5 CurrentValue["FontCapHeight"]/
AbsoluteCurrentValue[Magnification]}]],
GraphicsBox[
{Thickness[0.038461538461538464`],
{FaceForm[{GrayLevel[0.93], Opacity[1.]}],
FilledCurveBox[{{{1, 4, 3}, {0, 1, 0}, {1, 3, 3}, {0, 1, 0}, {1,
3, 3}, {0, 1, 0}, {1, 3, 3}, {0, 1, 0}}}, {{{
25.499999999999996`, 2.5}, {25.499999999999996`,
1.3953100000000003`}, {24.604699999999998`,
0.49999999999999994`}, {23.5, 0.49999999999999994`}, {2.5,
0.49999999999999994`}, {1.3953100000000003`,
0.49999999999999994`}, {0.49999999999999994`,
1.3953100000000003`}, {0.49999999999999994`, 2.5}, {
0.49999999999999994`, 23.5}, {0.49999999999999994`,
24.604699999999998`}, {1.3953100000000003`,
25.499999999999996`}, {2.5, 25.499999999999996`}, {23.5,
25.499999999999996`}, {24.604699999999998`,
25.499999999999996`}, {25.499999999999996`,
24.604699999999998`}, {25.499999999999996`, 23.5}, {
25.499999999999996`, 2.5}}}]},
{FaceForm[{RGBColor[0.5, 0.5, 0.5], Opacity[1.]}],
FilledCurveBox[{{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0,
1, 0}, {0, 1, 0}, {0, 1, 0}}}, {{{20.5426,
19.116799999999998`}, {16.3832, 21.876199999999997`}, {16.3832,
20.021499999999996`}, {6.930469999999999,
20.021499999999996`}, {6.930469999999999,
18.212100000000003`}, {16.3832, 18.212100000000003`}, {16.3832,
16.357399999999995`}, {20.5426, 19.116799999999998`}}}],
FilledCurveBox[{{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0,
1, 0}, {0, 1, 0}, {0, 1, 0}}}, {{{5.30508, 13.8391}, {9.46445,
11.079700000000003`}, {9.46445, 12.933999999999997`}, {
18.917199999999998`, 12.933999999999997`}, {18.917199999999998`,
14.7438}, {9.46445, 14.7438}, {9.46445, 16.598}, {5.30508,
13.8391}}}],
FilledCurveBox[{{{1, 4, 3}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {0,
1, 0}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {
1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {0, 1, 0}, {1, 3, 3}, {1, 3,
3}, {1, 3, 3}, {1, 3, 3}}}, CompressedData["
1:eJxTTMoPSmVmYGBgBGJjIGYCYq4u+eR3VWoOxhkv5j+Qk3SA8fu/r5rKOVHM
Yd2vmNyjZ9Qcrt9QXbW9S8RBg59767IidQcPMYPGaHFhB+Nn61SfiGo4xBwp
T7o2V9Dh0Iolfg6/NBxEHv/x1Xgi4FB1XNNqkqQWnP+axUTQjFkbzn+oO2HB
j/3aDg/Xn5T6WiDoYLs3aJpiqI7DrHN+bO6tQg4zfUR7vF7pQOyfIQyRd9d1
WLL0U1kLoyjEPdm6DpoTXfQX7xBzKPjQejLkhDacL5J4+LL2Gm2HtNnSl4Vf
iELM69J2qPZM3tLnJerQX1oozZugDfHPUxGI/4W1HQ5p3TthoyDi4D7lG1v8
Mi2HgqL9zoEHhB1inOxe3BRG8MH62zXhfIbN1Z82CGhC/GMg4nCm3mN/7TYN
iHlCUPdGakDc/1kUEr46GhD/eYnD+d9iBf/kC0vC+TuCrSL+X5Vy2HGR4R5T
uAbEfxYykPBYp+HQqsCuesZAFhL+rJoQ/2rIQdxTpwkJ7yVycPfD+GDzVqLx
xbUd5HYt2JfqBdWfpA2Jj9mykPDpgYaXtaxDy7yzq86vg8qvlIHE5ylY/Eo7
XAt7o787TxfOB5ufqesQ9PbyxxkPZSDhZ6nrMAGU3u7LQtLLEx2HN2253UbX
ofZ76jis/Pay4oynAsT8QG0HKZMv/gW7FCDyTFpwPsz/MD44/Mw1HFjb1uR9
TVVwWKy880/7FHWIexrkIfLX1RzOMDZZVjHIOaDkh3vSDuj5AwCF11Vc
"]]}},
AspectRatio->1,
Axes->False,
Background->GrayLevel[0.93],
Frame->True,
FrameStyle->Directive[
Thickness[Tiny],
GrayLevel[0.7]],
FrameTicks->None,
ImageSize->{Automatic,
Dynamic[
3.5 (CurrentValue["FontCapHeight"]/AbsoluteCurrentValue[
Magnification]), ImageSizeCache -> {45., {0., 9.}}]}], GridBox[{
{
RowBox[{
TagBox["\<\"Function name: \"\>",
"SummaryItemAnnotation"], "\[InvisibleSpace]",
TagBox["\<\"Basics_add\"\>",
"SummaryItem"]}]},
{
RowBox[{
TagBox["\<\"Argument count: \"\>",
"SummaryItemAnnotation"], "\[InvisibleSpace]",
TagBox["3",
"SummaryItem"]}]}
},
AutoDelete->False,
BaseStyle->{
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False},
GridBoxAlignment->{"Columns" -> {{Left}}, "Rows" -> {{Automatic}}},
GridBoxItemSize->{
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings->{"Columns" -> {{2}}, "Rows" -> {{Automatic}}}]}
},
AutoDelete->False,
BaselinePosition->{1, 1},
GridBoxAlignment->{"Rows" -> {{Top}}},
GridBoxItemSize->{
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}}], True->GridBox[{
{
PaneBox[
ButtonBox[
DynamicBox[FEPrivate`FrontEndResource[
"FEBitmaps", "SquareMinusIconMedium"]],
Appearance->None,
ButtonFunction:>(Typeset`open$$ = False),
Evaluator->Automatic,
Method->"Preemptive"],
Alignment->{Center, Center},
ImageSize->
Dynamic[{
Automatic, 3.5 CurrentValue["FontCapHeight"]/
AbsoluteCurrentValue[Magnification]}]],
GraphicsBox[
{Thickness[0.038461538461538464`],
{FaceForm[{GrayLevel[0.93], Opacity[1.]}],
FilledCurveBox[{{{1, 4, 3}, {0, 1, 0}, {1, 3, 3}, {0, 1, 0}, {1,
3, 3}, {0, 1, 0}, {1, 3, 3}, {0, 1, 0}}}, {{{
25.499999999999996`, 2.5}, {25.499999999999996`,
1.3953100000000003`}, {24.604699999999998`,
0.49999999999999994`}, {23.5, 0.49999999999999994`}, {2.5,
0.49999999999999994`}, {1.3953100000000003`,
0.49999999999999994`}, {0.49999999999999994`,
1.3953100000000003`}, {0.49999999999999994`, 2.5}, {
0.49999999999999994`, 23.5}, {0.49999999999999994`,
24.604699999999998`}, {1.3953100000000003`,
25.499999999999996`}, {2.5, 25.499999999999996`}, {23.5,
25.499999999999996`}, {24.604699999999998`,
25.499999999999996`}, {25.499999999999996`,
24.604699999999998`}, {25.499999999999996`, 23.5}, {
25.499999999999996`, 2.5}}}]},
{FaceForm[{RGBColor[0.5, 0.5, 0.5], Opacity[1.]}],
FilledCurveBox[{{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0,
1, 0}, {0, 1, 0}, {0, 1, 0}}}, {{{20.5426,
19.116799999999998`}, {16.3832, 21.876199999999997`}, {16.3832,
20.021499999999996`}, {6.930469999999999,
20.021499999999996`}, {6.930469999999999,
18.212100000000003`}, {16.3832, 18.212100000000003`}, {16.3832,
16.357399999999995`}, {20.5426, 19.116799999999998`}}}],
FilledCurveBox[{{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0,
1, 0}, {0, 1, 0}, {0, 1, 0}}}, {{{5.30508, 13.8391}, {9.46445,
11.079700000000003`}, {9.46445, 12.933999999999997`}, {
18.917199999999998`, 12.933999999999997`}, {18.917199999999998`,
14.7438}, {9.46445, 14.7438}, {9.46445, 16.598}, {5.30508,
13.8391}}}],
FilledCurveBox[{{{1, 4, 3}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {0,
1, 0}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {
1, 3, 3}, {1, 3, 3}, {1, 3, 3}, {0, 1, 0}, {1, 3, 3}, {1, 3,
3}, {1, 3, 3}, {1, 3, 3}}}, CompressedData["
1:eJxTTMoPSmVmYGBgBGJjIGYCYq4u+eR3VWoOxhkv5j+Qk3SA8fu/r5rKOVHM
Yd2vmNyjZ9Qcrt9QXbW9S8RBg59767IidQcPMYPGaHFhB+Nn61SfiGo4xBwp
T7o2V9Dh0Iolfg6/NBxEHv/x1Xgi4FB1XNNqkqQWnP+axUTQjFkbzn+oO2HB
j/3aDg/Xn5T6WiDoYLs3aJpiqI7DrHN+bO6tQg4zfUR7vF7pQOyfIQyRd9d1
WLL0U1kLoyjEPdm6DpoTXfQX7xBzKPjQejLkhDacL5J4+LL2Gm2HtNnSl4Vf
iELM69J2qPZM3tLnJerQX1oozZugDfHPUxGI/4W1HQ5p3TthoyDi4D7lG1v8
Mi2HgqL9zoEHhB1inOxe3BRG8MH62zXhfIbN1Z82CGhC/GMg4nCm3mN/7TYN
iHlCUPdGakDc/1kUEr46GhD/eYnD+d9iBf/kC0vC+TuCrSL+X5Vy2HGR4R5T
uAbEfxYykPBYp+HQqsCuesZAFhL+rJoQ/2rIQdxTpwkJ7yVycPfD+GDzVqLx
xbUd5HYt2JfqBdWfpA2Jj9mykPDpgYaXtaxDy7yzq86vg8qvlIHE5ylY/Eo7
XAt7o787TxfOB5ufqesQ9PbyxxkPZSDhZ6nrMAGU3u7LQtLLEx2HN2253UbX
ofZ76jis/Pay4oynAsT8QG0HKZMv/gW7FCDyTFpwPsz/MD44/Mw1HFjb1uR9
TVVwWKy880/7FHWIexrkIfLX1RzOMDZZVjHIOaDkh3vSDuj5AwCF11Vc
"]]}},
AspectRatio->1,
Axes->False,
Background->GrayLevel[0.93],
Frame->True,
FrameStyle->Directive[
Thickness[Tiny],
GrayLevel[0.7]],
FrameTicks->None,
ImageSize->{Automatic,
Dynamic[
3.5 (CurrentValue["FontCapHeight"]/AbsoluteCurrentValue[
Magnification]), ImageSizeCache -> {45., {0., 9.}}]}], GridBox[{
{
RowBox[{
TagBox["\<\"Function name: \"\>",
"SummaryItemAnnotation"], "\[InvisibleSpace]",
TagBox["\<\"Basics_add\"\>",
"SummaryItem"]}]},
{
RowBox[{
TagBox["\<\"Argument count: \"\>",
"SummaryItemAnnotation"], "\[InvisibleSpace]",
TagBox["3",
"SummaryItem"]}]},
{
RowBox[{
TagBox["\<\"Argument types: \"\>",
"SummaryItemAnnotation"], "\[InvisibleSpace]",
TagBox[
PaneBox[
RowBox[{"{",
RowBox[{"Integer", ",", "Real", ",", "Real"}], "}"}],
BaselinePosition->Baseline,
ContentPadding->False,
FrameMargins->0,
ImageSize->{{1, 500}, Automatic},
StripOnInput->True],
"SummaryItem"]}]},
{
RowBox[{
TagBox["\<\"Return type: \"\>",
"SummaryItemAnnotation"], "\[InvisibleSpace]",
TagBox[
PaneBox["Real",
BaselinePosition->Baseline,
ContentPadding->False,
FrameMargins->0,
ImageSize->{{1, 500}, Automatic},
StripOnInput->True],
"SummaryItem"]}]},
{
RowBox[{
TagBox["\<\"Library: \"\>",
"SummaryItemAnnotation"], "\[InvisibleSpace]",
TagBox["\<\"Basics.dylib\"\>",
"SummaryItem"]}]}
},
AutoDelete->False,
BaseStyle->{
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False},
GridBoxAlignment->{"Columns" -> {{Left}}, "Rows" -> {{Automatic}}},
GridBoxItemSize->{
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings->{"Columns" -> {{2}}, "Rows" -> {{Automatic}}}]}
},
AutoDelete->False,
BaselinePosition->{1, 1},
GridBoxAlignment->{"Rows" -> {{Top}}},
GridBoxItemSize->{
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}}]}, Dynamic[
Typeset`open$$],
ImageSize->Automatic],
BaselinePosition->Baseline],
DynamicModuleValues:>{}], "]"}],
LibraryFunction[
"/Users/szhorvat/Library/Mathematica/SystemFiles/LibraryResources/MacOSX-\
x86-64/Basics.dylib", "Basics_add", {Integer, Real, Real}, Real],
Editable->False,
SelectWithContents->True,
Selectable->False], "[",
RowBox[{"1", ",", "\[ImaginaryI]", ",", "1"}], "]"}]], "Output"]
}, Open ]],
Cell[TextData[{
Cell[BoxData["mandel"]],
" is a helper function for implementing the escape time algorithm for \
visualizing the Mandelbrot set. It counts how many iterations of ",
Cell[BoxData[
RowBox[{"z", "\[Function]",
RowBox[{
SuperscriptBox["z", "2"], "+", "c"}]}]]],
" are necessary before ",
Cell[BoxData[
RowBox[{
RowBox[{"Abs", "[", "z", "]"}], ">", "2"}]]],
". The first argument is ",
Cell[BoxData["c"]],
", the second the maximum number of iterations."
}], "Text"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{"Table", "[", "\[IndentingNewLine]",
RowBox[{
RowBox[{"obj", "@",
RowBox[{"\"\<mandel\>\"", "[",
RowBox[{
RowBox[{"a", "+",
RowBox[{"I", " ", "b"}]}], ",", "50"}], "]"}]}], ",",
"\[IndentingNewLine]",
RowBox[{"{",
RowBox[{"a", ",",
RowBox[{"-", "2"}], ",", "1", ",", "0.01"}], "}"}], ",",
RowBox[{"{",
RowBox[{"b", ",",
RowBox[{"-", "1"}], ",", "1", ",", "0.01"}], "}"}]}],
"\[IndentingNewLine]", "]"}], "//", "ArrayPlot"}]], "Input"],
Cell[BoxData[
GraphicsBox[RasterBox[CompressedData["
1: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
"], {{0, 0}, {201, 301}}, {0, 50}],
Frame->Automatic,
FrameLabel->{None, None},
FrameTicks->{{None, None}, {None, None}},
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]],
Method->{
"AxisPadding" -> Scaled[0.02], "DefaultBoundaryStyle" -> Automatic,
"DefaultPlotStyle" -> Automatic, "DomainPadding" -> Scaled[0.02],
"RangePadding" -> Scaled[0.05]}]], "Output"]
}, Open ]]
}, Open ]]
},
WindowSize->{808, 751},
WindowMargins->{{92, Automatic}, {-4, Automatic}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
CommonDefaultFormatTypes->{"TextInline"->StandardForm},
TrackCellChangeTimes->False,
FrontEndVersion->"10.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 4, \
2014)",
StyleDefinitions->"Default.nb"
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,155 @@
#include <LTemplate.h>
#include <complex>
#include <algorithm>
struct Img {
/* Invert an Image like ColorNegate
*
* Demonstrated features:
*
* - Iterating through all channels except the alpha channel (nonAlphaChannels)
* - Iterating through all pixels of a single channel linearly (pixelBegin)
*
*/
mma::GenericImageRef invert(mma::ImageRef<double> im) {
// loop through all channels except the alpha channel
for (int ch=0; ch < im.nonAlphaChannels(); ++ch)
// loop through the pixels of the given channel
// instead of auto it, we could use ImageRef<double>::pixel_iterator it
for (auto it = im.pixelBegin(ch); it != im.pixelEnd(ch); ++it)
*it = 1 - *it; // invert pixel value
return im;
}
/* Blur an image up to radius 1 by averaging it with its four direct neighbours.
* For simplicity, this implementation does not handle boundary pixels.
*
* Demonstrated features:
*
* - Iterating through all channels except the alpha channel (if one exists)
* - Indexing into an image by pixel position
*
*/
mma::GenericImageRef blur1(mma::ImageRef<double> im) {
// loop through all channels except the alpha channel
for (int ch=0; ch < im.nonAlphaChannels(); ++ch)
// loop through all non-boundary pixels using 2D indexing
for (int i=1; i < im.rows()-1; ++i)
for (int j=1; j < im.cols()-1; ++j)
// average each pixel with its four neighbours
im(i,j,ch) = (im(i-1, j, ch) + im(i+1, j, ch) + im(i, j-1, ch) + im(i, j+1, ch) + im(i, j, ch)) / 5.0;
return im;
}
/* Retrieve image dimensions.
*
* Demonstrated features:
*
* - GenericImageRef can refer an image with any pixel type, but it cannot index into them.
* Using it allows us to prevent copying the image.
*
*/
mma::IntTensorRef imageDimensions(mma::GenericImageRef im) {
return mma::makeVector<mint>({im.cols(), im.rows()});
}
/* Creates a gradient image.
*
* Demonstrated features:
*
* - Creating new images
* - Indexing into an image by pixel position
*
*/
mma::GenericImageRef gradient(mint cols, mint rows) {
auto im = mma::makeImage<mma::im_byte_t>(cols, rows);
for (int i=0; i < rows; ++i)
for (int j=0; j < cols; ++j)
im(i,j) = 255.0*j/cols;
return im;
}
/* Creates a Mandelbrot set image.
*
* Demonstrated features:
*
* - Creating new images
* - Indexing into an image by pixel position
*
*/
mma::GenericImageRef mandelbrot(mma::complex_t lower, mma::complex_t upper, mint width, mint iter) {
if (! (upper.real() > lower.real() && upper.imag() > lower.imag()) )
throw mma::LibraryError("Real and imaginary parts of 'upper' must be greater than that of 'lower'.");
if (iter > 255) {
iter = 255;
mma::message("The maximum number of iterations is 255. No more than this will be tried.");
}
double rat = (upper.real() - lower.real()) / width;
mint height = (upper.imag() - lower.imag()) / rat;
auto im = mma::makeImage<mma::im_byte_t>(width, height);
for (int i=0; i < height; ++i)
for (int j=0; j < width; ++j) {
mma::complex_t z = 0, c = lower + mma::complex_t(j,i)*rat;
int k=0;
while (std::abs(z) < 2 && k < iter) {
z = z*z+c;
k++;
}
im(height - i - 1, j) = k == iter ? 0 : k+1;
}
return im;
}
/* Adjusts each channel of an image so that the values span the whole available range (defined through top()).
*
* Demonstrated features:
*
* - Dispatching to the correct function based on the type of the image
* - Casting GenericImageRef to a type-specialized ImageRef
* - Finding the clipping values of different images types using mma::imageMax()
* - Iterating through each pixel and each non-alpha channel
*
*/
mma::GenericImageRef adjust(mma::GenericImageRef im) {
// Dispatch to the correct function based on the type of the image
switch (im.type()) {
case MImage_Type_Bit:
break;
case MImage_Type_Bit8:
iadjust(mma::ImageRef<mma::im_byte_t>(im));
break;
case MImage_Type_Bit16:
iadjust(mma::ImageRef<mma::im_bit16_t>(im));
break;
case MImage_Type_Real32:
iadjust(mma::ImageRef<mma::im_real32_t>(im));
break;
case MImage_Type_Real:
iadjust(mma::ImageRef<mma::im_real_t>(im));
break;
case MImage_Type_Undef:
throw mma::LibraryError("Invalid image.");
}
return im;
}
private:
// Specialized version of adjust() for each image type
template<typename T> void iadjust(mma::ImageRef<T> im) {
for (int ch=0; ch < im.nonAlphaChannels(); ++ch) {
auto minmax = std::minmax_element(im.pixelBegin(ch), im.pixelEnd(ch));
T lo = *minmax.first, hi = *minmax.second;
T diff = hi - lo;
if (diff == 0)
diff = 1;
for (auto it = im.pixelBegin(ch); it != im.pixelEnd(ch); ++it)
*it = mma::imageMax<T>() * double(*it - lo) / diff;
}
}
};

View File

@ -0,0 +1,133 @@
#include <LTemplate.h>
#include <random>
#include <cmath>
// Auxiliary class for holding the spin state.
template<typename T>
class Matrix {
int nrows, ncols;
T *data;
public:
Matrix(int r, int c) : nrows(r), ncols(c) {
data = new T[nrows*ncols];
}
~Matrix() { delete [] data; }
T & operator () (int i, int j) { return data[i*ncols + j]; }
const T & operator () (int i, int j) const { return data[i*ncols + j]; }
T & operator [] (int i) { return data[i]; }
const T & operator [] (int i) const { return data[i]; }
int rows() const { return nrows; }
int cols() const { return ncols; }
int size() const { return nrows*ncols; }
T *begin() { return data; }
T *end() { return data + size(); }
};
typedef Matrix<bool> StateMatrix;
// Convert bool value to -1 or +1.
inline int spin(bool b) { return 2*b-1; }
// LTemplate class for the Ising model simulation.
class Ising {
std::mt19937 engine;
/* LTemplate does not currently support constructor arguments, thus Ising
* objects must be created with an "empty" state. We indicate this using nullptr,
* which is safe to delete in the destructor.
*
* There is a separate function, setState(), for assigning an actual state.
*/
StateMatrix *state;
public:
Ising() : engine{ std::random_device()() }, state(nullptr) { }
~Ising() { delete state; }
// Seed the random number generator.
void seed(mint s) { engine.seed(s); }
// Set the Ising state.
void setState(mma::IntMatrixRef mat) {
if (mat.rows() < 2 || mat.cols() < 2)
throw mma::LibraryError("State matrix must be at least of size 2 by 2.");
delete state;
state = new StateMatrix(mat.rows(), mat.cols());
std::copy(mat.begin(), mat.end(), state->begin());
}
// Retrieve the Ising state.
mma::IntMatrixRef getState() const {
if (! state)
throw mma::LibraryError("State not set.");
return mma::makeMatrix<mint>(state->rows(), state->cols(), state->begin());
}
// Compute the magnetization value.
mint magnetization() const {
if (! state)
throw mma::LibraryError("State not set.");
int total = 0;
for (const auto &el : *state)
total += el;
return 2*total - state->size();
}
// Compute the energy value.
mint energy() const {
if (! state)
throw mma::LibraryError("State not set.");
int E = 0;
for (int i=1; i < state->rows(); ++i)
for (int j=0; j < state->cols(); ++j)
E += spin((*state)(i,j)) * spin((*state)(i-1,j));
for (int i=0; i < state->rows(); ++i)
for (int j=1; j < state->cols(); ++j)
E += spin((*state)(i,j)) * spin((*state)(i,j-1));
return -E;
}
// Simulate the Ising system for the given number of steps and the given temperature.
void simulate(mint steps, double temp) {
if (! state)
throw mma::LibraryError("State not set.");
if (temp <= 0)
throw mma::LibraryError("Temperature must be strictly positive.");
std::uniform_int_distribution<> randrow(0, state->rows()-1);
std::uniform_int_distribution<> randcol(0, state->cols()-1);
std::uniform_real_distribution<> rrand;
for (mint i=0; i < steps; ++i) {
// Allow for aborting the simulation every 1000 steps.
if (i % 1000 == 0)
mma::check_abort();
int ri = randrow(engine);
int rj = randcol(engine);
int s = 0;
if (ri > 0) s += spin((*state)(ri-1, rj));
if (ri < state->rows()-1) s += spin((*state)(ri+1, rj));
if (rj > 0) s += spin((*state)(ri, rj-1));
if (rj < state->cols()-1) s += spin((*state)(ri, rj+1));
int x = spin((*state)(ri,rj));
int deltaE = 2*s*x;
if (rrand(engine) < std::exp( -deltaE/temp )) {
(*state)(ri,rj) = ! (*state)(ri,rj); // do flip
}
}
}
};

View File

@ -0,0 +1,198 @@
Notebook[{
Cell[CellGroupData[{
Cell["Two-dimensional Ising model", "Section",
ExpressionUUID -> "10c6cfd6-9e82-43f5-a390-f895753bc07f"],
Cell[TextData[{
"This example shows how to simulate a two-dimensional ",
ButtonBox["Ising model",
BaseStyle->"Hyperlink",
ButtonData->{
URL["https://en.wikipedia.org/wiki/Ising_model"], None},
ButtonNote->"https://en.wikipedia.org/wiki/Ising_model"],
" in C++ and visualize it in real time in Mathematica."
}], "Text",
ExpressionUUID -> "76cdc71d-e64b-4770-8661-fd72ae6b7780"],
Cell[BoxData[{
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}], ";"}]}], "Input",
ExpressionUUID -> "742d9654-8e42-415c-8976-dcce157c587c"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=", "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{"\"\<Ising\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<seed\>\"", ",",
RowBox[{"{", "Integer", "}"}], ",", "\"\<Void\>\""}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<getState\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Integer", ",", "2"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<setState\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Integer", ",", "2", ",", "\"\<Constant\>\""}], "}"}],
"}"}], ",", "\"\<Void\>\""}], "]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<energy\>\"", ",",
RowBox[{"{", "}"}], ",", "Integer"}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<magnetization\>\"", ",",
RowBox[{"{", "}"}], ",", "Integer"}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<simulate\>\"", ",",
RowBox[{"{",
RowBox[{"Integer", ",", "Real"}], "}"}], ",", "\"\<Void\>\""}],
"]"}]}], "\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]",
"]"}]}], ";"}]], "Input",
ExpressionUUID -> "74ae851f-272f-4653-9816-f1c3194402de"],
Cell[BoxData[
RowBox[{"CompileTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "ffbc1822-22e9-47c4-be40-57db4f4eb58d"],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "add3ebe9-db11-4e9c-932e-6825b7a1836c"],
Cell[BoxData[
RowBox[{"ising", "=",
RowBox[{"Make", "[", "Ising", "]"}]}]], "Input",
ExpressionUUID -> "238aa2cf-9058-40f5-8230-9c9f71652ca1"],
Cell[TextData[{
"The state must be set before the ",
Cell[BoxData["ising"],
ExpressionUUID -> "1082ab58-96d7-4dc4-a21c-1971dfaa4685"],
" object can be used:"
}], "Text",
ExpressionUUID -> "cf0f3dce-51aa-4efa-87b2-61fc61b49c09"],
Cell[BoxData[{
RowBox[{
RowBox[{"ising", "@",
RowBox[{"\"\<setState\>\"", "[",
RowBox[{"RandomInteger", "[",
RowBox[{"1", ",",
RowBox[{"{",
RowBox[{"40", ",", "40"}], "}"}]}], "]"}], "]"}]}], ";"}], "\n",
RowBox[{
RowBox[{"state", "=",
RowBox[{"ising", "@",
RowBox[{"\"\<getState\>\"", "[", "]"}]}]}], ";"}]}], "Input",
ExpressionUUID -> "732764c4-9e22-41c5-8271-53a1ecaf3c95"],
Cell["\<\
Control sliders for the temperature and simulation speed. Try using them \
while the simulation is running.\
\>", "Text",
ExpressionUUID -> "bb8b1248-3180-4132-bfc9-664523f0b223"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"\"\<temp\>\"", ",",
RowBox[{"Control", "[",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"temp", ",", "2"}], "}"}], ",", "0.01", ",", "20"}], "}"}],
"]"}], ",",
RowBox[{"Dynamic", "[", "temp", "]"}]}], "}"}]], "Input",
ExpressionUUID -> "60f3866b-788c-4462-91dc-70b167cb8f84"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"\"\<speed\>\"", ",",
RowBox[{"Control", "[",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"step", ",", "300"}], "}"}], ",", "1", ",", "10000", ",",
"1"}], "}"}], "]"}], ",",
RowBox[{"Dynamic", "[", "step", "]"}]}], "}"}]], "Input",
ExpressionUUID -> "82de69c3-d667-4447-874f-e58320aa4df3"],
Cell["Set up dynamic visualizations.", "Text",
ExpressionUUID -> "37962e41-50d0-4648-9fa0-5fda053fa3e2"],
Cell[BoxData[
RowBox[{"Dynamic", "@",
RowBox[{"Row", "[",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"ArrayPlot", "[",
RowBox[{"state", ",",
RowBox[{"ImageSize", "\[Rule]", "Medium"}]}], "]"}], ",",
RowBox[{"VerticalGauge", "[",
RowBox[{
RowBox[{"ising", "@",
RowBox[{"\"\<energy\>\"", "[", "]"}]}], ",",
RowBox[{"2", " ",
RowBox[{"40", "^", "2"}],
RowBox[{"{",
RowBox[{
RowBox[{"-", "1"}], ",", "1"}], "}"}]}], ",",
RowBox[{"GaugeLabels", "\[Rule]", "\"\<energy\>\""}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"VerticalGauge", "[",
RowBox[{
RowBox[{"ising", "@",
RowBox[{"\"\<magnetization\>\"", "[", "]"}]}], ",",
RowBox[{
RowBox[{"40", "^", "2"}],
RowBox[{"{",
RowBox[{
RowBox[{"-", "1"}], ",", "1"}], "}"}]}], ",",
RowBox[{"GaugeLabels", "\[Rule]", "\"\<magnetization\>\""}]}], "]"}]}],
"}"}], "]"}]}]], "Input",
ExpressionUUID -> "73fd3f39-b896-4ae1-a4cc-115272b9e9af"],
Cell["Start the simulation.", "Text",
ExpressionUUID -> "8f9ec8ef-ea0b-4024-ba82-1f22cae42506"],
Cell[BoxData[
RowBox[{"While", "[",
RowBox[{"True", ",", "\[IndentingNewLine]",
RowBox[{
RowBox[{"ising", "@",
RowBox[{"\"\<simulate\>\"", "[",
RowBox[{"step", ",", "temp"}], "]"}]}], ";", "\[IndentingNewLine]",
RowBox[{"state", "=",
RowBox[{"ising", "@",
RowBox[{"\"\<getState\>\"", "[", "]"}]}]}], ";", "\[IndentingNewLine]",
RowBox[{"Pause", "[", "0.05", "]"}]}]}], "\[IndentingNewLine]",
"]"}]], "Input",
ExpressionUUID -> "c7758668-cab3-47ee-a816-125c948085c4"],
Cell["\<\
Simply abort the calculation (Evaluation menu, Abort Evaluation) to stop the \
simulation.\
\>", "Text",
ExpressionUUID -> "897d8457-ad83-4800-a4b2-33c18a32e805"]
}, Open ]]
},
WindowSize->{808, 824},
WindowMargins->{{Automatic, 169}, {Automatic, 10}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
CommonDefaultFormatTypes->{"TextInline"->StandardForm},
TrackCellChangeTimes->False,
FrontEndVersion->"10.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 4, \
2014)",
StyleDefinitions->"Default.nb"
]

View File

@ -0,0 +1,704 @@
Notebook[{
Cell[CellGroupData[{
Cell["Managed Library Expressions", "Section",
ExpressionUUID -> "cd2d3f18-e46f-4d9c-adac-d36ea52104dd"],
Cell[TextData[{
"This example demonstrates various operations on ",
ButtonBox["managed library expressions",
BaseStyle->"Link",
ButtonData->
"paclet:paclet:LibraryLink/tutorial/InteractionWithMathematica#353220453"],\
". It shows the implementation of a real-valued vector class, ",
Cell[BoxData[
FormBox["VecExpr", TraditionalForm]],
ExpressionUUID -> "54d425c9-3fb5-4ffc-87c3-e4a57edcb78c"],
"."
}], "Text",
ExpressionUUID -> "63587299-0a81-4c30-a2c3-d05440e19b72"],
Cell["\<\
LTemplate was originally created to simplify working with managed library \
expressions. All LTemplate classes correspond to library expressions with the \
same manager name.\
\>", "Text"],
Cell[BoxData[{
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}], ";"}], "\[IndentingNewLine]",
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}]}], "Input",
ExpressionUUID -> "3c1bcca1-fd1e-487c-a227-5eebf7de8e12"],
Cell["\<\
This library has two classes, each having its own header file.\
\>", "Text",
ExpressionUUID -> "b611e1bd-c606-4faa-b805-87bd28e021a6"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=",
RowBox[{"LTemplate", "[",
RowBox[{"\"\<LibraryExpressions\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{"(*", " ",
RowBox[{
"Functions", " ", "that", " ", "are", " ", "not", " ", "attached", " ",
"to", " ", "any", " ", "VecExpr", " ",
RowBox[{"(",
RowBox[{
RowBox[{"i", ".", "e", ".", " ", "could"}], " ", "also", " ", "be",
" ", "free"}], ")"}], " ", "will", " ", "be", " ", "members", " ",
"of", " ", "this", " ",
RowBox[{"class", ".", " ", "There"}], " ", "will", " ", "be", " ",
"only", " ", "once", " ", "instance", " ", "of", " ", "this", " ",
RowBox[{"class", "."}]}], " ", "*)"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"LClass", "[",
RowBox[{"\"\<Manager\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<releaseVecExpr\>\"", ",",
RowBox[{"{", "Integer", "}"}], ",", "\"\<Void\>\""}], "]"}],
"\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]", "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"(*", " ",
RowBox[{"The", " ", "vector", " ",
RowBox[{"class", "."}]}], " ", "*)"}], "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{"\"\<VecExpr\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<set\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "1"}], "}"}], "}"}], ",",
"\"\<Void\>\""}], "]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<value\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Real", ",", "1"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<inner\>\"", ",",
RowBox[{"{",
RowBox[{"LExpressionID", "[", "\"\<VecExpr\>\"", "]"}], "}"}],
",", "Real"}], "]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<setToSum\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Integer", ",", "1"}], "}"}], "}"}], ",",
"\"\<Void\>\""}], "]"}]}], "\[IndentingNewLine]", "}"}]}],
"\[IndentingNewLine]", "]"}]}], "\[IndentingNewLine]", "}"}]}],
"\[IndentingNewLine]", "]"}]}], ";"}]], "Input",
ExpressionUUID -> "5dd1cf3f-d485-4693-8d58-975a44fa935e"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"CompileTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "0991b970-8180-4faa-af96-aa4996111648"],
Cell[CellGroupData[{
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Current directory is: \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/\
Examples/LibraryExpressions\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Current directory is: ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
LibraryExpressions",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "d9d4032f-0322-40d3-9f57-d95e3b99b3a5"],
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Unloading library \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"LibraryExpressions\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\" ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Unloading library ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["LibraryExpressions",
RGBColor[0, 0,
Rational[2, 3]]],
Style[" ...",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "d9d4032f-0322-40d3-9f57-d95e3b99b3a5"],
Cell[BoxData[
StyleBox["\<\"Generating library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "d9d4032f-0322-40d3-9f57-d95e3b99b3a5"],
Cell[BoxData[
StyleBox["\<\"Compiling library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "d9d4032f-0322-40d3-9f57-d95e3b99b3a5"]
}, Open ]],
Cell[BoxData["\<\"/Users/szhorvat/Library/Mathematica/SystemFiles/\
LibraryResources/MacOSX-x86-64/LibraryExpressions.dylib\"\>"], "Output",
ExpressionUUID -> "ec9a1924-6a42-40af-b5df-ea4965aa360a"]
}, Open ]],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "86a63d4d-0b65-4d65-87ff-14e55df6b2bb"],
Cell["\<\
We start by turning off history tracking, to be able to demonstrate automatic \
freeing of managed library expressions later.\
\>", "Text",
ExpressionUUID -> "603fbe90-66bf-43bf-be7b-9110da8bc154"],
Cell[BoxData[
RowBox[{
RowBox[{"$HistoryLength", "=", "0"}], ";"}]], "Input",
ExpressionUUID -> "117a414b-6cad-44aa-bbf5-f226c089520d"],
Cell[TextData[{
Cell[BoxData[
FormBox[
RowBox[{"toVecExpr", "[", "]"}], TraditionalForm]],
ExpressionUUID -> "7f181341-43b8-4312-b5e2-8fc05fa57338"],
" converts to a ",
StyleBox["Mathematica",
FontSlant->"Italic"],
" list to a ",
Cell[BoxData[
FormBox["VecExpr", TraditionalForm]],
ExpressionUUID -> "b66620f0-ec83-49aa-95f2-855e7c1cd587"],
" vector. We define ",
Cell[BoxData[
FormBox[
RowBox[{"toVecExpr", "[", "]"}], TraditionalForm]],
ExpressionUUID -> "c432be49-3b6a-4455-8461-7c215d3ad655"],
" in such a way that it will not accept any symbolic arguments, and use ",
Cell[BoxData[
FormBox["Block", TraditionalForm]],
ExpressionUUID -> "d2cf1e57-06de-4cb4-926a-d34e2562e95c"],
" for localization. This is slightly faster than ",
Cell[BoxData[
FormBox["Module", TraditionalForm]],
ExpressionUUID -> "e3a3e20f-ac1f-42fd-8d03-412a92876bdd"],
". While this performance difference is not normally noticeable in ",
StyleBox["Mathematica",
FontSlant->"Italic"],
", library functions are so fast that it is measurable in this case."
}], "Text",
ExpressionUUID -> "09264c44-3a23-4454-b579-e768a6a14f46"],
Cell[BoxData[
RowBox[{
RowBox[{"toVecExpr", "[",
RowBox[{"v_", "?",
RowBox[{"(",
RowBox[{
RowBox[{"VectorQ", "[",
RowBox[{"#", ",", "NumericQ"}], "]"}], "&"}], ")"}]}], "]"}], ":=",
"\[IndentingNewLine]",
RowBox[{"Block", "[",
RowBox[{
RowBox[{"{",
RowBox[{"vec", "=",
RowBox[{"Make", "[", "VecExpr", "]"}]}], "}"}], ",",
"\[IndentingNewLine]",
RowBox[{
RowBox[{"vec", "@",
RowBox[{"\"\<set\>\"", "[", "v", "]"}]}], ";", "\[IndentingNewLine]",
"vec"}]}], "\[IndentingNewLine]", "]"}]}]], "Input",
ExpressionUUID -> "7f5298e4-7c8f-4c34-acc3-ecaacdec40dc"],
Cell["Let us create two vectors:", "Text",
ExpressionUUID -> "c0748e4f-e445-435a-9d80-a008a9e867b1"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v1", "=",
RowBox[{"toVecExpr", "[",
RowBox[{"{",
RowBox[{"1.6", ",", "2", ",", "3", ",", "4"}], "}"}], "]"}]}]], "Input",
ExpressionUUID -> "3305886a-0a00-4b43-adf5-f3d3fc544331"],
Cell[BoxData[
RowBox[{"VecExpr", "[", "1", "]"}]], "Output",
ExpressionUUID -> "e306bbdf-65d1-4a4a-8a55-020b9625051d"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v2", "=",
RowBox[{"toVecExpr", "[",
RowBox[{"{",
RowBox[{"4", ",", "3", ",", "2", ",", "1"}], "}"}], "]"}]}]], "Input",
ExpressionUUID -> "aea78f2a-ffdb-4519-9afb-a9cf8794a14c"],
Cell[BoxData[
RowBox[{"VecExpr", "[", "2", "]"}]], "Output",
ExpressionUUID -> "023dda62-c25a-461d-9815-b7915b4f68a9"]
}, Open ]],
Cell["Retrieve their value:", "Text",
ExpressionUUID -> "83f0efc4-afba-4130-93b8-ab20869e3cdb"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v1", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "336a42a3-538d-4694-a496-73874b0e9eed"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"1.6`", ",", "2.`", ",", "3.`", ",", "4.`"}], "}"}]], "Output",
ExpressionUUID -> "f9a27d1e-e6e5-4737-b63c-124ae123eee0"]
}, Open ]],
Cell[TextData[{
"Compute their inner product. Notice that we must pass the managed library \
expression ID (i.e. an integer) of a VecExpr. While LTemplate could in \
principle detect when ",
ButtonBox["ManagedLibraryExpressionID",
BaseStyle->"Link",
ButtonData->"paclet:ref/ManagedLibraryExpressionID"],
" needs to be applied, this is left to the user so that better performance \
can be achieved."
}], "Text",
ExpressionUUID -> "8b4aa657-1a23-417a-9231-9bffbc50de16"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v1", "@",
RowBox[{"\"\<inner\>\"", "[",
RowBox[{"ManagedLibraryExpressionID", "[", "v2", "]"}], "]"}]}]], "Input",
ExpressionUUID -> "22cca200-8d33-4b30-a1c9-5cb06dd6bef4"],
Cell[BoxData["22.4`"], "Output",
ExpressionUUID -> "ad417a0b-38c6-476c-bdd1-5b96bc6e7926"]
}, Open ]],
Cell["Verify the result:", "Text",
ExpressionUUID -> "56fcadd6-a1a0-4e58-9cfe-282ba5d072e2"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{"v1", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}], ".",
RowBox[{"v2", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}]}]], "Input",
ExpressionUUID -> "4a458cca-6c38-47ca-a63b-986694f0a950"],
Cell[BoxData["22.4`"], "Output",
ExpressionUUID -> "938f5fab-15f5-4195-8281-1b90b5fa2071"]
}, Open ]],
Cell[TextData[{
"The following function creates a new ",
Cell[BoxData[
FormBox["VecExpr", TraditionalForm]],
ExpressionUUID -> "4cfc5c43-dd6c-4bba-8f0f-ead68ebccca6"],
" from the sum of multiple other vectors:"
}], "Text",
ExpressionUUID -> "37e823c2-302b-4dac-a693-5310f70edd0f"],
Cell[BoxData[
RowBox[{
RowBox[{"vecSum", "[", "vecs__VecExpr", "]"}], ":=", "\[IndentingNewLine]",
RowBox[{"Block", "[",
RowBox[{
RowBox[{"{",
RowBox[{"vec", "=",
RowBox[{"Make", "[", "VecExpr", "]"}]}], "}"}], ",",
"\[IndentingNewLine]",
RowBox[{
RowBox[{"vec", "@",
RowBox[{"\"\<setToSum\>\"", "[",
RowBox[{"ManagedLibraryExpressionID", "/@",
RowBox[{"{", "vecs", "}"}]}], "]"}]}], ";", "\[IndentingNewLine]",
"vec"}]}], "\[IndentingNewLine]", "]"}]}]], "Input",
ExpressionUUID -> "5b07c542-8f3a-450a-9156-ff190821a399"],
Cell["Let\[CloseCurlyQuote]s try it:", "Text",
ExpressionUUID -> "0a2cd7a7-82a9-4352-9e06-d3f2ab108119"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v3", "=",
RowBox[{"vecSum", "[",
RowBox[{"v1", ",", "v2"}], "]"}]}]], "Input",
ExpressionUUID -> "a431b93b-fafd-468f-89fd-cbb590eda6c8"],
Cell[BoxData[
RowBox[{"VecExpr", "[", "3", "]"}]], "Output",
ExpressionUUID -> "4e38e6ef-a73e-4f5c-b007-963974729189"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v3", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "2bc5057f-aadc-4c0f-aee0-057f922410ae"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"5.6`", ",", "5.`", ",", "5.`", ",", "5.`"}], "}"}]], "Output",
ExpressionUUID -> "3e36e89b-5ed2-47a1-82c5-7a544e8fc7f2"]
}, Open ]],
Cell["At this point, we have three managed library expressions", "Text",
ExpressionUUID -> "ae1326ce-2cbf-4e37-8780-c9340fc6fa10"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"LExpressionList", "[", "VecExpr", "]"}]], "Input",
ExpressionUUID -> "b26ae979-7b2f-4398-870f-bc6de7d63a4c"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"VecExpr", "[", "1", "]"}], ",",
RowBox[{"VecExpr", "[", "2", "]"}], ",",
RowBox[{"VecExpr", "[", "3", "]"}]}], "}"}]], "Output",
ExpressionUUID -> "67ec54a6-67c2-4213-b7a5-358ac73d97b5"]
}, Open ]],
Cell["Let us now sum three vectors:", "Text",
ExpressionUUID -> "2f4da39c-222c-4f38-bd63-1fb09cd9782d"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v3", "=",
RowBox[{"vecSum", "[",
RowBox[{"v1", ",", "v2", ",", "v1"}], "]"}]}]], "Input",
ExpressionUUID -> "ca0daf5a-201b-4edd-a667-dd4d1de7efe5"],
Cell[BoxData[
RowBox[{"VecExpr", "[", "4", "]"}]], "Output",
ExpressionUUID -> "582d2dec-c63f-44de-9e6b-a54104bc1f48"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v3", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "2d90fd89-59c8-4b99-94e3-d21a769593fe"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"7.199999999999999`", ",", "7.`", ",", "8.`", ",", "9.`"}],
"}"}]], "Output",
ExpressionUUID -> "bebf8d06-f688-4185-b32a-d834e1cd51bd"]
}, Open ]],
Cell[TextData[{
"When we gave the symbol ",
Cell[BoxData[
FormBox["v3", TraditionalForm]]],
" a new value, its old value (a ",
Cell[BoxData[
FormBox["VecExpr", TraditionalForm]]],
") no longer had any references to it. Thus ",
StyleBox["Mathematica",
FontSlant->"Italic"],
" has automatically released the corresponding managed library expression. \
Notice that ",
Cell[BoxData[
FormBox[
RowBox[{"VecExpr", "[", "3", "]"}], TraditionalForm]],
ExpressionUUID -> "ceca620d-5ac9-4ca9-a9bc-a9a3d5d22da7"],
" no longer exists."
}], "Text",
ExpressionUUID -> "80718511-b739-4bdb-9356-f2e06507efcb"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"LExpressionList", "[", "VecExpr", "]"}]], "Input",
ExpressionUUID -> "ecc5986c-7ad5-4149-bd6d-4336b1616946"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"VecExpr", "[", "1", "]"}], ",",
RowBox[{"VecExpr", "[", "2", "]"}], ",",
RowBox[{"VecExpr", "[", "4", "]"}]}], "}"}]], "Output",
ExpressionUUID -> "f92b408f-6f24-469d-a10c-f2c66e363fdc"]
}, Open ]],
Cell[TextData[{
"However, if ",
ButtonBox["$HistoryLength",
BaseStyle->"Link",
ButtonData->"paclet:ref/$HistoryLength"],
" had not been set to 0, Out would have been keeping a reference to ",
Cell[BoxData[
FormBox[
RowBox[{"VecExpr", "[", "3", "]"}], TraditionalForm]],
ExpressionUUID -> "8c83c4ed-4a84-4699-bb05-3e80f48bbdf3"],
", preventing its release."
}], "Text",
ExpressionUUID -> "38285429-55e5-4415-bb9a-5999782a86ec"],
Cell[TextData[{
"Since library expressions are automatically managed by ",
StyleBox["Mathematica",
FontSlant->"Italic"],
", there is normally no need to release them manually. Thus LTemplate (or ",
StyleBox["Mathematica",
FontSlant->"Italic"],
" itself) does not currently provide a function to do this. Should you want \
to do this anyway for some reason, you can use the LibraryLink C API function \
",
ButtonBox["releaseManagedLibraryExpression",
BaseStyle->"Link",
ButtonData->
"paclet:LibraryLink/ref/callback/releaseManagedLibraryExpression"],
", and expose it to ",
StyleBox["Mathematica",
FontSlant->"Italic"],
". This is how e.g. the ",
ButtonBox["TriangleDelete",
BaseStyle->"Link",
ButtonData->"paclet:TriangleLink/ref/TriangleDelete"],
" function of ",
ButtonBox["TriangleLink",
BaseStyle->"Link",
ButtonData->"paclet:TriangleLink/guide/TriangleLink"],
" works. An example is shown below."
}], "Text",
ExpressionUUID -> "67beb8c0-7739-42a0-ae14-5d9690809294"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ManagedLibraryExpressionQ", "[", "v3", "]"}]], "Input",
ExpressionUUID -> "489039f5-2f2d-418c-9776-8b3adc53afd5"],
Cell[BoxData["True"], "Output",
ExpressionUUID -> "f7039d15-cdb0-4d95-9622-147c5f3c38a3"]
}, Open ]],
Cell[BoxData[
RowBox[{
RowBox[{"manager", "=",
RowBox[{"Make", "[", "Manager", "]"}]}], ";"}]], "Input",
ExpressionUUID -> "6e71477f-6c3b-4768-bc8e-ee292fc77262"],
Cell[BoxData[
RowBox[{"manager", "@",
RowBox[{"\"\<releaseVecExpr\>\"", "[",
RowBox[{"ManagedLibraryExpressionID", "[", "v3", "]"}], "]"}]}]], "Input",
ExpressionUUID -> "22bfe2c8-8279-4e30-8d3b-2f8152cecda3"],
Cell["\<\
The problem with allowing explicit deletions is that it makes it easy to \
create expressions which look like they are pointing to a library expression, \
but in fact they aren\[CloseCurlyQuote]t (as the library expression was \
already released).\
\>", "Text",
ExpressionUUID -> "7bba95eb-45d5-432b-8599-c96392d83558"],
Cell[CellGroupData[{
Cell[BoxData["v3"], "Input",
ExpressionUUID -> "3da604e0-ba9f-47b4-b203-36895cc93536"],
Cell[BoxData[
RowBox[{"VecExpr", "[", "4", "]"}]], "Output",
ExpressionUUID -> "fb71ea5a-a9d5-4449-8f4e-233ea6c12c03"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"v3", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "89a9dd05-4d44-405b-b1ac-acaee0720f68"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LibraryFunction", "::", "noinst"}], "MessageName"], ":",
" ", "\<\"Managed library expression instance does not exist. \
\\!\\(\\*ButtonBox[\\\"\[RightSkeleton]\\\", ButtonStyle->\\\"Link\\\", \
ButtonFrame->None, ButtonData:>\\\"paclet:ref/LibraryFunction\\\", ButtonNote \
-> \\\"LibraryFunction::noinst\\\"]\\)\"\>"}]], "Message", "MSG",
ExpressionUUID -> "60e15e21-1284-4ec8-a7d0-024e642d2f55"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "6abe0f62-8086-427e-961b-8a1290bb3790"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ManagedLibraryExpressionQ", "[", "v3", "]"}]], "Input",
ExpressionUUID -> "a8d02726-8b03-4c2e-a76b-3384c0da588a"],
Cell[BoxData["False"], "Output",
ExpressionUUID -> "b38befe8-49ab-424f-9870-1781db4ec5ce"]
}, Open ]],
Cell["Now there are only two VecExpr left:", "Text",
ExpressionUUID -> "eae3d927-cae9-4c84-8ba3-fdea45f77701"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"LExpressionList", "[", "VecExpr", "]"}]], "Input",
ExpressionUUID -> "799d2977-f1f8-44b8-9d6f-41984193daa7"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"VecExpr", "[", "1", "]"}], ",",
RowBox[{"VecExpr", "[", "2", "]"}]}], "}"}]], "Output",
ExpressionUUID -> "80c4584b-6ba6-4031-9c3a-423379551aca"]
}, Open ]],
Cell["Let us release those too:", "Text",
ExpressionUUID -> "7a1bb01e-1cb6-4845-bf28-8f93e2f1b7a6"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{
RowBox[{"manager", "@",
RowBox[{"\"\<releaseVecExpr\>\"", "[", "#", "]"}]}], "&"}], "/@",
RowBox[{"ManagedLibraryExpressionID", "/@",
RowBox[{"LExpressionList", "[", "VecExpr", "]"}]}]}]], "Input",
ExpressionUUID -> "2c77a682-236c-40fe-9ddf-c4968958628c"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"Null", ",", "Null"}], "}"}]], "Output",
ExpressionUUID -> "e2adcb84-213d-4cac-9e68-b30e25dd99d3"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"LExpressionList", "[", "VecExpr", "]"}]], "Input",
ExpressionUUID -> "9edfb5c5-1e4c-4e40-b263-6ebab0206733"],
Cell[BoxData[
RowBox[{"{", "}"}]], "Output",
ExpressionUUID -> "cfcac460-d9f2-4c84-a1bf-00a65dac3867"]
}, Open ]]
}, Open ]]
},
WindowSize->{808, 751},
WindowMargins->{{12, Automatic}, {Automatic, 24}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
TrackCellChangeTimes->False,
FrontEndVersion->"10.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 4, \
2014)",
StyleDefinitions->"Default.nb"
]

View File

@ -0,0 +1,13 @@
#include <LTemplate.h>
// Dummy class for "free" functions
struct Manager {
// Release a VecExpr
void releaseVecExpr(mint id) {
int err = mma::libData->releaseManagedLibraryExpression("VecExpr", id);
if (err)
throw mma::LibraryError("Managed library expression does not exist.");
}
};

View File

@ -0,0 +1,56 @@
#include <LTemplate.h>
#include <vector>
#include <numeric>
#include <algorithm>
// A class for arbitrary length real vectors
class VecExpr {
std::vector<double> vec;
public:
// Set the value of the vector
void set(mma::RealTensorRef values) {
vec.assign(values.begin(), values.end());
}
// Retrieve the value of the vector
mma::RealTensorRef value() const {
return mma::makeVector<double>(vec.size(), vec.data());
}
// Inner product with another vector
// The integer library expression ID passed to the function is
// automatically translated to an object reference (VecExpr &)
double inner(const VecExpr &v) const {
if (vec.size() != v.vec.size())
throw mma::LibraryError("VecExprs are of inconsistent sizes.");
return std::inner_product(vec.begin(), vec.end(), v.vec.begin(), 0.0);
}
// Set this vector to the sum of an arbitrary number of other vectors
// Currently there is no feature in LTemplate to expose multiple IDs as object references.
// Instead, IDs can be translated manually using mma::getInstance().
void setToSum(mma::IntTensorRef ids) {
if (ids.size() == 0)
throw mma::LibraryError("There must be at least one VecExpr to sum.");
// Get the size of the first vector, and resize this vector
const size_t len = mma::getInstance<VecExpr>(ids[0]).vec.size();
vec.clear();
vec.resize(len, 0.0);
// Iterate through all library expression IDs
for (const auto &id : ids) {
VecExpr &ve = mma::getInstance<VecExpr>(id);
if (ve.vec.size() != len)
throw mma::LibraryError("Mismatch between VecExpr sizes");
for (auto it1 = vec.begin(), it2 = ve.vec.begin();
it1 != vec.end();
++it1, ++it2)
{
*it1 += *it2;
}
}
}
};

View File

@ -0,0 +1,5 @@
#include "Tensor.h"
// The IntegerTensor class
typedef Tensor<mint> IntegerTensor;

View File

@ -0,0 +1,120 @@
#include <LTemplate.h>
// The mlstream.h header makes it easier to handle argument passing through MathLink
#include <mlstream.h>
#include <string>
#include <vector>
#include <cmath>
struct LinkDemo {
/* When using LinkObject based passing, the function must follow the same conventions
* which are described in the LibraryLink tutorial:
*
* - a single MLINK argument
* - void return type
*
* The arguments are passed in a list, which must be explicitly read off the link.
* The usual MathLink functions (mathlink.h) may be used to do this.
*/
void reverse(MLINK link) {
int args = 1;
if (!MLTestHeadWithArgCount(link, "List", &args))
throw mma::LibraryError("reverse: one argument expected.");
const char *str;
if (!MLGetString(link, &str))
throw mma::LibraryError("reverse: string expected.");
std::string s = str;
MLReleaseString(link, str);
std::reverse(s.begin(), s.end());
MLNewPacket(link);
MLPutString(link, s.c_str());
}
/* LTemplate comes with the mlstream.h auxiliary header, which makes it easier
* to read the arguments, check for errors, and return a result.
* It uses a streams-like interface.
*/
void reverse2(MLINK link) {
// A "context string" may optionally be passed to mlStream ("reverse2").
// This will be prepended to any automatically generated error messages.
mlStream ml(link, "reverse2");
ml >> mlCheckArgs(1); // expecting a single argument
std::string str;
ml >> str; // read a string
std::reverse(str.begin(), str.end()); // reverse it
ml.newPacket(); // must call newPacket() before returning results; same as MLNewPacket()
ml << str; // resturn a single result
}
void addTwo(MLINK link) {
mlStream ml(link); // the context string may be omitted
ml >> mlCheckArgs(2); // two arguments expected
mint a, b;
ml >> a >> b; // read two integers
ml.newPacket();
ml << a+b; // return their sum
}
// Compute the product and sum of the elements of a list
void prodSum(MLINK link) {
mlStream ml(link, "prodSum");
ml >> mlCheckArgs(1);
// vectors can be read directly form mlStream
std::vector<double> vec;
ml >> vec;
double prod = 1.0;
double sum = 0.0;
for (const auto &el : vec) {
prod *= el;
sum += el;
}
ml.newPacket();
// To return multiple results, they must be explicitly placed into a List
ml << mlHead("List", 2) // a list of two elements
<< prod << sum; // now put the correct number of list elements
}
// Compute the square root of the elements of a list.
void sqrtList(MLINK link) {
mlStream ml(link, "sqrtList");
ml >> mlCheckArgs(1);
std::vector<double> vec;
ml >> vec;
for (auto &el : vec)
el = std::sqrt(el);
ml.newPacket();
ml << vec; // vectors can be returned directly
}
// Concatenate an arbitrary number of strings
void strcat(MLINK link) {
mlStream ml(link, "strcat");
// We do not check for the number of arguments;
// instead, we read all arguments into a string vector
std::vector<std::string> vec;
ml >> vec;
// Concatenate the strings
std::string result;
for (const auto &el : vec)
result += el;
ml.newPacket();
ml << result;
}
};

View File

@ -0,0 +1,632 @@
Notebook[{
Cell[CellGroupData[{
Cell["LinkObject based passing", "Section",
ExpressionUUID -> "5f730c1c-3f28-44e9-a51b-8c18457a0324"],
Cell["\<\
This example demonstrates passing arguments and returning results through a \
MathLink connection.\
\>", "Text",
ExpressionUUID -> "4931aba6-de17-4b05-9fa9-774e9e7c77b4"],
Cell[TextData[{
ButtonBox["LinkObject-based passing",
BaseStyle->"Link",
ButtonData->
"paclet:paclet:LibraryLink/tutorial/InteractionWithMathematica#306127487"],\
" provides much more flexibility than using the standard LibraryLink type. \
However, it is also much slower. See a benchmark here:"
}], "Text",
ExpressionUUID -> "2a159845-6072-4bfb-9bec-57f3c1c411bb"],
Cell[TextData[ButtonBox["https://mathematica.stackexchange.com/questions/\
91887/mathlink-wstp-vs-librarylink-performance",
BaseStyle->"Hyperlink",
ButtonData->{
URL["https://mathematica.stackexchange.com/questions/91887/mathlink-wstp-\
vs-librarylink-performance/12"], None},
ButtonNote->
"https://mathematica.stackexchange.com/questions/91887/mathlink-wstp-vs-\
librarylink-performance/12"]], "Item",
ExpressionUUID -> "16e90e3f-c037-4f85-97cb-622e2139b86d"],
Cell[BoxData[{
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}], ";"}], "\[IndentingNewLine]",
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}]}], "Input",
ExpressionUUID -> "7e1f28de-1661-4af5-b312-b65eee18d48b"],
Cell[BoxData[
RowBox[{
RowBox[{
RowBox[{"tensorClass", "[", "type_", "]"}], ":=", "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{
RowBox[{
RowBox[{"ToString", "[", "type", "]"}], "<>", "\"\<Tensor\>\""}], ",",
"\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<set\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"type", ",", "_", ",", "\"\<Manual\>\""}], "}"}], "}"}],
",", "\"\<Void\>\""}], "]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<value\>\"", ",", "LinkObject"}], "]"}]}],
"\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]", "]"}]}],
";"}]], "Input",
ExpressionUUID -> "7fda221d-b883-438b-8492-91ba45272041"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=", "\[IndentingNewLine]",
RowBox[{"LTemplate", "[",
RowBox[{"\"\<LinkDemo\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"LClass", "[", "\[IndentingNewLine]",
RowBox[{"\"\<LinkDemo\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{"(*", " ",
RowBox[{
"LinkObject", " ", "based", " ", "passing", " ", "can", " ", "be",
" ", "specified", " ", "in", " ", "the", " ", "same", " ", "was",
" ", "as", " ", "in", " ",
RowBox[{"LibraryFunctionLoad", ":"}]}], " ", "*)"}],
"\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<reverse\>\"", ",", "LinkObject", ",", "LinkObject"}],
"]"}], ",", "\[IndentingNewLine]", "\[IndentingNewLine]",
RowBox[{"(*", " ",
RowBox[{
RowBox[{"when", " ", "using", " ", "LinkObject"}], "-",
RowBox[{
"based", " ", "passing", " ", "the", " ", "\"\<return type\>\"",
" ", "may", " ", "be", " ",
RowBox[{"omitted", ":"}]}]}], " ", "*)"}],
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<reverse2\>\"", ",", "LinkObject"}], "]"}], ",",
"\[IndentingNewLine]", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<addTwo\>\"", ",", "LinkObject"}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<prodSum\>\"", ",", "LinkObject"}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<sqrtList\>\"", ",", "LinkObject"}], "]"}], ",",
"\[IndentingNewLine]", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<strcat\>\"", ",", "LinkObject"}], "]"}]}],
"\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]", "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"tensorClass", "[", "Real", "]"}], ",", "\[IndentingNewLine]",
RowBox[{"tensorClass", "[", "Integer", "]"}]}], "\[IndentingNewLine]",
"}"}]}], "\[IndentingNewLine]", "]"}]}], ";"}]], "Input",
ExpressionUUID -> "6ed6ee35-ca79-4bb0-a779-b5016009a32b"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"CompileTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "8d0172da-dc4a-4a66-b09c-e337af11bcd8"],
Cell[CellGroupData[{
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Current directory is: \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/\
Examples/LinkObject\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Current directory is: ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
LinkObject",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "e76d9baf-6d2d-4e59-9cb8-baa17660b303"],
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Unloading library \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"LinkDemo\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\" ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Unloading library ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["LinkDemo",
RGBColor[0, 0,
Rational[2, 3]]],
Style[" ...",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "e76d9baf-6d2d-4e59-9cb8-baa17660b303"],
Cell[BoxData[
StyleBox["\<\"Generating library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "e76d9baf-6d2d-4e59-9cb8-baa17660b303"],
Cell[BoxData[
StyleBox["\<\"Compiling library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "e76d9baf-6d2d-4e59-9cb8-baa17660b303"]
}, Open ]],
Cell[BoxData["\<\"/Users/szhorvat/Library/Mathematica/SystemFiles/\
LibraryResources/MacOSX-x86-64/LinkDemo.dylib\"\>"], "Output",
ExpressionUUID -> "d37d7b4d-0a60-4c6d-8488-1f8db5b9cd9c"]
}, Open ]],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "59006634-acdc-465c-b23b-3388f0d02058"],
Cell[CellGroupData[{
Cell["Basics", "Subsubsection",
ExpressionUUID -> "08e1f854-767a-473e-8e37-517fdd8ddebd"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "=",
RowBox[{"Make", "[", "LinkDemo", "]"}]}]], "Input",
ExpressionUUID -> "1e7436af-1b46-4b2c-8438-da9f2d814fc6"],
Cell[BoxData[
RowBox[{"LinkDemo", "[", "1", "]"}]], "Output",
ExpressionUUID -> "2fd1917c-d3a5-4176-bf57-64c85cf81023"]
}, Open ]],
Cell["Reverse a string.", "Text",
ExpressionUUID -> "bd40472f-b3f6-49b9-b999-b23b80b8d65c"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<reverse\>\"", "[", "\"\<Dennis sinned.\>\"", "]"}]}]], "Input",
ExpressionUUID -> "a98933ac-d478-4d94-b8a5-017add059ddf"],
Cell[BoxData["\<\".dennis sinneD\"\>"], "Output",
ExpressionUUID -> "5b6b0ce7-bf9e-4a0a-beb0-bf18e6f04d74"]
}, Open ]],
Cell[TextData[{
Cell[BoxData[
FormBox[
RowBox[{"reverse2", "[", "]"}], TraditionalForm]],
ExpressionUUID -> "a39e405b-bd6b-4ffd-88ae-d8630e0b50c5"],
" is a simpler implementation of the same using mlstream.h."
}], "Text",
ExpressionUUID -> "bb67809e-d820-4b43-82ac-184e311a9412"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<reverse2\>\"", "[", "\"\<Dennis sinned.\>\"", "]"}]}]], "Input",
ExpressionUUID -> "f6aa51a4-2dd7-423f-bce3-4513fd0125a8"],
Cell[BoxData["\<\".dennis sinneD\"\>"], "Output",
ExpressionUUID -> "d37f147a-0ac4-46e7-98d7-c4cc7aba007d"]
}, Open ]],
Cell["Error checking is included.", "Text",
ExpressionUUID -> "a7d2e878-5009-49f2-a72e-ef03395e781e"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<reverse2\>\"", "[",
RowBox[{"\"\<foo\>\"", ",", "\"\<bar\>\""}], "]"}]}]], "Input",
ExpressionUUID -> "bcd06e5b-36da-4c50-b2aa-2d44abbd9988"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "error"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"reverse2: 1 argument expected, 2 \
received.\\\"\\)\[NoBreak]\"\>"}]], "Message", "MSG",
ExpressionUUID -> "b555dda9-2a07-4886-b6da-17876773c66b"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "f9b75ce4-5529-4e24-b633-712187be51c9"]
}, Open ]],
Cell["\<\
Note that any type that can be converted to a string can be read off the link \
as a string. Passing a number of a symbol to the function won\
\[CloseCurlyQuote]t result in an error.\
\>", "Text",
ExpressionUUID -> "a33d738a-83e5-4bb3-9305-a0df47aeca31"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<reverse2\>\"", "[", "123", "]"}]}]], "Input",
ExpressionUUID -> "2c12bcb8-71bc-490b-8623-281fcf54be92"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "391dec1a-5613-404c-a85f-a2748b02099a"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<reverse2\>\"", "[", "symbol", "]"}]}]], "Input",
ExpressionUUID -> "ce6d7519-b297-46db-a4cb-b9f4eadc92bd"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "8b8513d6-caf5-42be-9b2c-d9120ea125d9"]
}, Open ]],
Cell["Add two numbers.", "Text",
ExpressionUUID -> "c860b0f5-793b-4044-b233-68f8ed268664"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<addTwo\>\"", "[",
RowBox[{"4", ",", "5"}], "]"}]}]], "Input",
ExpressionUUID -> "21fee05f-283c-47d5-8e33-67738d4056ff"],
Cell[BoxData["9"], "Output",
ExpressionUUID -> "1087ed51-42a8-4123-9ede-2e01f1570227"]
}, Open ]],
Cell["\<\
This function tried to read integers from the link. Strings are not \
convertible to integers, thus with string arguments an error occurs.\
\>", "Text",
ExpressionUUID -> "4036c2fe-bb2b-478d-a988-cd0f1293ce8d"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<addTwo\>\"", "[",
RowBox[{"\"\<a\>\"", ",", "\"\<b\>\""}], "]"}]}]], "Input",
ExpressionUUID -> "91cc4482-9505-4651-8154-a95ad14c6a0c"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "error"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"Integer64 expected.\\\"\\)\[NoBreak]\"\>"}]], \
"Message", "MSG",
ExpressionUUID -> "304bb7e1-9adc-4e7f-942f-01f0825f3dbc"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "afffa030-4085-4308-aab6-6ec8e9c32ec1"]
}, Open ]],
Cell["\<\
Compute both the produce and sum of an arbitrary-length real list:\
\>", "Text",
ExpressionUUID -> "e849ad0c-2ecf-48e8-983c-81f1386ae91b"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<prodSum\>\"", "[",
RowBox[{"Range", "[", "5", "]"}], "]"}]}]], "Input",
ExpressionUUID -> "2f44c694-4ca8-433b-94f2-27abc3141a04"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"120.`", ",", "15.`"}], "}"}]], "Output",
ExpressionUUID -> "1094a56a-a80b-462b-840f-58cee58e6773"]
}, Open ]],
Cell["Error checking is always available.", "Text",
ExpressionUUID -> "2cf21cf2-59b7-4c24-b199-4af38484f52b"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<prodSum\>\"", "[", "12", "]"}]}]], "Input",
ExpressionUUID -> "5b320d7a-5956-46da-a48d-f4f574ebadaa"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "error"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"prodSum: Real64 list expected.\\\"\\)\
\[NoBreak]\"\>"}]], "Message", "MSG",
ExpressionUUID -> "a41bf603-f9d2-45a8-8d8b-4022c4c70f8b"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "113724dd-0d3d-4801-9fa9-5f2060057e6b"]
}, Open ]],
Cell["Compute the square root of each element in a list.", "Text",
ExpressionUUID -> "8552624d-d3e3-4eba-8f30-6e851b28f019"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<sqrtList\>\"", "[",
RowBox[{"Range", "[", "5", "]"}], "]"}]}]], "Input",
ExpressionUUID -> "7f1ab8a6-56b6-41f8-bf9a-3af150053cbc"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
"1.`", ",", "1.4142135623730951`", ",", "1.7320508075688772`", ",", "2.`",
",", "2.23606797749979`"}], "}"}]], "Output",
ExpressionUUID -> "ce544aaa-ab16-4957-a9a5-7f51c821ed19"]
}, Open ]]
}, Open ]],
Cell[CellGroupData[{
Cell["Variable number of arguments", "Subsubsection",
ExpressionUUID -> "5c32a900-84ca-4881-a485-00251fe436d5"],
Cell["Concatenate an arbitrary number of string arguments.", "Text",
ExpressionUUID -> "edcf9a77-da24-4df1-87ab-ce9030a26ea5"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<strcat\>\"", "[",
RowBox[{"\"\<foo\>\"", ",", "\"\<bar\>\""}], "]"}]}]], "Input",
ExpressionUUID -> "1afd7a38-c3ee-41a3-8de9-ee8450f60dcb"],
Cell[BoxData["\<\"foobar\"\>"], "Output",
ExpressionUUID -> "3724c723-f575-4b87-8e55-ae6cc8127c56"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<strcat\>\"", "[",
RowBox[{"\"\<foo\>\"", ",", "\"\<bar\>\"", ",", "\"\<baz\>\""}],
"]"}]}]], "Input",
ExpressionUUID -> "406b2ff3-f017-4177-aeb1-29b0d905032b"],
Cell[BoxData["\<\"foobarbaz\"\>"], "Output",
ExpressionUUID -> "4670280e-25f6-493f-a02b-4bd42d8a2f11"]
}, Open ]]
}, Open ]],
Cell[CellGroupData[{
Cell["Returning MTensors", "Subsubsection",
ExpressionUUID -> "06a99056-bbd9-43a7-8dfc-beac65d7c439"],
Cell["\<\
mlstream.h supports directly returning Real and Integer Tensors.\
\>", "Text",
ExpressionUUID -> "09498a36-b2a2-41c3-b8f6-2e4e19ad55df"],
Cell[TextData[{
"The following function creates a new instance of the RealTensor or \
IntegerTensor class. These two were included in the template specification \
using the helper function ",
Cell[BoxData[
FormBox[
RowBox[{"tensorClass", "[", "]"}], TraditionalForm]],
ExpressionUUID -> "b452462b-1341-47f3-b457-0b918f8ee2b1"],
". In C++, they share code using the template mechanism."
}], "Text",
ExpressionUUID -> "621670d4-eb5a-4acc-a241-825977492d90"],
Cell[BoxData[
RowBox[{
RowBox[{"makeTensor", "[",
RowBox[{"array_", ",", "type_"}], "]"}], ":=", "\[IndentingNewLine]",
RowBox[{"Module", "[",
RowBox[{
RowBox[{"{", "ten", "}"}], ",", "\[IndentingNewLine]",
RowBox[{
RowBox[{"ten", "=",
RowBox[{"Make", "[",
RowBox[{
RowBox[{"<|",
RowBox[{
RowBox[{"Real", "\[Rule]", "RealTensor"}], ",",
RowBox[{"Integer", "\[Rule]", "IntegerTensor"}]}], "|>"}], "[",
"type", "]"}], "]"}]}], ";", "\[IndentingNewLine]",
RowBox[{"If", "[",
RowBox[{
RowBox[{
RowBox[{"ten", "@",
RowBox[{"\"\<set\>\"", "[", "array", "]"}]}], "=!=", "Null"}], ",",
"\[IndentingNewLine]",
RowBox[{"Return", "[", "$Failed", "]"}]}], "\[IndentingNewLine]",
"]"}], ";", "\[IndentingNewLine]", "ten"}]}], "\[IndentingNewLine]",
"]"}]}]], "Input",
ExpressionUUID -> "913bdc3f-0cfd-4271-af0a-348be33d0e6e"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ten1", "=",
RowBox[{"makeTensor", "[",
RowBox[{
RowBox[{"{",
RowBox[{"1", ",", "2", ",", "3"}], "}"}], ",", "Integer"}],
"]"}]}]], "Input",
ExpressionUUID -> "71f268f0-674f-4793-b78a-55e022318aa1"],
Cell[BoxData[
RowBox[{"IntegerTensor", "[", "1", "]"}]], "Output",
ExpressionUUID -> "944b9e6b-97b7-4a5e-be9b-de773cf27c89"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ten1", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "c72d872c-9871-42f9-8d67-d6c0e0a85a7d"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"1", ",", "2", ",", "3"}], "}"}]], "Output",
ExpressionUUID -> "2f9afaf1-d14d-4b7b-8fe7-1d09d69e6862"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ten2", "=",
RowBox[{"makeTensor", "[",
RowBox[{
RowBox[{"RandomReal", "[",
RowBox[{"1", ",",
RowBox[{"{",
RowBox[{"2", ",", "3"}], "}"}]}], "]"}], ",", "Real"}],
"]"}]}]], "Input",
ExpressionUUID -> "cc26659c-f597-40ac-8287-a597920b2766"],
Cell[BoxData[
RowBox[{"RealTensor", "[", "1", "]"}]], "Output",
ExpressionUUID -> "a6b494e9-c508-4cc9-b787-097e8f29232d"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ten2", "@",
RowBox[{"\"\<value\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "1717bae0-cbf6-4060-9d05-1af1d6084804"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
"0.4400929447288291`", ",", "0.35580944983968976`", ",",
"0.6226563927874686`"}], "}"}], ",",
RowBox[{"{",
RowBox[{
"0.07763187725628051`", ",", "0.3081456393842128`", ",",
"0.19111291592768676`"}], "}"}]}], "}"}]], "Output",
ExpressionUUID -> "db5c0e01-d1c0-42a1-80bf-6f83a0d5f478"]
}, Open ]]
}, Open ]]
}, Open ]]
},
WindowSize->{808, 751},
WindowMargins->{{4, Automatic}, {Automatic, 4}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
TrackCellChangeTimes->False,
FrontEndVersion->"10.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 4, \
2014)",
StyleDefinitions->"Default.nb"
]

View File

@ -0,0 +1,5 @@
#include "Tensor.h"
// The RealTensor class.
typedef Tensor<double> RealTensor;

View File

@ -0,0 +1,42 @@
#ifndef TENSOR_H
#define TENSOR_H
#include <LTemplate.h>
#include <mlstream.h>
// Class representing a Tensor.
// It is specialized for Real and Integer tensors in RealTensor.h and IntegerTensor.h.
// This is because LTemplate requires a separate header file for each class.
template<typename T>
class Tensor {
mma::TensorRef<T> *rt = nullptr;
void free() {
if (rt) {
rt->free();
delete rt;
}
}
public:
~Tensor() { free(); }
// Set Tensor value; meant to be used in conjunction with Make[]
void set(mma::TensorRef<T> t) {
free();
rt = new mma::TensorRef<T>(t);
}
// Retrieve Tensor value using MathLink
void value(MLINK ml) {
if (! rt)
throw mma::LibraryError("No tensor set.");
mlStream link(ml);
link >> mlCheckArgs(0);
link.newPacket();
link << *rt;
}
};
#endif // TENSOR_H

View File

@ -0,0 +1,51 @@
#include <LTemplate.h>
class NA {
public:
// Store the data from a Real Tensor in a Byte NumericArray and shuffle the byte storage order
mma::NumericArrayRef<uint8_t> shuffle(mma::RealTensorRef t) {
const uint8_t *data = reinterpret_cast<uint8_t *>(t.data());
auto na = mma::makeNumericVector<uint8_t>(t.size() * sizeof(double));
for (int i=0; i < sizeof(double); ++i)
for (int j=0; j < t.size(); ++j)
na[i*t.size() + j] = data[j*sizeof(double) + i];
return na;
}
// Reverse the transformation done by shuffle()
mma::RealTensorRef deshuffle(mma::NumericArrayRef<uint8_t> na) {
if (na.size() % sizeof(double) != 0)
throw mma::LibraryError("Input size must be a multiple of 8.");
auto t = mma::makeVector<double>(na.size() / sizeof(double));
uint8_t *data = reinterpret_cast<uint8_t *>(t.data());
for (int i=0; i < sizeof(double); ++i)
for (int j=0; j < t.size(); ++j)
data[j*sizeof(double) + i] = na[i*t.size() + j];
return t;
}
// Convert an arbitrary NumericArray into a Byte NumericArray. Use the default conversion method,
// which is to clip and round values not representable as the target type.
mma::NumericArrayRef<uint8_t> clipToBytes(mma::GenericNumericArrayRef na) {
return na.convertTo<uint8_t>();
}
// Convert an arbitrary type NumericArray into a Byte NumericArray. Use the Check conversion method,
// which will verify that all values fit in the target type, and throw a LibraryError exception if they don't.
mma::NumericArrayRef<uint8_t> safeConvertToBytes(mma::GenericNumericArrayRef na) {
return na.convertTo<uint8_t>(mma::GenericNumericArrayRef::Check);
}
// Convert an arbitrary type NumericArray into a Real32 NumericArray
// using the chosen conversion method and tolerance.
mma::NumericArrayRef<float> convertToFloat(mma::GenericNumericArrayRef na, mint method, double tolerance) {
return na.convertTo<float>(mma::GenericNumericArrayRef::ConversionMethod(method), tolerance);
}
// Convert an arbitrary type NumericArray into a Integer16 NumericArray
// using the chosen conversion method and tolerance.
mma::NumericArrayRef<int16_t> convertToInteger16(mma::GenericNumericArrayRef na, mint method, double tolerance) {
return na.convertTo<int16_t>(mma::GenericNumericArrayRef::ConversionMethod(method), tolerance);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
#include <LTemplate.h>
#include <sstream>
#include <vector>
class Printing {
mint positiveValue = 1;
public:
/* Throw an mma::LibraryError exception in case of errors.
* The associated message will be printed directly in the notebook.
*/
void set(mint x) {
if (x <= 0)
throw mma::LibraryError("The value must be positive.");
positiveValue = x;
}
// Print a C string or an std::string
void hello() const {
mma::print("Hello world!");
}
/* The most convenient way to show a complex message is to use the
* stream interface mma::out.
*
* Note that the output is only printed to the notebook when the
* mma::mout buffer is flushed. This is most easily accomplished
* by inserting an std::endl into the stream. Flushing effectively
* starts a new notebook cell.
*
* Due to how Mathematica's Print[] works, a newline is always
* inserted at the end of the output, whether or not it was explicitly
* sent to mma::mout.
*
* The buffer is always flushed when the library function exits,
* thus the std::endl below is not strictly required.
*/
void printValue() const {
mma::mout << "My value is " << positiveValue << "!" << std::endl;
}
// Issue a message in Mathematica as LTemplate::info
void message(const char *msg) const {
mma::message(msg);
mma::disownString(msg); // release the string sent by the kernel
}
// Issue an error message in Mathematica as LTemplate::error
void errorMessage(const char *msg) const {
mma::message(msg, mma::M_ERROR);
mma::disownString(msg); // release the string sent by the kernel
}
// Use std::ostringstream to build a more complex message
void messageValue() const {
std::ostringstream msg;
msg << "The value is " << positiveValue << ".";
mma::message(msg.str());
}
/* The massert macro can be used in place of the standard C assert macro.
* Instead of aborting the entire kernel process, it will simply return
* from the library, and print the assertion failure message in the notebook.
*/
void assertDemo() const {
massert(42 == 137);
}
// This function demonstrates catching arbitrary exceptions
void exception() const {
std::vector<int> vec = {1,2,3};
vec.at(4); // out-of-bounds error, throws std::out_of_range exception
}
};

View File

@ -0,0 +1,449 @@
Notebook[{
Cell[CellGroupData[{
Cell["Printing messages from an LTemplate library", "Section",
ExpressionUUID -> "1afcf7ff-2148-49b1-bca3-c1d27cb68e11"],
Cell[TextData[{
"This example illustrates how to print from a library into a notebook (as in \
",
ButtonBox["Print",
BaseStyle->"Link",
ButtonData->"paclet:ref/Print"],
"), and how to issue messages (as in ",
ButtonBox["Message",
BaseStyle->"Link",
ButtonData->"paclet:ref/Print"],
"), as well as other features useful for error reporting or debugging."
}], "Text",
ExpressionUUID -> "5e0c3751-73d6-48b8-a521-a495e915b9b5"],
Cell[BoxData[{
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}], ";"}]}], "Input",
ExpressionUUID -> "04ef3909-ebdf-4f84-88f6-fe52710284f9"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=", "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{"\"\<Printing\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<set\>\"", ",",
RowBox[{"{", "Integer", "}"}], ",", "\"\<Void\>\""}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<hello\>\"", ",",
RowBox[{"{", "}"}], ",", "\"\<Void\>\""}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<printValue\>\"", ",",
RowBox[{"{", "}"}], ",", "\"\<Void\>\""}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<message\>\"", ",",
RowBox[{"{", "\"\<UTF8String\>\"", "}"}], ",", "\"\<Void\>\""}],
"]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<errorMessage\>\"", ",",
RowBox[{"{", "\"\<UTF8String\>\"", "}"}], ",", "\"\<Void\>\""}],
"]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<messageValue\>\"", ",",
RowBox[{"{", "}"}], ",", "\"\<Void\>\""}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<assertDemo\>\"", ",",
RowBox[{"{", "}"}], ",", "\"\<Void\>\""}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<exception\>\"", ",",
RowBox[{"{", "}"}], ",", "\"\<Void\>\""}], "]"}]}],
"\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]", "]"}]}],
";"}]], "Input",
ExpressionUUID -> "5992e7b7-1044-4d77-8909-7c0400320a42"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"CompileTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "030e9f79-2e4b-4b44-8c70-062e521e3c35"],
Cell[CellGroupData[{
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Current directory is: \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/\
Examples/PrintingAndMessages\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Current directory is: ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
PrintingAndMessages",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "35331c6b-de6a-4b9f-844e-603973de16b9"],
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Unloading library \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"Printing\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\" ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Unloading library ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["Printing",
RGBColor[0, 0,
Rational[2, 3]]],
Style[" ...",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "35331c6b-de6a-4b9f-844e-603973de16b9"],
Cell[BoxData[
StyleBox["\<\"Generating library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "35331c6b-de6a-4b9f-844e-603973de16b9"],
Cell[BoxData[
StyleBox["\<\"Compiling library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "35331c6b-de6a-4b9f-844e-603973de16b9"]
}, Open ]],
Cell[BoxData["\<\"/Users/szhorvat/Library/Mathematica/SystemFiles/\
LibraryResources/MacOSX-x86-64/Printing.dylib\"\>"], "Output",
ExpressionUUID -> "8a7e178c-7e8d-4096-b074-63b7ee78f393"]
}, Open ]],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "f2c79f41-1ae4-4b80-9037-7ef180f26b82"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "=",
RowBox[{"Make", "[", "Printing", "]"}]}]], "Input",
ExpressionUUID -> "6e6482a9-786c-4c70-9e9f-f997dd8d8fb6"],
Cell[BoxData[
RowBox[{"Printing", "[", "1", "]"}]], "Output",
ExpressionUUID -> "fc669461-212f-400d-a861-6265724e6d55"]
}, Open ]],
Cell[TextData[{
"Throwing a mma::LibraryError object causes the associated error message to \
be shown as an ",
Cell[BoxData[
FormBox[
RowBox[{"LTemplate", "::", "error"}], TraditionalForm]],
ExpressionUUID -> "ac3ead2e-094d-4bd9-a11a-2ad688c223d0"],
" message in the notebook."
}], "Text",
ExpressionUUID -> "ce4ad3db-ccbc-427b-8167-f14db2a6dd07"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{"\"\<set\>\"", "[",
RowBox[{"-", "1"}], "]"}]}]], "Input",
ExpressionUUID -> "4576c374-6ce1-44cb-ab66-317041a79b37"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "error"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"The value must be \
positive.\\\"\\)\[NoBreak]\"\>"}]], "Message", "MSG",
ExpressionUUID -> "655db173-eb2d-4167-808e-f1d194644760"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "07f2da4a-e2b3-46fc-a5ee-83a14302b2a3"]
}, Open ]],
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{"\"\<set\>\"", "[", "42", "]"}]}]], "Input",
ExpressionUUID -> "67abd17d-c6c3-42a0-857a-83db6147921e"],
Cell[TextData[{
"Printing directly into the notebook, as with ",
Cell[BoxData[
FormBox["Print", TraditionalForm]],
FormatType->"TraditionalForm"],
":"
}], "Text",
ExpressionUUID -> "7ca22b0f-a792-43c9-b519-d35e6babb132"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{"\"\<hello\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "9e5da1b1-e270-43a7-9d4d-8a567bff464a"],
Cell[BoxData["\<\"Hello world!\"\>"], "Print",
ExpressionUUID -> "b4ef3684-611a-4813-b24e-061f50960a34"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{"\"\<printValue\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "18e2ac87-f132-4ee9-8370-63689269e88e"],
Cell[BoxData["\<\"My value is 42!\"\>"], "Print",
ExpressionUUID -> "3a93b2df-2159-4424-9afd-35b017268e1b"]
}, Open ]],
Cell["Issuing messages directly from the library:", "Text",
ExpressionUUID -> "51d2ae64-0a11-4939-8ab7-7fd41d857685"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{
"\"\<message\>\"", "[", "\"\<Hello from Message!\>\"", "]"}]}]], "Input",
ExpressionUUID -> "058c1324-2d04-478c-aa00-f0fc62d1ea60"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "info"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"Hello from Message!\\\"\\)\[NoBreak]\"\>"}]], \
"Message", "MSG",
ExpressionUUID -> "424eee77-650c-42ae-a335-e550cf345d42"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{
"\"\<errorMessage\>\"", "[", "\"\<Error encountered.\>\"",
"]"}]}]], "Input"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "error"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"Error encountered.\\\"\\)\[NoBreak]\"\>"}]], \
"Message", "MSG"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{"\"\<messageValue\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "85bf86be-5305-4ee7-8ed8-38ab0e81753e"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "info"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"The value is 42.\\\"\\)\[NoBreak]\"\>"}]], \
"Message", "MSG",
ExpressionUUID -> "e2b1d362-349e-499f-bd0f-70e0e1d3d89a"]
}, Open ]],
Cell[TextData[{
"There are three basic types of messages to choose from ",
Cell[BoxData[
FormBox[
RowBox[{"LTemplate", "::", "info"}], TraditionalForm]],
ExpressionUUID -> "0334245a-ecf7-45ac-a4ef-ee0eb08eff26"],
", ",
Cell[BoxData[
FormBox[
RowBox[{"LTemplate", "::", "warning"}], TraditionalForm]],
ExpressionUUID -> "d41a1c79-ca68-4078-9fb4-70d5f993ef7b"],
" ",
Cell[BoxData[
FormBox[
RowBox[{"LTemplate", "::", "error"}], TraditionalForm]],
ExpressionUUID -> "cfb885ab-e547-4d18-98e5-69659ca41971"],
". Additionally, ",
Cell[BoxData[
FormBox[
RowBox[{"LTemplate", "::", "assert"}], TraditionalForm]],
ExpressionUUID -> "a192dfa9-f3ee-4892-bf5f-44a9af66177d"],
" is used by the massert() macro. When embedding LTemplate into another \
package, the symbol with which message are associated can be changed to \
something else than ",
Cell[BoxData[
FormBox["LTemplate", TraditionalForm]],
ExpressionUUID -> "1ede47f2-1366-4123-b323-006b08763669"],
". See the skeleton project included in the LTemplate distribution to see \
how this is accomplished."
}], "Text",
ExpressionUUID -> "2ec5a785-d7e5-4ef2-af22-5d6194dce795"],
Cell["\<\
LTemplate.h provides the massert() macro as a replacement for the standard C \
assert() macro. Unlike assert(), massert() will not terminate the kernel \
process. Instead, it prints the assertion failure message directly into the \
notebook and returns from the library function.\
\>", "Text",
ExpressionUUID -> "fdcf12aa-5d3d-4cb6-a0fb-f0d4f438e6a8"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{"\"\<assertDemo\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "ee1c42ba-786d-4ccc-9aa2-2c8f5fc998fb"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "assert"}], "MessageName"], ":",
" ", "\<\"Assertion failed: \[NoBreak]\\!\\(\\\"42 == 137, file \
/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
PrintingAndMessages/Printing.h, line 67\\\"\\)\[NoBreak].\"\>"}]], "Message", \
"MSG",
ExpressionUUID -> "dcf44bc0-82df-49b6-8b39-f851369c95ce"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "3f981706-4bd3-4bfd-bed2-3d21b962aefd"]
}, Open ]],
Cell[TextData[{
"LTemplate functions will catch ",
StyleBox["all",
FontSlant->"Italic"],
" C++ exceptions to avoid killing the kernel. For exceptions different from \
mma::LibraryError a warning message is shown: uncaught exceptions can \
indicate a serious error in the library, possibly even memory corruption, \
thus it is best to restart the kernel session. If the exception derives from \
std::exception, the what() description is also included."
}], "Text",
ExpressionUUID -> "827ac7f3-b8b5-4e93-8e59-2f84568a1ddd"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"expr", "@",
RowBox[{"\"\<exception\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "d3dca0fe-04a0-42f9-a548-4394ac2e1aff"],
Cell[BoxData[
RowBox[{
StyleBox[
RowBox[{"LTemplate", "::", "error"}], "MessageName"], ":",
" ", "\<\"\[NoBreak]\\!\\(\\\"Unknown exception caught in \
Printing::exception(). The library may be in an inconsistent state. It is \
recommended that you restart the kernel now to avoid \
instability.\\\\nvector\\\"\\)\[NoBreak]\"\>"}]], "Message", "MSG",
ExpressionUUID -> "4b958576-2c0e-4050-aa31-432503d82f65"],
Cell[BoxData[
RowBox[{"LibraryFunctionError", "[",
RowBox[{"\<\"LIBRARY_FUNCTION_ERROR\"\>", ",", "6"}], "]"}]], "Output",
ExpressionUUID -> "d3ca1829-0e10-4ecc-906c-71fed771766f"]
}, Open ]]
}, Open ]]
},
WindowSize->{808, 751},
WindowMargins->{{124, Automatic}, {36, Automatic}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
TrackCellChangeTimes->False,
FrontEndVersion->"10.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 4, \
2014)",
StyleDefinitions->"Default.nb"
]

View File

@ -0,0 +1,27 @@
#include <LTemplate.h>
class RA {
public:
// Store the data from a Real Tensor in a Byte RawArray and shuffle the byte storage order
mma::RawArrayRef<uint8_t> shuffle(mma::RealTensorRef t) {
const uint8_t *data = reinterpret_cast<uint8_t *>(t.data());
auto ra = mma::makeRawVector<uint8_t>(t.size() * sizeof(double));
for (int i=0; i < sizeof(double); ++i)
for (int j=0; j < t.size(); ++j)
ra[i*t.size() + j] = data[j*sizeof(double) + i];
return ra;
}
// Reverse the transformation done by shuffle()
mma::RealTensorRef deshuffle(mma::RawArrayRef<uint8_t> ra) {
if (ra.size() % sizeof(double) != 0)
throw mma::LibraryError("Input size must be a multiple of 8.");
auto t = mma::makeVector<double>(ra.size() / sizeof(double));
uint8_t *data = reinterpret_cast<uint8_t *>(t.data());
for (int i=0; i < sizeof(double); ++i)
for (int j=0; j < t.size(); ++j)
data[j*sizeof(double) + i] = ra[i*t.size() + j];
return t;
}
};

View File

@ -0,0 +1,764 @@
Notebook[{
Cell[CellGroupData[{
Cell["Working with RawArrays", \
"Section",ExpressionUUID->"fff5ad90-c711-4958-b676-be343cf900c3"],
Cell[TextData[{
StyleBox["Note: ",
FontWeight->"Bold"],
StyleBox["RawArrays, available in Mathematica 10.4 and later, are not \
documented and not supported by Wolfram Research. Mathematica 12.0 replaces ",
FontSlant->"Italic"],
Cell[BoxData["RawArray"],
FontSlant->"Italic",ExpressionUUID->
"bf9ba4bf-9bb2-4cef-83a4-b640dc36c5ce"],
StyleBox[" with the documented ",
FontSlant->"Italic"],
Cell[BoxData["NumericArray"],
FontSlant->"Italic",ExpressionUUID->
"04d40a53-9fd8-4e65-8f09-48aa2b32248b"],
StyleBox[". Consider using ",
FontSlant->"Italic"],
Cell[BoxData["NumericArray"],
FontSlant->"Italic",ExpressionUUID->
"29aa7d1e-4bb6-4b28-ad40-c144b2ed6ad6"],
StyleBox[" instead.",
FontSlant->"Italic"]
}], "Text",ExpressionUUID->"0f7c0727-0d43-4ea5-a912-e7713cf8a6a0"],
Cell[TextData[{
"This example demonstrates working with RawArrays. It requires ",
StyleBox["Mathematica",
FontSlant->"Italic"],
" 11.1 or later because it uses the ",
Cell[BoxData[
ButtonBox["BinarySerialize",
BaseStyle->"Hyperlink",
ButtonData->{
URL["http://reference.wolfram.com/language/ref/BinarySerialize.html"],
None},
ButtonNote->
"http://reference.wolfram.com/language/ref/BinarySerialize.html"]],
ExpressionUUID->"b73d0c21-921c-40e5-a0f1-bf9368919810"],
" function."
}], "Text",ExpressionUUID->"71315409-8bf1-4733-aabb-377f9feb2a01"],
Cell["\<\
RawArray support in LTemplate requires Mathematica 10.4 or later.\
\>", "Text",ExpressionUUID->"725aaf69-f8c0-4b97-a381-bde120d8bfc4"],
Cell[BoxData[{
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}],
";"}]}], "Input",ExpressionUUID->"35c0416d-df3e-4655-8910-ffa15d860a2f"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=", "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{"\"\<RA\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<shuffle\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{
RowBox[{"LType", "[",
RowBox[{"List", ",", "Real", ",", "1"}], "]"}], ",",
"\"\<Constant\>\""}], "}"}], "}"}], ",",
RowBox[{"LType", "[",
RowBox[{"RawArray", ",", "\"\<Byte\>\""}], "]"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<deshuffle\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{
RowBox[{"LType", "[",
RowBox[{"RawArray", ",", "\"\<Byte\>\""}], "]"}], ",",
"\"\<Constant\>\""}], "}"}], "}"}], ",",
RowBox[{"LType", "[",
RowBox[{"List", ",", "Real", ",", "1"}], "]"}]}], "]"}]}],
"\[IndentingNewLine]", "}"}]}], "\[IndentingNewLine]", "]"}]}],
";"}]], "Input",ExpressionUUID->"28b12d00-2a3a-4117-b361-71794c21c60d"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"CompileTemplate", "[", "template",
"]"}]], "Input",ExpressionUUID->"e003c53b-e132-4175-b40c-de5aa3ebdfbc"],
Cell[CellGroupData[{
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Current directory is: \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/\
Examples/RawArray\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Current directory is: ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
RawArray",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->
False]], "Print",ExpressionUUID->"89147b84-e437-4a32-a63e-5afd96e2a69b"],
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Unloading library \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"RA\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\" ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Unloading library ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["RA",
RGBColor[0, 0,
Rational[2, 3]]],
Style[" ...",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->
False]], "Print",ExpressionUUID->"25d27c05-18c8-42c1-b98c-fd1e585088f3"],
Cell[BoxData[
StyleBox["\<\"Generating library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[
2, 3]]]], "Print",ExpressionUUID->"8dc2deb6-488a-41ab-b3a5-29a3557814fb"],
Cell[BoxData[
StyleBox["\<\"Compiling library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[
2, 3]]]], "Print",ExpressionUUID->"ee0a54d5-cb48-461e-885c-8b333d578b51"]
}, Open ]],
Cell[BoxData["\<\"/Users/szhorvat/Library/Mathematica/SystemFiles/\
LibraryResources/MacOSX-x86-64/RA.dylib\"\>"], \
"Output",ExpressionUUID->"3b14953d-7b42-4935-96c3-6ac1db941b01"]
}, Open ]],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template",
"]"}]], "Input",ExpressionUUID->"1b175dcc-89b6-4482-a163-55b5a6a2fb58"],
Cell[BoxData[
RowBox[{
RowBox[{"obj", "=",
RowBox[{"Make", "[", "RA", "]"}]}],
";"}]], "Input",ExpressionUUID->"2655c6b0-63c0-4a66-a8bb-984c3949c8d5"],
Cell["This table of real numbers takes up 800 kB of storage.", \
"Text",ExpressionUUID->"62ca9139-cee5-45a1-aa49-013a1cf6684f"],
Cell[BoxData[
RowBox[{
RowBox[{"data", "=",
RowBox[{"Table", "[",
RowBox[{
RowBox[{"Sin", "[", "x", "]"}], ",",
RowBox[{"{",
RowBox[{"x", ",", "0", ",", "100", ",", "0.001"}], "}"}]}], "]"}]}],
";"}]], "Input",ExpressionUUID->"6302ce63-b63d-4279-b1cf-2d1993c1ac84"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ByteCount", "[", "data",
"]"}]], "Input",ExpressionUUID->"e637b750-883d-4865-8906-73261219ee9c"],
Cell[BoxData["800152"], \
"Output",ExpressionUUID->"4863b78b-d31e-478d-9472-f01fb4fa7fec"]
}, Open ]],
Cell["\<\
However, there is a lot of redundancy in the numbers as they represent a \
continuous function.\
\>", "Text",ExpressionUUID->"2752208d-da2d-421e-9d0f-5d1bfd91e42a"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"ListLinePlot", "[",
RowBox[{"data", ",",
RowBox[{"MaxPlotPoints", "\[Rule]", "500"}]}],
"]"}]], "Input",ExpressionUUID->"3ddb6a0d-c908-4c7f-a14a-5d9f90c71b9b"],
Cell[BoxData[
GraphicsBox[{{}, {{}, {},
{RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.002777777777777778],
AbsoluteThickness[1.6], LineBox[CompressedData["
1:eJxN2XlcjPv7P/DKlj05RMhkiRNRkuUgL8pSpFSyFaOIhEqW0NGQXYgQEoMs
IY0oRDWhhaR9ozLt0z5bU1H5+n2u93k8fv3T49V9d890P7uu93W/R9fZw3aL
moqKikJVReX/facvyXyV///LZg9qlI9jenJz6eePjuDJrrjz00eUUeadwske
aaLoS9WURedxpsnspsmLOso3L2FDiE7+tOhGyoIr2J21NbDHvmbK767hd+2r
Tb6/WU4NwXjBqnV7bFn25WOAYKlbzYF6yvl3cHSlyoVBpmLK5veg2TfwikPv
Svb693HSqMK1zC+PsuFDBDYeqOs1N5ny0XBYuIVlD1qYkPC/vPkx1ukGHkv5
lk552FO81D2W+EK9mPKXCBQUfhyuJ66g7BiJGQ/NTmT4iikfE2B36kGXJKsG
ynbP0TTtjuuNj02UdaLw4EH7vLfiZso1Udhp1jB5bwLLwS9QenHfl+nn2fnL
XuKHyqhbEx3Z9bpH47tavPEivVrKydF4pHlyantxJeWdMQjL9nf9+4yIst4r
aI43cMjxyKec/woTOzRyRIYplPu8gcfRec05A4V0Pw6/QVuew7JPD75SXhcL
cyg8Fx8rpjztLbwU0sKxg9j9bXuL027XenQFsfv/8R1qr27btHRWA+VTcVhd
5PZG/1YTZYt4NGpKOz3ymGfvBPhdTErPLWU5PgEXSrycfuXS+bw5Qiz3inAp
j6Xr8W4I0VG0sXD6uVrKXUK03pkyv+/MKvp9+0Tk/X5gapIrouNRibjSpVb6
PTefjvd7D/+Yw2dDw1Lo+KP3uJZkhKB5QrofFe+RX9TTcJ386/8yb+UHaNQ4
15vEMP+4D+iovRrsy2H3m/MRy7XTrG/wmb//R4iLozQd9cmLV/4RqxRmpW6n
yZOHJGwb7bxy7Sfy5oUmIWnOaK/n9Sy3J+FWitnBpW3s/NXJ+HF2r8u8eub/
Ohku5T4dgxOZ/6gU7KwY5nXGvYrO906Bn6v6vX5qZXQ8JwUWT39e0BpRQHlK
KhIRmVtVwPy/pOKGv+9eG3fy5/X8hEcyjZNanAzKez8hxk/Pz7OI/HmiT3C3
lWR6/c38zT6D4zzy/tu75M8L+wzrOxc1F3CYl1oaeuq9O3rtEPPckAZ/WUdY
bQLzjk2DQfvEQisZy1pfkBrtHxbRv5m9/hc07/SqO9OP9YuCL6iLmJefXkX+
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
ixL+D5h7iDQ=
"]]}}, {}, {}, {{}, {}}, {{}, {}}},
AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948],
Axes->{True, True},
AxesLabel->{None, None},
AxesOrigin->{0., 0},
DisplayFunction->Identity,
Frame->{{False, False}, {False, False}},
FrameLabel->{{None, None}, {None, None}},
FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}},
GridLines->{None, None},
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]],
ImagePadding->All,
Method->{"CoordinatesToolOptions" -> {"DisplayFunction" -> ({
(Identity[#]& )[
Part[#, 1]],
(Identity[#]& )[
Part[#, 2]]}& ), "CopiedValueFunction" -> ({
(Identity[#]& )[
Part[#, 1]],
(Identity[#]& )[
Part[#, 2]]}& )}},
PlotRange->{{0., 100001.}, {-0.9999999998602358, 0.9999999998313446}},
PlotRangeClipping->True,
PlotRangePadding->{{
Scaled[0.02],
Scaled[0.02]}, {
Scaled[0.05],
Scaled[0.05]}},
Ticks->{
Automatic,
Automatic}]], \
"Output",ExpressionUUID->"305faab1-e6ad-424b-941d-1a13d0f9e389"]
}, Open ]],
Cell["\<\
It is reasonable to expect this data to compress well, but BinarySerialize \
does not do very well on it. The result is 750 kB, only a 6% reduction from \
the original size.\
\>", "Text",ExpressionUUID->"db7d2b25-4b5a-4a66-99d3-c1c901095d98"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"BinarySerialize", "[",
RowBox[{"data", ",",
RowBox[{"PerformanceGoal", "\[Rule]", "\"\<Size\>\""}]}],
"]"}]], "Input",ExpressionUUID->"12e321f1-7759-4537-a82b-c85df2754486"],
Cell[BoxData[
TagBox[
TemplateBox[{RowBox[{
StyleBox[
TagBox["ByteArray", "SummaryHead"], "NonInterpretableSummary"],
StyleBox["[", "NonInterpretableSummary"],
DynamicModuleBox[{Typeset`open$$ = False},
PanelBox[
PaneSelectorBox[{False -> GridBox[{{
GridBox[{{
TagBox["\"750.4 kB\"", "SummaryItem"]}},
GridBoxAlignment -> {
"Columns" -> {{Left}}, "Rows" -> {{Automatic}}}, AutoDelete ->
False, GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings -> {
"Columns" -> {{2}}, "Rows" -> {{Automatic}}},
BaseStyle -> {
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False}]}},
GridBoxAlignment -> {"Rows" -> {{Top}}}, AutoDelete -> False,
GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
BaselinePosition -> {1, 1}], True -> GridBox[{{
GridBox[{{
TagBox["\"750.4 kB\"", "SummaryItem"]}},
GridBoxAlignment -> {
"Columns" -> {{Left}}, "Rows" -> {{Automatic}}}, AutoDelete ->
False, GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings -> {
"Columns" -> {{2}}, "Rows" -> {{Automatic}}},
BaseStyle -> {
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False}]}},
GridBoxAlignment -> {"Rows" -> {{Top}}}, AutoDelete -> False,
GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
BaselinePosition -> {1, 1}]},
Dynamic[Typeset`open$$], ImageSize -> Automatic], BaselinePosition ->
Baseline], DynamicModuleValues :> {}],
StyleBox["]", "NonInterpretableSummary"]}]},
"CopyTag",
DisplayFunction->(#& ),
InterpretationFunction->("ByteArray[<750447>]"& )],
False,
Editable->False,
SelectWithContents->True,
Selectable->
False]], "Output",ExpressionUUID->"6306f9e4-ca35-4ce4-8eb3-302884341323"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{
RowBox[{"ByteCount", "[", "%", "]"}], "/",
RowBox[{"ByteCount", "[", "data", "]"}]}], "//",
"N"}]], "Input",ExpressionUUID->"f3df6018-424d-4b85-8ba2-773367817370"],
Cell[BoxData["0.9380005298993191`"], \
"Output",ExpressionUUID->"1f42d380-bb2d-48da-8b54-8114334c6891"]
}, Open ]],
Cell[TextData[{
"The compressibility can be improved considerably by rearranging the \
underlying bytes of the data so that the first byte of each floating point \
number are stored contiguously, followed by the second bytes, and so on. This \
exposes the redundancy in the data. The ",
Cell[BoxData[
"shuffle"],ExpressionUUID->"96674cd3-b1e8-47ba-876b-a021153d76d7"],
" function performs this rearranging."
}], "Text",ExpressionUUID->"633ef7d1-1ab3-4811-9c14-0a0b865c68bd"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{
"\"\<shuffle\>\"", "[", "data",
"]"}]}]], "Input",ExpressionUUID->"f199ac5e-96fc-44c8-8cc1-bce892c26b87"],
Cell[BoxData[
TagBox[
RowBox[{"RawArray", "[",
RowBox[{"\<\"UnsignedInteger8\"\>", ",",
RowBox[{
StyleBox["\<\"<\"\>",
ShowStringCharacters->False], "\[InvisibleSpace]", "800008",
"\[InvisibleSpace]",
StyleBox["\<\">\"\>",
ShowStringCharacters->False]}]}], "]"}],
False,
Editable->False,
SelectWithContents->
True]], "Output",ExpressionUUID->"4271f9f0-fd75-469f-a37c-b8901eb6b06c"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"BinarySerialize", "[",
RowBox[{
RowBox[{"obj", "@",
RowBox[{"\"\<shuffle\>\"", "[", "data", "]"}]}], ",",
RowBox[{"PerformanceGoal", "\[Rule]", "\"\<Size\>\""}]}],
"]"}]], "Input",ExpressionUUID->"21501e88-0b6a-432b-8cac-f349f7ff1351"],
Cell[BoxData[
TagBox[
TemplateBox[{RowBox[{
StyleBox[
TagBox["ByteArray", "SummaryHead"], "NonInterpretableSummary"],
StyleBox["[", "NonInterpretableSummary"],
DynamicModuleBox[{Typeset`open$$ = False},
PanelBox[
PaneSelectorBox[{False -> GridBox[{{
GridBox[{{
TagBox["\"548.0 kB\"", "SummaryItem"]}},
GridBoxAlignment -> {
"Columns" -> {{Left}}, "Rows" -> {{Automatic}}}, AutoDelete ->
False, GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings -> {
"Columns" -> {{2}}, "Rows" -> {{Automatic}}},
BaseStyle -> {
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False}]}},
GridBoxAlignment -> {"Rows" -> {{Top}}}, AutoDelete -> False,
GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
BaselinePosition -> {1, 1}], True -> GridBox[{{
GridBox[{{
TagBox["\"548.0 kB\"", "SummaryItem"]}},
GridBoxAlignment -> {
"Columns" -> {{Left}}, "Rows" -> {{Automatic}}}, AutoDelete ->
False, GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings -> {
"Columns" -> {{2}}, "Rows" -> {{Automatic}}},
BaseStyle -> {
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False}]}},
GridBoxAlignment -> {"Rows" -> {{Top}}}, AutoDelete -> False,
GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
BaselinePosition -> {1, 1}]},
Dynamic[Typeset`open$$], ImageSize -> Automatic], BaselinePosition ->
Baseline], DynamicModuleValues :> {}],
StyleBox["]", "NonInterpretableSummary"]}]},
"CopyTag",
DisplayFunction->(#& ),
InterpretationFunction->("ByteArray[<548033>]"& )],
False,
Editable->False,
SelectWithContents->True,
Selectable->
False]], "Output",ExpressionUUID->"fbbe7a2c-a7f1-43cb-8523-9dd456a0bb84"]
}, Open ]],
Cell["Now we have a 31% reduction.", \
"Text",ExpressionUUID->"cd8235af-dbda-4a42-bf58-47bae7556ca8"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{
RowBox[{"ByteCount", "[", "%", "]"}], "/",
RowBox[{"ByteCount", "[", "data", "]"}]}], "//",
"N"}]], "Input",ExpressionUUID->"b4bc966b-6080-432b-a863-e8ae8ca6de33"],
Cell[BoxData["0.6850310940921225`"], \
"Output",ExpressionUUID->"282ba1b8-236a-477b-9925-33df390fe4d1"]
}, Open ]],
Cell["\<\
The compressibility could be improved further (at the cost of some numerical \
accuracy) by storing only the differences between the consecutive numbers. \
The following functions implement this:\
\>", "Text",ExpressionUUID->"6132506c-9377-459f-ac60-98e95b1cea24"],
Cell[BoxData[
RowBox[{
RowBox[{"compress", "[",
RowBox[{"data_", "?",
RowBox[{"(",
RowBox[{
RowBox[{"VectorQ", "[",
RowBox[{"#", ",", "Developer`MachineRealQ"}], "]"}], "&"}], ")"}]}],
"]"}], ":=", "\[IndentingNewLine]",
RowBox[{"BinarySerialize", "[", "\[IndentingNewLine]",
RowBox[{
RowBox[{"obj", "@",
RowBox[{"\"\<shuffle\>\"", "[",
RowBox[{"Prepend", "[",
RowBox[{
RowBox[{"Differences", "[", "data", "]"}], ",",
RowBox[{"First", "[", "data", "]"}]}], "]"}], "]"}]}], ",",
"\[IndentingNewLine]",
RowBox[{"PerformanceGoal", "\[Rule]", "\"\<Size\>\""}]}],
"\[IndentingNewLine]",
"]"}]}]], "Input",ExpressionUUID->"a0b56d69-1359-4221-b791-0450443bfabf"],
Cell[BoxData[
RowBox[{
RowBox[{"decompress", "[", "bytes_", "]"}], ":=",
RowBox[{"Accumulate", "[",
RowBox[{"obj", "@",
RowBox[{"\"\<deshuffle\>\"", "[",
RowBox[{"BinaryDeserialize", "[", "bytes", "]"}], "]"}]}],
"]"}]}]], "Input",ExpressionUUID->"afbcff7b-0c29-4e83-92fd-f422abb5822f"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"compress", "[", "data",
"]"}]], "Input",ExpressionUUID->"33d3fee4-c860-468b-82f8-b8701a6fbabf"],
Cell[BoxData[
TagBox[
TemplateBox[{RowBox[{
StyleBox[
TagBox["ByteArray", "SummaryHead"], "NonInterpretableSummary"],
StyleBox["[", "NonInterpretableSummary"],
DynamicModuleBox[{Typeset`open$$ = False},
PanelBox[
PaneSelectorBox[{False -> GridBox[{{
GridBox[{{
TagBox["\"440.0 kB\"", "SummaryItem"]}},
GridBoxAlignment -> {
"Columns" -> {{Left}}, "Rows" -> {{Automatic}}}, AutoDelete ->
False, GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings -> {
"Columns" -> {{2}}, "Rows" -> {{Automatic}}},
BaseStyle -> {
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False}]}},
GridBoxAlignment -> {"Rows" -> {{Top}}}, AutoDelete -> False,
GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
BaselinePosition -> {1, 1}], True -> GridBox[{{
GridBox[{{
TagBox["\"440.0 kB\"", "SummaryItem"]}},
GridBoxAlignment -> {
"Columns" -> {{Left}}, "Rows" -> {{Automatic}}}, AutoDelete ->
False, GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
GridBoxSpacings -> {
"Columns" -> {{2}}, "Rows" -> {{Automatic}}},
BaseStyle -> {
ShowStringCharacters -> False, NumberMarks -> False,
PrintPrecision -> 3, ShowSyntaxStyles -> False}]}},
GridBoxAlignment -> {"Rows" -> {{Top}}}, AutoDelete -> False,
GridBoxItemSize -> {
"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}},
BaselinePosition -> {1, 1}]},
Dynamic[Typeset`open$$], ImageSize -> Automatic], BaselinePosition ->
Baseline], DynamicModuleValues :> {}],
StyleBox["]", "NonInterpretableSummary"]}]},
"CopyTag",
DisplayFunction->(#& ),
InterpretationFunction->("ByteArray[<440021>]"& )],
False,
Editable->False,
SelectWithContents->True,
Selectable->
False]], "Output",ExpressionUUID->"566d3dab-b4a6-474d-be7f-231c09ff246b"]
}, Open ]],
Cell["This way we could achieve a 45% reduction in size.", \
"Text",ExpressionUUID->"5600a668-09b5-4540-b2f7-de4764c469ba"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{
RowBox[{"ByteCount", "@",
RowBox[{"compress", "[", "data", "]"}]}], "/",
RowBox[{"ByteCount", "[", "data", "]"}]}], "//",
"N"}]], "Input",ExpressionUUID->"4ec69f1b-8cbf-43f0-8e02-2bbcd4742ce3"],
Cell[BoxData["0.5500417420690069`"], \
"Output",ExpressionUUID->"af90dac3-cbe9-44aa-a801-f16370f0bbe6"]
}, Open ]],
Cell["For practical purposes, the accuracy loss is negligible.", \
"Text",ExpressionUUID->"e33c89ed-85d7-4c78-9419-0a1facb233b7"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{"Abs", "[",
RowBox[{
RowBox[{"decompress", "@",
RowBox[{"compress", "[", "data", "]"}]}], "-", "data"}], "]"}], "//",
"Max"}]], "Input",ExpressionUUID->"cf050699-40c0-45f3-9161-65ed31ce042a"],
Cell[BoxData["4.336808689942018`*^-19"], \
"Output",ExpressionUUID->"48e262ee-e1e1-4111-9858-f20411638ad6"]
}, Open ]]
}, Open ]]
},
WindowSize->{878, 722},
WindowMargins->{{42, Automatic}, {Automatic, 55}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
CommonDefaultFormatTypes->{"TextInline"->StandardForm},
TrackCellChangeTimes->False,
FrontEndVersion->"11.1 for Mac OS X x86 (32-bit, 64-bit Kernel) (April 18, \
2017)",
StyleDefinitions->"Default.nb"
]

View File

@ -0,0 +1,167 @@
#include <LTemplate.h>
#include <iomanip>
class Sparse {
public:
// ACCESSING PROPERTIES
mma::RealTensorRef explicitValues(mma::SparseArrayRef<double> sa) {
// The Tensor returned by .explicitValues() is part of the SparseArray data structure,
// and should not be modified. Therefore we .clone() it before returning it to Mathematica.
return sa.explicitValues().clone();
}
mma::IntTensorRef explicitPositions(mma::SparseArrayRef<double> sa) {
// Unlike .explicitValues(), the .explicitPositions() member function creates a new Tensor.
// We are responsible for freeing this Tensor when we are done using it.
// In this case we simply return it to the kernel without cloning.
return sa.explicitPositions();
}
mma::IntTensorRef rowPointers(mma::SparseArrayRef<double> sa) {
return sa.rowPointers().clone();
}
mma::IntTensorRef columnIndices(mma::SparseArrayRef<double> sa) {
return sa.columnIndices().clone();
}
// Find the rank of a sparse array.
mint depth(mma::SparseArrayRef<double> sa) {
return sa.rank();
}
// Find the dimensions of a sparse array.
mma::IntTensorRef dimensions(mma::SparseArrayRef<double> sa) {
return mma::makeVector<mint>(sa.rank(), sa.dimensions());
}
// The implicit value of a sparse array is the value assumed for the
// elements that were not explicitly stored.
double implicitValue(mma::SparseArrayRef<double> sa) {
return sa.implicitValue();
}
// DENSE <-> SPARSE CONVERSIONS
// Convert sparse arrays to dense ones.
mma::RealTensorRef toDense(mma::SparseArrayRef<double> sa) {
return sa.toTensor();
}
// Convert dense arrays to sparse ones.
mma::SparseArrayRef<double> toSparse(mma::RealTensorRef t) {
return t.toSparseArray();
}
// ELEMENT ACCESS
// Iterate through all index-pairs of a matrix and print the corresponding element.
void printMatrix(mma::SparseMatrixRef<double> sm) {
mma::mout << "Rows: " << sm.rows() << ", Cols: " << sm.cols() << std::endl;
for (int i=0; i < sm.rows(); ++i) {
for (int j=0; j < sm.cols(); ++j)
mma::mout << std::setw(9) << sm(i,j);
mma::mout << '\n';
}
}
// Iterate through all explicitly stored elements of a sparse matrix.
void printExplicit(mma::SparseMatrixRef<double> sm) {
mma::mout << "Rows: " << sm.rows() << ", Cols: " << sm.cols() << std::endl;
for (auto it = sm.begin(); it != sm.end(); ++it)
mma::mout << "(" << it.row() << ", " << it.col() << ") " << *it << '\n';
}
// Find the smallest and largest elements of a sparse array.
mma::RealTensorRef minmax(mma::SparseArrayRef<double> sa) {
auto mm = std::minmax_element(sa.explicitValues().begin(), sa.explicitValues().end());
auto res = std::minmax({*mm.first, *mm.second, sa.implicitValue()});
return mma::makeVector<double>({res.first, res.second});
}
// CREATING SPARSE ARRAYS FROM SCRATCH
// Create a 5-by-6 sparse array by explicitly specifying the stored elements.
mma::SparseMatrixRef<double> createMatrixDemo() {
// The positions matrix must me n-by-2 in size.
// Positions indices start at 1, as in Mathematica, not in 0, as in C++.
auto pos = mma::makeMatrix<mint>({{1,1}, {3,4}, {2,3}});
// The explicit value array.
auto vals = mma::makeVector<double>({1.0, 2.5, 3.6});
auto sm = mma::makeSparseMatrix(pos, vals, 5, 6);
// The Tensors we used for constructing the sparse matrix must be explicitly freed.
pos.free();
vals.free();
return sm;
}
// Create a 3D sparse array, analogously to createMatrixDemo() above.
mma::SparseArrayRef<double> createCubeDemo() {
auto pos = mma::makeMatrix<mint>({{1,2,1}, {3,2,1}});
auto vals = mma::makeVector<double>({1.5,3.2});
auto dims = mma::makeVector<mint>({3,3,3});
auto sa = mma::makeSparseArray(pos, vals, dims);
pos.free();
vals.free();
dims.free();
return sa;
}
// Create a 3-by-4 all-zero SparseArray.
mma::SparseMatrixRef<double> createZeroMatrixDemo() {
auto pos = mma::makeMatrix<mint>(0,2);
auto vals = mma::makeVector<double>(0);
auto sa = mma::makeSparseMatrix(pos, vals, 3, 4);
pos.free();
vals.free();
return sa;
}
// RECOMPUTE STRUCTURE
// Recompute the sparse structure to eliminate unnecessary explicit values.
mma::SparseArrayRef<double> resetImplicitValue(mma::SparseArrayRef<double> sa) {
return sa.resetImplicitValue();
}
// Recompute the sparse structure based on a user-specified implicit value.
mma::SparseArrayRef<double> newImplicitValue(mma::SparseArrayRef<double> sa, double iv) {
return sa.resetImplicitValue(iv);
}
// MODIFY SPARSE ARRAY
mma::SparseArrayRef<double> modify(mma::SparseArrayRef<double> sa) {
auto fun = [] (double x) { return x*x + 1; }; // x -> x*x+1
for (auto &el : sa.explicitValues())
el = fun(el);
sa.implicitValue() = fun(sa.implicitValue());
/* Optionally, use
*
* return sa.resetImplicitValue();
*
* to eliminate any redundant explicit values. This is unnecessary with the
* transformation x -> x*x+1 as it leaves no real value unchanged.
*/
return sa;
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
#include <LTemplate.h>
#include <random>
#include <numeric>
#include <iomanip>
class Tensor {
public:
// A trivial function that returns a real array as-is.
mma::RealTensorRef identity(mma::RealTensorRef t) { return t; }
// Return the depth of a real array.
mint depth(mma::RealTensorRef t) {
return t.rank();
}
// Return the dimensions of a real array. Demonstrates creating new arrays.
mma::IntTensorRef dimensions(mma::RealTensorRef t) {
return mma::makeVector<mint>(t.rank(), t.dimensions());
}
// Return the total number of elements in a real array.
mint length(mma::RealTensorRef t) {
return t.length();
}
// Sum the elements of an arbitrary dimensional real array.
// Demonstrates linear iteration through array elements.
double sum(mma::RealTensorRef t) {
double s = 0.0;
for (const auto &el : t)
s += el;
return s;
}
// Print the elements of a vector along with their indices.
// Demonstrates direct indexing.
void printVector(mma::RealTensorRef v) {
for (int i=0; i < v.size(); ++i)
mma::mout << std::setw(4) << i+1 << ": " << std::setw(9) << v[i] << '\n';
}
// Print the elements of a matrix.
// Demonstrates matrix indexing.
void printMatrix(mma::RealMatrixRef m) {
for (int i=0; i < m.rows(); ++i) {
for (int j=0; j < m.cols(); ++j)
mma::mout << std::setw(9) << m(i,j);
mma::mout << '\n';
}
}
// Directly create a complex vector using initializer list.
mma::ComplexTensorRef createVector() {
return mma::makeVector<mma::complex_t>({mma::complex_t(2,-1), 2.5, 6});
}
// Directly create a real matrix using initializer list.
mma::RealMatrixRef createMatrix() {
return mma::makeMatrix<double>({{1.5, 0.7}, {3.9, 4}});
}
// Directly create an integer cube (rank-3 Tensor) using initializer list.
mma::IntTensorRef createCube() {
return mma::makeCube<mint>({ {{1,2},{3,4}}, {{5,6},{7,8}} });
}
// Create a high-dimensional Tensor, specifying its dimensions directly.
mma::RealTensorRef ones2345() {
auto t = mma::makeTensor<double>({2,3,4,5});
std::fill(t.begin(), t.end(), 1);
return t;
}
// Create an arbitrary dimensional array of zeros.
mma::RealTensorRef zeros(mma::IntTensorRef dims) {
auto t = mma::makeTensor<double>(dims.length(), dims.data());
std::fill(t.begin(), t.end(), 0);
return t;
}
// Create an integer range.
mma::IntTensorRef range(mint i, mint j) {
if (j < i)
return mma::makeVector<mint>(0);
else {
auto vec = mma::makeVector<mint>(j-i+1);
std::iota(vec.begin(), vec.end(), i);
return vec;
}
}
// Create n random numbers between lower and upper.
mma::RealTensorRef randomReal(mint n, double lower, double upper) {
std::random_device r;
std::default_random_engine eng(r());
std::uniform_real_distribution<double> dist(lower, upper);
auto vec = mma::makeVector<double>(n);
for (auto &el : vec)
el = dist(eng);
return vec;
}
};

View File

@ -0,0 +1,963 @@
Notebook[{
Cell[CellGroupData[{
Cell["Working with arrays", "Section",
ExpressionUUID -> "89046541-ecb9-4571-a6e2-02bc16e11ecd"],
Cell["\<\
These examples demonstrate the basics of working with multidimensional \
arrays, the meat-and-potatoes of LibraryLink programming.\
\>", "Text",
ExpressionUUID -> "9c75b65d-6319-43d0-add4-e5a2f62865ec"],
Cell[BoxData[{
RowBox[{
RowBox[{"SetDirectory", "@",
RowBox[{"NotebookDirectory", "[", "]"}]}], ";"}], "\[IndentingNewLine]",
RowBox[{"Needs", "[", "\"\<LTemplate`\>\"", "]"}]}], "Input",
ExpressionUUID -> "ebe6207a-a36c-43fc-81c0-301563a98729"],
Cell[BoxData[
RowBox[{
RowBox[{"template", "=", "\[IndentingNewLine]",
RowBox[{"LClass", "[",
RowBox[{"\"\<Tensor\>\"", ",", "\[IndentingNewLine]",
RowBox[{"{", "\[IndentingNewLine]",
RowBox[{"(*", " ",
RowBox[{
"properties", " ", "and", " ", "basic", " ", "argument", " ",
"passing"}], " ", "*)"}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"LFun", "[",
RowBox[{"\"\<identity\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "_"}], "}"}], "}"}], ",",
RowBox[{"{",
RowBox[{"Real", ",", "_"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<depth\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "_"}], "}"}], "}"}], ",", "Integer"}], "]"}],
",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<dimensions\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "_"}], "}"}], "}"}], ",",
RowBox[{"{",
RowBox[{"Integer", ",", "1"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<length\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "_"}], "}"}], "}"}], ",", "Integer"}], "]"}],
",", "\[IndentingNewLine]", "\[IndentingNewLine]",
RowBox[{"(*", " ",
RowBox[{"iteration", " ", "and", " ", "element", " ", "access"}], " ",
"*)"}], "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<sum\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "_"}], "}"}], "}"}], ",", "Real"}], "]"}],
",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<printVector\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "1"}], "}"}], "}"}], ",", "\"\<Void\>\""}],
"]"}], ",", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<printMatrix\>\"", ",", " ",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Real", ",", "2"}], "}"}], "}"}], ",", "\"\<Void\>\""}],
"]"}], ",", "\[IndentingNewLine]", "\[IndentingNewLine]",
RowBox[{"(*", " ",
RowBox[{
"creating", " ", "Tensors", " ", "of", " ", "various", " ",
"dimensions"}], " ", "*)"}], "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<createVector\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Complex", ",", "1"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<createMatrix\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Real", ",", "2"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<createCube\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Integer", ",", "3"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<ones2345\>\"", ",",
RowBox[{"{", "}"}], ",",
RowBox[{"{",
RowBox[{"Real", ",", "4"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]", "\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<zeros\>\"", ",",
RowBox[{"{",
RowBox[{"{",
RowBox[{"Integer", ",", "1"}], "}"}], "}"}], ",",
RowBox[{"{",
RowBox[{"Real", ",", "_"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<range\>\"", ",",
RowBox[{"{",
RowBox[{"Integer", ",", "Integer"}], "}"}], ",",
RowBox[{"{",
RowBox[{"Integer", ",", "1"}], "}"}]}], "]"}], ",",
"\[IndentingNewLine]",
RowBox[{"LFun", "[",
RowBox[{"\"\<randomReal\>\"", ",",
RowBox[{"{",
RowBox[{"Integer",
RowBox[{"(*", " ", "n", " ", "*)"}], ",", "Real", " ",
RowBox[{"(*", " ",
RowBox[{"lower", " ", "bound"}], " ", "*)"}], ",", " ", "Real"}],
" ",
RowBox[{"(*", " ",
RowBox[{"upper", " ", "bound"}], " ", "*)"}], "}"}], ",",
RowBox[{"{",
RowBox[{"Real", ",", "1"}], "}"}]}], "]"}]}], "\[IndentingNewLine]",
"}"}]}], "\[IndentingNewLine]", "]"}]}], ";"}]], "Input",
ExpressionUUID -> "76f0bd2a-001c-4b12-8ada-339aada23a1d"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"CompileTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "84627654-cf87-45b8-b889-a53a94794b73"],
Cell[CellGroupData[{
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Current directory is: \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/\
Examples/Tensor\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Current directory is: ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["/Users/szhorvat/Repos/LTemplate/LTemplate/Documentation/Examples/\
Tensor",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "ffd01111-03d8-4e49-b831-cfea5b37552d"],
Cell[BoxData[
InterpretationBox[
RowBox[{
StyleBox["\<\"Unloading library \"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\"Tensor\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]], "\[InvisibleSpace]",
StyleBox["\<\" ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]}],
SequenceForm[
Style["Unloading library ",
RGBColor[0, 0,
Rational[2, 3]]],
Style["Tensor",
RGBColor[0, 0,
Rational[2, 3]]],
Style[" ...",
RGBColor[0, 0,
Rational[2, 3]]]],
Editable->False]], "Print",
ExpressionUUID -> "ffd01111-03d8-4e49-b831-cfea5b37552d"],
Cell[BoxData[
StyleBox["\<\"Generating library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "ffd01111-03d8-4e49-b831-cfea5b37552d"],
Cell[BoxData[
StyleBox["\<\"Compiling library code ...\"\>",
StripOnInput->False,
LineColor->RGBColor[0, 0,
Rational[2, 3]],
FrontFaceColor->RGBColor[0, 0,
Rational[2, 3]],
BackFaceColor->RGBColor[0, 0,
Rational[2, 3]],
GraphicsColor->RGBColor[0, 0,
Rational[2, 3]],
FontColor->RGBColor[0, 0,
Rational[2, 3]]]], "Print",
ExpressionUUID -> "ffd01111-03d8-4e49-b831-cfea5b37552d"]
}, Open ]],
Cell[BoxData["\<\"/Users/szhorvat/Library/Mathematica/SystemFiles/\
LibraryResources/MacOSX-x86-64/Tensor.dylib\"\>"], "Output",
ExpressionUUID -> "4839bed5-e820-4d57-aabf-7e39d7d71cf1"]
}, Open ]],
Cell[BoxData[
RowBox[{"LoadTemplate", "[", "template", "]"}]], "Input",
ExpressionUUID -> "22e04a97-b178-46db-b9c6-393d8485b3ad"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "=",
RowBox[{"Make", "[", "Tensor", "]"}]}]], "Input",
ExpressionUUID -> "e8609779-55a3-4886-ab0a-3b1298e9938a"],
Cell[BoxData[
RowBox[{"Tensor", "[", "1", "]"}]], "Output",
ExpressionUUID -> "15ca9e05-e17b-4bc9-b925-1c62fd666605"]
}, Open ]],
Cell["We will use this random matrix for testing:", "Text",
ExpressionUUID -> "6be0909a-caa7-4fa1-9ca0-a7d71004caf5"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"arr", "=",
RowBox[{"RandomReal", "[",
RowBox[{"1", ",",
RowBox[{"{",
RowBox[{"2", ",", "3"}], "}"}]}], "]"}]}]], "Input",
ExpressionUUID -> "b0dba48f-7746-4b27-a93a-045ed7352c17"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
"0.10382876133700258`", ",", "0.2392867379885466`", ",",
"0.3888547597436942`"}], "}"}], ",",
RowBox[{"{",
RowBox[{
"0.05883891620681547`", ",", "0.1635506346922937`", ",",
"0.24925601323394098`"}], "}"}]}], "}"}]], "Output",
ExpressionUUID -> "f205a1d3-46ed-47ee-b7be-8697ded518f2"]
}, Open ]],
Cell["Get the depth of the array:", "Text",
ExpressionUUID -> "da12df11-3248-4919-ade3-7eddea2ac6dd"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<depth\>\"", "[", "arr", "]"}]}]], "Input",
ExpressionUUID -> "5acca3fc-f44d-4bb4-9d72-b76bde62a457"],
Cell[BoxData["2"], "Output",
ExpressionUUID -> "ff9fdb6e-becf-4ceb-ae1c-c2e6a38f64f0"]
}, Open ]],
Cell["Get its dimensions:", "Text",
ExpressionUUID -> "6469be75-7e43-410e-a6ec-1f1d537a8956"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<dimensions\>\"", "[", "arr", "]"}]}]], "Input",
ExpressionUUID -> "6ebb3959-c0d2-4c5c-a960-59195955cb2c"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"2", ",", "3"}], "}"}]], "Output",
ExpressionUUID -> "c5ecd901-afbc-4f33-9010-597035936bf4"]
}, Open ]],
Cell["Get the total number of elements:", "Text"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<length\>\"", "[", "arr", "]"}]}]], "Input"],
Cell[BoxData["6"], "Output"]
}, Open ]],
Cell["\<\
A trivial function that returns a real-valued arbitrary dimensional array \
as-is:\
\>", "Text",
ExpressionUUID -> "ed64c68b-1c78-4d8a-9777-a1059cc09345"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<identity\>\"", "[", "arr", "]"}]}]], "Input",
ExpressionUUID -> "41d120e5-5fcf-4b0d-82ce-6d95c2c6242c"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
"0.10382876133700258`", ",", "0.2392867379885466`", ",",
"0.3888547597436942`"}], "}"}], ",",
RowBox[{"{",
RowBox[{
"0.05883891620681547`", ",", "0.1635506346922937`", ",",
"0.24925601323394098`"}], "}"}]}], "}"}]], "Output",
ExpressionUUID -> "48408d7c-01f2-4fab-a51c-5bfd29ef1b39"]
}, Open ]],
Cell["Sum the elements of an array:", "Text",
ExpressionUUID -> "02b45b96-3bbe-43d3-84e1-a1c3ca9a7848"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<sum\>\"", "[", "arr", "]"}]}]], "Input",
ExpressionUUID -> "641e3ed1-74b6-44a3-9737-c530fb156673"],
Cell[BoxData["1.2036158232022935`"], "Output",
ExpressionUUID -> "df28ec17-9f54-4832-826c-bb397e31a9bc"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"Total", "[",
RowBox[{"arr", ",", "Infinity"}], "]"}]], "Input",
ExpressionUUID -> "628e794d-7f15-4689-8403-900a0c71664e"],
Cell[BoxData["1.2036158232022935`"], "Output",
ExpressionUUID -> "f10bf4c9-76a6-4787-93eb-ed2634520e02"]
}, Open ]],
Cell["\<\
This function demonstrates iterating through the elements of a matrix, and \
printing them to the notebook:\
\>", "Text",
ExpressionUUID -> "78452fda-9dd0-47a4-a0a3-35ba17a928f2"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<printMatrix\>\"", "[", "arr", "]"}]}]], "Input",
ExpressionUUID -> "b743607a-3b07-4620-b727-8eaf04f652c8"],
Cell[BoxData["\<\" 0.103829 0.239287 0.388855\\n0.0588389 0.163551 0.249256\"\
\>"], "Print",
ExpressionUUID -> "8ecfd94f-7d7d-4c33-9778-368a6c87f256"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"MatrixForm", "[", "arr", "]"}]], "Input",
ExpressionUUID -> "f0be799a-5da5-4440-8d0a-7a5fd80798bb"],
Cell[BoxData[
TagBox[
RowBox[{"(", "\[NoBreak]", GridBox[{
{"0.10382876133700258`", "0.2392867379885466`", "0.3888547597436942`"},
{"0.05883891620681547`", "0.1635506346922937`", "0.24925601323394098`"}
},
GridBoxAlignment->{
"Columns" -> {{Center}}, "ColumnsIndexed" -> {}, "Rows" -> {{Baseline}},
"RowsIndexed" -> {}},
GridBoxSpacings->{"Columns" -> {
Offset[0.27999999999999997`], {
Offset[0.7]},
Offset[0.27999999999999997`]}, "ColumnsIndexed" -> {}, "Rows" -> {
Offset[0.2], {
Offset[0.4]},
Offset[0.2]}, "RowsIndexed" -> {}}], "\[NoBreak]", ")"}],
Function[BoxForm`e$,
MatrixForm[BoxForm`e$]]]], "Output",
ExpressionUUID -> "03272424-4977-45d9-8e77-6a9c369c770c"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<printVector\>\"", "[",
RowBox[{"{",
RowBox[{"E", ",", "Pi", ",", "EulerGamma"}], "}"}], "]"}]}]], "Input"],
Cell[BoxData["\<\" 1: 2.71828\\n 2: 3.14159\\n 3: 0.577216\"\>"], \
"Print"]
}, Open ]],
Cell["\<\
Create vectors, matrices or cubes (3D arrays) directly. Also demonstrates \
Complex, Real and Integer tensors.\
\>", "Text",
ExpressionUUID -> "248f6a25-7cb6-411e-8131-0c6d0e1fc4ad"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<createVector\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "9d335f32-8d83-40aa-993e-63eb86d0d3ab"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"2.`", "\[VeryThinSpace]", "-",
RowBox[{"1.`", " ", "\[ImaginaryI]"}]}], ",",
RowBox[{"2.5`", "\[VeryThinSpace]", "+",
RowBox[{"0.`", " ", "\[ImaginaryI]"}]}], ",",
RowBox[{"6.`", "\[VeryThinSpace]", "+",
RowBox[{"0.`", " ", "\[ImaginaryI]"}]}]}], "}"}]], "Output",
ExpressionUUID -> "f08f788f-54f0-4360-b650-f70491393107"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<createMatrix\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "6c796ef8-0b4a-4e18-91c9-c3b28d930e1d"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1.5`", ",", "0.7`"}], "}"}], ",",
RowBox[{"{",
RowBox[{"3.9`", ",", "4.`"}], "}"}]}], "}"}]], "Output",
ExpressionUUID -> "c594d8aa-541c-4887-b52a-cecbe9c837c7"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<createCube\>\"", "[", "]"}]}]], "Input",
ExpressionUUID -> "80811547-218b-4994-9296-a52bd69d5a18"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1", ",", "2"}], "}"}], ",",
RowBox[{"{",
RowBox[{"3", ",", "4"}], "}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"5", ",", "6"}], "}"}], ",",
RowBox[{"{",
RowBox[{"7", ",", "8"}], "}"}]}], "}"}]}], "}"}]], "Output",
ExpressionUUID -> "2195c631-51c7-4985-ae01-1f5fc2927435"]
}, Open ]],
Cell[TextData[{
"Directly create an array of ones of dimensions ",
Cell[BoxData[
FormBox[
RowBox[{"{",
RowBox[{"2", ",", "3", ",", "4", ",", "5"}], "}"}], TraditionalForm]]],
"."
}], "Text"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<ones2345\>\"", "[", "]"}]}]], "Input"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}]}], "}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}], ",",
RowBox[{"{",
RowBox[{"1.`", ",", "1.`", ",", "1.`", ",", "1.`", ",", "1.`"}],
"}"}]}], "}"}]}], "}"}]}], "}"}]], "Output"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"Dimensions", "[", "%", "]"}]], "Input"],
Cell[BoxData[
RowBox[{"{", "1", "}"}]], "Output"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<zeros\>\"", "[",
RowBox[{"{",
RowBox[{"3", ",", "2", ",", "2"}], "}"}], "]"}]}]], "Input"],
Cell[BoxData[
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"0.`", ",", "0.`"}], "}"}], ",",
RowBox[{"{",
RowBox[{"0.`", ",", "0.`"}], "}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"0.`", ",", "0.`"}], "}"}], ",",
RowBox[{"{",
RowBox[{"0.`", ",", "0.`"}], "}"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{
RowBox[{"{",
RowBox[{"0.`", ",", "0.`"}], "}"}], ",",
RowBox[{"{",
RowBox[{"0.`", ",", "0.`"}], "}"}]}], "}"}]}], "}"}]], "Output"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"Dimensions", "[", "%", "]"}]], "Input"],
Cell[BoxData[
RowBox[{"{", "1", "}"}]], "Output"]
}, Open ]],
Cell["Create an array of arbitrary dimensions, filled with zeros:", "Text"],
Cell["Create integer ranges:", "Text",
ExpressionUUID -> "2cb9e4db-6866-4601-8588-697007e22adc"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<range\>\"", "[",
RowBox[{"3", ",", "7"}], "]"}]}]], "Input",
ExpressionUUID -> "8394e275-4553-426b-82b5-d2402e369267"],
Cell[BoxData[
RowBox[{"{",
RowBox[{"3", ",", "4", ",", "5", ",", "6", ",", "7"}], "}"}]], "Output",
ExpressionUUID -> "8da9db06-6a75-46e1-b723-289393a60607"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<range\>\"", "[",
RowBox[{"1", ",", "0"}], "]"}]}]], "Input",
ExpressionUUID -> "9fdf257a-00fc-4a15-beb0-496056e630fb"],
Cell[BoxData[
RowBox[{"{", "}"}]], "Output",
ExpressionUUID -> "1aa7edbb-b61f-4158-96ae-9b00990af0a4"]
}, Open ]],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{"obj", "@",
RowBox[{"\"\<range\>\"", "[",
RowBox[{"1", ",", "1"}], "]"}]}]], "Input",
ExpressionUUID -> "de1d9044-84ee-49c2-91a8-e2213ece219e"],
Cell[BoxData[
RowBox[{"{", "1", "}"}]], "Output",
ExpressionUUID -> "feecdea2-f8a2-4f82-9f35-66fe7046dc3c"]
}, Open ]],
Cell["Generate 1000 random numbers between 0 and 10:", "Text",
ExpressionUUID -> "d80ae80b-b1db-4137-89d7-59d272a5ab77"],
Cell[CellGroupData[{
Cell[BoxData[
RowBox[{
RowBox[{"obj", "@",
RowBox[{"\"\<randomReal\>\"", "[",
RowBox[{"1000", ",", "0", ",", "10"}], "]"}]}], "//",
"Histogram"}]], "Input",
ExpressionUUID -> "dc1549e3-4320-4f36-ab93-954603f5a072"],
Cell[BoxData[
GraphicsBox[{
{RGBColor[0.987148, 0.8073604000000001, 0.49470040000000004`], EdgeForm[{
Opacity[0.63], Thickness[Small]}], {},
{RGBColor[0.987148, 0.8073604000000001, 0.49470040000000004`], EdgeForm[{
Opacity[0.63], Thickness[Small]}],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{0., 0}, {1., 81}, "RoundingRadius" -> 0]},
ImageSizeCache->{{26.254403522818258`,
59.27642113690954}, {-48.1405962925824, 91.93456273819318}}],
StatusArea[#, 81]& ,
TagBoxNote->"81"],
StyleBox["81", {}, StripOnInput -> False]],
Annotation[#,
Style[81, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{1., 0}, {2., 98}, "RoundingRadius" -> 0]},
ImageSizeCache->{{58.77642113690954,
91.79843875100082}, {-77.43414818793038, 91.93456273819318}}],
StatusArea[#, 98]& ,
TagBoxNote->"98"],
StyleBox["98", {}, StripOnInput -> False]],
Annotation[#,
Style[98, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{2., 0}, {3., 105}, "RoundingRadius" -> 0]},
ImageSizeCache->{{91.29843875100082,
124.3204563650921}, {-89.49619896836775, 91.93456273819318}}],
StatusArea[#, 105]& ,
TagBoxNote->"105"],
StyleBox["105", {}, StripOnInput -> False]],
Annotation[#,
Style[105, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{3., 0}, {4., 93}, "RoundingRadius" -> 0]},
ImageSizeCache->{{123.8204563650921,
156.84247397918338`}, {-68.81839763047508, 91.93456273819318}}],
StatusArea[#, 93]& ,
TagBoxNote->"93"],
StyleBox["93", {}, StripOnInput -> False]],
Annotation[#,
Style[93, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{4., 0}, {5., 105}, "RoundingRadius" -> 0]},
ImageSizeCache->{{156.34247397918338`,
189.36449159327466`}, {-89.49619896836775, 91.93456273819318}}],
StatusArea[#, 105]& ,
TagBoxNote->"105"],
StyleBox["105", {}, StripOnInput -> False]],
Annotation[#,
Style[105, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{5., 0}, {6., 110}, "RoundingRadius" -> 0]},
ImageSizeCache->{{188.86449159327466`,
221.88650920736595`}, {-98.11194952582305, 91.93456273819318}}],
StatusArea[#, 110]& ,
TagBoxNote->"110"],
StyleBox["110", {}, StripOnInput -> False]],
Annotation[#,
Style[110, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{6., 0}, {7., 91}, "RoundingRadius" -> 0]},
ImageSizeCache->{{221.38650920736595`,
254.40852682145723`}, {-65.37209740749297, 91.93456273819318}}],
StatusArea[#, 91]& ,
TagBoxNote->"91"],
StyleBox["91", {}, StripOnInput -> False]],
Annotation[#,
Style[91, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{7., 0}, {8., 100}, "RoundingRadius" -> 0]},
ImageSizeCache->{{253.90852682145723`,
286.93054443554854`}, {-80.88044841091248, 91.93456273819318}}],
StatusArea[#, 100]& ,
TagBoxNote->"100"],
StyleBox["100", {}, StripOnInput -> False]],
Annotation[#,
Style[100, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{8., 0}, {9., 104}, "RoundingRadius" -> 0]},
ImageSizeCache->{{286.43054443554854`,
319.4525620496398}, {-87.77304885687671, 91.93456273819318}}],
StatusArea[#, 104]& ,
TagBoxNote->"104"],
StyleBox["104", {}, StripOnInput -> False]],
Annotation[#,
Style[104, {}], "Tooltip"]& ],
TagBox[
TooltipBox[
TagBox[
DynamicBox[{
FEPrivate`If[
CurrentValue["MouseOver"],
EdgeForm[{
GrayLevel[0.5],
AbsoluteThickness[1.5],
Opacity[0.66]}], {}, {}],
RectangleBox[{9., 0}, {10., 113}, "RoundingRadius" -> 0]},
ImageSizeCache->{{318.9525620496398,
351.9745796637311}, {-103.28139986029622`, 91.93456273819318}}],
StatusArea[#, 113]& ,
TagBoxNote->"113"],
StyleBox["113", {}, StripOnInput -> False]],
Annotation[#,
Style[113, {}],
"Tooltip"]& ]}, {}, {}}, {{}, {}, {}, {}, {}, {}, {}, {}, {}, {}}},
AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948],
Axes->{True, True},
AxesLabel->{None, None},
AxesOrigin->{-0.2, 0},
FrameLabel->{{None, None}, {None, None}},
FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}},
GridLines->{None, None},
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]],
PlotRange->{{0., 10.}, {All, All}},
PlotRangePadding->{{
Scaled[0.02],
Scaled[0.02]}, {
Scaled[0.02],
Scaled[0.05]}},
Ticks->{Automatic, Automatic}]], "Output",
ExpressionUUID -> "00030c6d-66e9-4869-b5ac-1f17488c7fd2"]
}, Open ]]
}, Open ]]
},
WindowSize->{808, 751},
WindowMargins->{{68, Automatic}, {Automatic, 44}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
TrackCellChangeTimes->False,
FrontEndVersion->"10.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 4, \
2014)",
StyleDefinitions->"Default.nb"
]

View File

@ -0,0 +1,323 @@
Notebook[{
Cell[CellGroupData[{
Cell["LTemplate FAQ", "Title",
ExpressionUUID -> "a5b9798d-8acb-4713-b51f-9f5a4097104d"],
Cell[CellGroupData[{
Cell["What is LTemplate?", "Subsection",
ExpressionUUID -> "e800e0bf-3d74-4a5b-be42-25cbbd33f0a3"],
Cell[TextData[{
"LTemplate is a system that makes ",
ButtonBox["LibraryLink",
BaseStyle->"Link",
ButtonData->"paclet:LibraryLink/tutorial/Overview"],
" development fast and convenient."
}], "Text",
ExpressionUUID -> "84bc5199-cfac-4299-bbcf-7a325adebdda"],
Cell[TextData[{
"LTemplate is a ",
StyleBox["Mathematica",
FontSlant->"Italic"],
" package that simplifies writing LibraryLink code by automatically \
generating repetitive code based on \[OpenCurlyDoubleQuote]templates\
\[CloseCurlyDoubleQuote] describing a C++ class interface. These are inspired \
by ",
StyleBox["MathLink",
FontSlant->"Italic"],
"\[CloseCurlyQuote]s ",
StyleBox[".tm", "Program"],
" files. It also provides easy to use C++ wrapper classes for the usual \
LibraryLink types, as well as a number of convenience functions for faster \
development and debugging."
}], "Text",
ExpressionUUID -> "5c9c4883-d28c-4484-a0dd-dbdec923af1b"]
}, Open ]],
Cell[CellGroupData[{
Cell["What is the best way to learn LTemplate?", "Subsection",
ExpressionUUID -> "10ef8230-2810-479d-a49e-81c66d950569"],
Cell[TextData[{
"It is recommended to understand the basics of the LibraryLink C API before \
starting to use LTemplate. ",
ButtonBox["There is an excellent set of tutorials at Wolfram Community",
BaseStyle->"Hyperlink",
ButtonData->{
URL["http://community.wolfram.com/groups/-/m/t/189735/"], None},
ButtonNote->"http://community.wolfram.com/groups/-/m/t/189735/"],
", written by Arnoud Buzing. These are much easier to follow than the User \
Guide. Read them concurrently with ",
ButtonBox["the LibraryLink User Guide",
BaseStyle->"Link",
ButtonData->"paclet:LibraryLink/tutorial/Overview"],
" and learn at least about passing numerical arguments, returning results, \
and basic handling of arrays."
}], "Text",
ExpressionUUID -> "c89e8e65-ef9d-4631-8615-3f48fa4c6a24"],
Cell[TextData[{
"Once you have a grasp of the basics, start reading ",
ButtonBox["LTemplateTutorial",
BaseStyle->"Hyperlink",
ButtonData->{"LTemplateTutorial.nb", None}],
" while concurrently looking at the example programs in the \
Documentation/Examples directory. Start with these two sets of examples: \
Basics, Tensor."
}], "Text",
ExpressionUUID -> "48223301-4631-4c9d-8eba-22f3997bbeda"],
Cell[TextData[{
"When working with array-like types, such as Tensors, SparseArray, Images \
and RawArrays, it is important to understand memory management in \
LibraryLink. This is discussed in the ",
ButtonBox["Memory Management of MTensors",
BaseStyle->"Link",
ButtonData->
"paclet:LibraryLink/tutorial/InteractionWithMathematica#97446640"],
" section of the User Guide."
}], "Text",
ExpressionUUID -> "200e6859-1313-406b-bc6e-7a01099ac1c7"]
}, Open ]],
Cell[CellGroupData[{
Cell["\<\
Do I need to learn LibraryLink before starting to use LTemplate?\
\>", "Subsection",
ExpressionUUID -> "fe2694c6-98bb-4b52-9fee-1ff1b8bc7609"],
Cell[TextData[{
"Yes, it is strongly recommended to learn at least the basics. Please take a \
look at ",
ButtonBox["the LibraryLink user guide",
BaseStyle->"Link",
ButtonData->"paclet:LibraryLink/tutorial/Overview"],
" and understand the basic LibraryLink examples."
}], "Text",
ExpressionUUID -> "7be581f2-80bf-479c-8e6e-b52c26c90176"],
Cell["\<\
While LTemplate makes it much easier and faster to set up a library, it is \
necessary to understand certain concepts, such as the memory management of \
MTensors, to be able to write correct code.\
\>", "Text",
ExpressionUUID -> "227313e7-b579-4141-b2de-fdec7ba242c8"]
}, Open ]],
Cell[CellGroupData[{
Cell["What are the minimum system requirements?", "Subsection",
ExpressionUUID -> "51910736-00c4-49b0-a96a-8f49ce40bc9b"],
Cell[TextData[{
StyleBox["Mathematica",
FontSlant->"Italic"],
" 10.0 or later and a C++11 capable compiler."
}], "Text",
ExpressionUUID -> "9fe30d23-5ab4-4554-8cf8-8c2bdfd839b0"],
Cell["\<\
If using the default compiler on OS X, then OS X 10.9 or later is needed for \
C++11 support.\
\>", "Text",
ExpressionUUID -> "21a75098-23b8-4b98-a52d-c5bf149c206b"]
}, Open ]],
Cell[CellGroupData[{
Cell["\<\
Can I use LTemplate to generate an interface to an existing class?\
\>", "Subsection",
ExpressionUUID -> "1e1f3d74-d37e-4ca9-9add-9bd3b2dc3f03"],
Cell["\<\
No. Just like LibraryLink\[CloseCurlyQuote]s library functions, LTemplate \
classes must follow certain conventions.\
\>", "Text",
ExpressionUUID -> "6149f3af-6968-4612-821d-e0bb36832284"],
Cell["\<\
To interface with another library, one would normally create conversion \
functions to/from that library\[CloseCurlyQuote]s data types. See \
Examples/Armadillo for an example.\
\>", "Text",
ExpressionUUID -> "d359e04d-37aa-4085-a1a0-9debfc2116ff"]
}, Open ]],
Cell[CellGroupData[{
Cell["Can I use C instead of C++?", "Subsection",
ExpressionUUID -> "450cc096-5703-43bd-99bc-43067ca00ffc"],
Cell["\<\
LTemplate requires the use of C++. It is the features that C++ provides over \
C that made it possible to construct an easier-to-use interface than the C \
LibraryLink API. However, LTemplate only requires the use of relatively basic \
C++ features.\
\>", "Text",
ExpressionUUID -> "648cfb8b-abac-4831-a302-3630b1347094"]
}, Open ]],
Cell[CellGroupData[{
Cell["\<\
Why do I need to create a class? I only need a few functions.\
\>", "Subsection",
ExpressionUUID -> "199aeea2-6a9e-4d87-96b8-83f5fb006faa"],
Cell["\<\
Future versions of LTemplate may add support for free functions.\
\>", "Text",
ExpressionUUID -> "e81f5fe4-c895-4058-8ce6-e841fe1da761"],
Cell["\<\
Originally, LTemplate was created to make it easy to set up managed library \
expressions, which map very well to classes. If you only need free \
functions, you can always create a single instance of a class, and keep \
calling functions on it.\
\>", "Text",
ExpressionUUID -> "cf515e75-a8f9-48e7-b670-3165f0b60d1e"],
Cell["\<\
However, non-trivial libraries that manage a global state, such as physics \
simulations, typically benefit from encapsulating that state into a class. \
Then it becomes easy to create multiple simulation states and manage them \
simultaneously.\
\>", "Text",
ExpressionUUID -> "a9232ad7-1bf9-4d2f-961d-48ddfa5cdf2c"]
}, Open ]],
Cell[CellGroupData[{
Cell["How do I write library initialization and cleanup code?", "Subsection",
ExpressionUUID -> "7156cafb-6789-46cc-861c-dde52523c241"],
Cell[TextData[{
"Currently LTemplate doesn\[CloseCurlyQuote]t support injecting code into ",
StyleBox["WolframLibrary_initialize", "Program"],
" and ",
StyleBox["WolframLibrary_uninitialize", "Program"],
". Add the initialization and cleanup code to the constructor and destructor \
of a special class. Then create a single instance of this class. The \
destructor will be called when the library is unloaded."
}], "Text",
ExpressionUUID -> "c0e101f7-fb15-475d-86d2-91512f7e6871"],
Cell["\<\
A drawback of this method is that it cannot be controlled which classes and \
which objects will be destroyed last. This will be remedied in a future \
version of LTemplate.\
\>", "Text",
ExpressionUUID -> "8fdffd20-a2eb-4df5-903f-b07a1baec6b7"]
}, Open ]],
Cell[CellGroupData[{
Cell["Can I use the LibraryLink C API with LTemplate?", "Subsection",
ExpressionUUID -> "3869333c-c237-439b-9bda-cb8b0d1121c5"],
Cell[TextData[{
"Yes, the C functions from ",
StyleBox["WolframLibrary.h", "Program"],
" can be used in a library built with LTemplate."
}], "Text",
ExpressionUUID -> "e578081d-e797-43a6-8e7c-e0a6ececb829"],
Cell[TextData[{
"Wrapper classes, such as ",
StyleBox["mma::TensorRef", "Program"],
", always provide access to the underlying data structure, such as ",
StyleBox["MTensor", "Program"],
". See e.g. ",
StyleBox["mma::TensorRef::tensor()", "Program"],
"."
}], "Text",
ExpressionUUID -> "42722a35-6258-4c92-9f37-cf435e4cc308"],
Cell[TextData[{
StyleBox["mma::libData", "Program"],
" provides access to the LibraryLink callback functions."
}], "Text",
ExpressionUUID -> "c9873b5b-4323-4c9b-bf4f-c57dbb5cfbdb"]
}, Open ]],
Cell[CellGroupData[{
Cell["Can I use LTemplate in another package?", "Subsection",
ExpressionUUID -> "909417d4-a800-483c-87ab-9ea4ce1c1c17"],
Cell["\<\
Yes, LTemplate is designed to be embeddable into other packages.\
\>", "Text",
ExpressionUUID -> "a96a30e4-40f1-4dd6-9276-ee30fd5a3a7e"],
Cell["\<\
Mathematica packages that rely on LTemplate should embed it instead of \
requiring users to install LTemplate. This is to avoid compatibility problems.\
\>", "Text",
ExpressionUUID -> "b4c08f9c-74dd-4046-a480-8e2f8dfd5447"],
Cell["\<\
When LTemplate is embedded into another package, it supports a few \
customization features:\
\>", "Text",
ExpressionUUID -> "626ecd89-cbfc-4337-88a2-b6b8380b001b"],
Cell[CellGroupData[{
Cell["\<\
The symbol that library messages are associated with can be customized.\
\>", "Item",
ExpressionUUID -> "bd6578de-767a-4477-9e09-f0ef6e2707dc"],
Cell["\<\
LTemplate can be set up for lazy loading, so that each function gets loaded \
only when needed.\
\>", "Item",
ExpressionUUID -> "caeec10e-d9e6-4ec4-b674-66badb0548b8"]
}, Open ]],
Cell["\<\
See the skeleton-project directory for an example of embedding LTemplate.\
\>", "Text",
ExpressionUUID -> "7cd2aed8-e1d5-401d-8058-ed20cf1575c4"]
}, Open ]],
Cell[CellGroupData[{
Cell["Are there any published packages built on LTemplate?", "Subsection",
ExpressionUUID -> "1ccb7075-3970-4518-bcac-634be0af38e5"],
Cell[TextData[{
ButtonBox["IGraph/M",
BaseStyle->"Hyperlink",
ButtonData->{
URL["http://szhorvat.net/mathematica/IGraphM"], None},
ButtonNote->"http://szhorvat.net/mathematica/IGraphM"],
" is an interface to the ",
ButtonBox["igraph network analysis library",
BaseStyle->"Hyperlink",
ButtonData->{
URL["http://igraph.org/"], None},
ButtonNote->"http://igraph.org/"],
". It is built on top of LTemplate, and it implements a wrapper class for \
igraph graphs."
}], "Text",
ExpressionUUID -> "954ec604-83e0-4c38-acf8-7c72a132ab8f"]
}, Open ]]
}, Open ]]
},
WindowSize->{641, 852},
WindowMargins->{{183, Automatic}, {Automatic, 49}},
PrivateNotebookOptions->{"FileOutlineCache"->False},
TrackCellChangeTimes->False,
FrontEndVersion->"10.4 for Mac OS X x86 (32-bit, 64-bit Kernel) (April 11, \
2016)",
StyleDefinitions->"Default.nb"
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2019 Szabolcs Horvát.
*
* See the file LICENSE.txt for copying permission.
*/
// These #includes are redundant. They are only for the IDE.
#include "LTemplate.h"
#include "LTemplateHelpers.h"
namespace mma {
WolframLibraryData libData;
namespace detail { // private
int MBuffer::sync() {
// If the last character is a newline, remove it.
// This makes it convenient to flush with std::endl
if (pptr() > pbase() && pptr()[-1] == '\n')
pbump(-1);
*pptr() = '\0';
std::ptrdiff_t n = pptr() - pbase();
if (n > 0)
mma::print(&buf.front());
pbump(-n);
return 0;
}
std::streambuf::int_type MBuffer::overflow(std::streambuf::int_type ch) {
if (ch != traits_type::eof()) {
massert(pptr() == epptr()); // overflow should only be called if the buffer is out of space
*pptr() = traits_type::to_char_type(ch);
std::size_t offset = pptr() - pbase();
std::size_t old_buf_size = buf.size() - 1;
buf.resize( 2*old_buf_size + 1 );
setp( &buf.front(), &buf.back() );
pbump( offset + 1 );
}
return ch;
}
static MBuffer mbuf;
} // end namespace detail
std::ostream mout(&detail::mbuf);
void message(const char *msg, MessageType type) {
if (msg == NULL)
return;
if (libData->AbortQ())
return; // trying to use the MathLink connection during an abort will break it
const char *tag;
switch (type) {
case M_ERROR:
tag = "error";
break;
case M_WARNING:
tag = "warning";
break;
case M_ASSERT:
tag = "assert";
break;
case M_INFO:
default:
tag = "info";
}
MLINK link = libData->getMathLink(libData);
MLPutFunction(link, "EvaluatePacket", 1);
MLPutFunction(link, "Message", 2);
MLPutFunction(link, "MessageName", 2);
MLPutSymbol(link, LTEMPLATE_MESSAGE_SYMBOL);
MLPutString(link, tag);
MLPutString(link, msg);
libData->processMathLink(link);
int pkt = MLNextPacket(link);
if (pkt == RETURNPKT)
MLNewPacket(link);
}
} // end namespace mma

View File

@ -0,0 +1,22 @@
#ifndef LTEMPLATE_COMPILER_SETUP_H
#define LTEMPLATE_COMPILER_SETUP_H
#if __cplusplus >= 201103L || _MSC_VER >= 1900
#define LTEMPLATE_USE_CXX11
#endif
#if LTEMPLATE_MMA_VERSION >= 1040 && defined (LTEMPLATE_USE_CXX11)
#define LTEMPLATE_RAWARRAY
#endif
#if LTEMPLATE_MMA_VERSION >= 1200 && defined (LTEMPLATE_USE_CXX11)
#define LTEMPLATE_NUMERICARRAY
#endif
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif
#endif // LTEMPLATE_COMPILER_SETUP_H

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2019 Szabolcs Horvát.
*
* See the file LICENSE.txt for copying permission.
*/
#ifndef LTEMPLATE_HELPERS_H
#define LTEMPLATE_HELPERS_H
#include "LTemplate.h"
#include <algorithm>
#include <vector>
#include <map>
namespace mma {
namespace detail {
// Functions for getting and setting arguments and return values
template<typename T>
inline TensorRef<T> getTensor(MArgument marg) { return MArgument_getMTensor(marg); }
template<typename T>
inline void setTensor(MArgument marg, TensorRef<T> &val) { MArgument_setMTensor(marg, val.tensor()); }
template<typename T>
inline SparseArrayRef<T> getSparseArray(MArgument marg) { return MArgument_getMSparseArray(marg); }
template<typename T>
inline void setSparseArray(MArgument marg, SparseArrayRef<T> &val) { MArgument_setMSparseArray(marg, val.sparseArray()); }
template<typename T>
inline ImageRef<T> getImage(MArgument marg) { return MArgument_getMImage(marg); }
template<typename T>
inline Image3DRef<T> getImage3D(MArgument marg) { return MArgument_getMImage(marg); }
inline GenericImageRef getGenericImage(MArgument marg) { return MArgument_getMImage(marg); }
inline GenericImage3DRef getGenericImage3D(MArgument marg) { return MArgument_getMImage(marg); }
template<typename T>
inline void setImage(MArgument marg, ImageRef<T> &val) { MArgument_setMImage(marg, val.image()); }
template<typename T>
inline void setImage3D(MArgument marg, Image3DRef<T> &val) { MArgument_setMImage(marg, val.image()); }
inline void setGenericImage(MArgument marg, GenericImageRef &val) { MArgument_setMImage(marg, val.image()); }
inline void setGenericImage3D(MArgument marg, GenericImage3DRef &val) { MArgument_setMImage(marg, val.image()); }
#ifdef LTEMPLATE_RAWARRAY
template<typename T>
inline RawArrayRef<T> getRawArray(MArgument marg) { return MArgument_getMRawArray(marg); }
inline GenericRawArrayRef getGenericRawArray(MArgument marg) { return MArgument_getMRawArray(marg); }
template<typename T>
inline void setRawArray(MArgument marg, RawArrayRef<T> &val) { MArgument_setMRawArray(marg, val.rawArray()); }
inline void setGenericRawArray(MArgument marg, GenericRawArrayRef &val) { MArgument_setMRawArray(marg, val.rawArray()); }
#endif // LTEMPLATE_RAWARRAY
#ifdef LTEMPLATE_NUMERICARRAY
template<typename T>
inline NumericArrayRef<T> getNumericArray(MArgument marg) { return MArgument_getMNumericArray(marg); }
inline GenericNumericArrayRef getGenericNumericArray(MArgument marg) { return MArgument_getMNumericArray(marg); }
template<typename T>
inline void setNumericArray(MArgument marg, NumericArrayRef<T> &val) { MArgument_setMNumericArray(marg, val.numericArray()); }
inline void setGenericNumericArray(MArgument marg, GenericNumericArrayRef &val) { MArgument_setMNumericArray(marg, val.numericArray()); }
#endif // LTEMPLATE_NUMERICARRAY
inline complex_t getComplex(MArgument marg) {
mcomplex c = MArgument_getComplex(marg);
return complex_t(c.ri[0], c.ri[1]);
}
inline void setComplex(MArgument marg, complex_t val) {
mcomplex *c = reinterpret_cast<mcomplex *>(&val);
MArgument_setComplex(marg, *c);
}
inline const char *getString(MArgument marg) {
return const_cast<const char *>(MArgument_getUTF8String(marg));
}
inline void setString(MArgument marg, const char *val) {
MArgument_setUTF8String(marg, const_cast<char *>(val));
}
template<typename Collection>
inline IntTensorRef get_collection(const Collection &collection) {
IntTensorRef ids = makeVector<mint>(collection.size());
typename Collection::const_iterator i = collection.begin();
mint *j = ids.begin();
for (; i != collection.end(); ++i, ++j)
*j = i->first;
return ids;
}
template<typename T>
class getObject {
std::map<mint, T *> &collection;
public:
explicit getObject(std::map<mint, T *> &coll) : collection(coll) { }
T & operator () (MArgument marg) { return *(collection[MArgument_getInteger(marg)]); }
};
// Underlying stream buffer for mma::mout
class MBuffer : public std::streambuf {
std::vector<char_type> buf;
public:
explicit MBuffer(std::size_t buf_size = 4096) : buf(buf_size + 1) {
setp(&buf.front(), &buf.back());
}
protected:
int sync();
int_type overflow(int_type ch);
private:
MBuffer(const MBuffer &);
MBuffer & operator = (const MBuffer &);
};
// Used with RAII to ensure that mma::mout is flushed before the exit of any top-level function.
struct MOutFlushGuard {
~MOutFlushGuard() { mout.flush(); }
};
// Handles unknown exceptions in top-level functions.
inline void handleUnknownException(const char *what, const char *funname) {
std::ostringstream msg;
msg << "Unknown exception caught in "
<< funname
<< ". The library may be in an inconsistent state. It is recommended that you restart the kernel now to avoid instability.";
if (what)
msg << '\n' << what;
message(msg.str(), M_ERROR);
}
} // namespace detail
} // namespace mma
#endif // LTEMPLATE_HELPERS_H

View File

@ -0,0 +1,441 @@
/*
* Copyright (c) 2019 Szabolcs Horvát.
*
* See the file LICENSE.txt for copying permission.
*/
#ifndef MLSTREAM_H
#define MLSTREAM_H
/** \file mlstream.h
* \brief Auxiliary header for LTemplate to ease reading function arguments and returning values through MathLink.
*
* LTemplate itself does not depend on mlstream.h, so if you don't use this header,
* feel free to remove it from your project. mlstream.h is not meant as a general
* MathLink interface. It is specifically designed for handling arguments and return
* values in conjunction with LTemplate and `LinkObject`-based functions.
* To do this, mlstream functions are usually called in a specific sequence, as
* illustrated below.
*
* Example usage:
* \code
* void addMult(MLINK link) {
* mlStream ml(link, "addMult"); // any errors messages will mention the context "addMult"
*
* int i, j;
* ml >> mlCheckArgs(2) // read off the head List and check argument count
* >> i >> j; // read two integer arguments
*
* // compute the result
* int sum = i+j;
* int prod = i*j;
*
* // alias for MLNewPacket, must be used before returning the result
* ml.newPacket();
*
* // we return two results in a list
* ml << mlHead("List", 2)
* << sum << prod;
* }
* \endcode
*
* See `Documentation/Examples/LinkObject` for more examples.
*
* ----
*
* Currently, mlstream.h has direct support for sending and receiving the following types:
*
* **Sending**
*
* - Signed integers (16-, 32- and 64-bit)
* - Floating point numbers
* - Strings (`std::string` or null-terminated C string)
* - `mma::RealTensorRef` and `mma::IntTensorRef` of arbitrary dimensions
* - `std::vector` or `std::list` holding any supported type (with optimization for `std::vector` holding numerical types)
* - `std::pair` holding any two supported types
* - Symbols (mlSymbol) or functions (mlHead)
*
* **Receiving**
*
* - Signed integers (16-, 32- and 64-bit)
* - Floating point numbers
* - Strings (`std::string` only)
* - `std::vector` holding any supported type (with optimization for numerical types)
*/
#include "LTemplate.h"
#include <vector>
#include <list>
#include <utility>
#include <string>
#include <sstream>
#include <type_traits>
// Sanity checks for the sizes of MathLink integer types.
static_assert(sizeof(short) == 2, "MathLink type size mismatch: sizeof(short) != 2.");
static_assert(sizeof(int) == 4 , "MathLink type size mismatch: sizeof(int) != 4.");
static_assert(sizeof(mlint64) == 8, "MathLink type size mismatch: sizeof(mlint64) != 8.");
/** \brief Wrapper for `MLINK` to allow using extractors and inserters
*
* \param link is the MLINK object to wrap
* \param context is a string that will be prepended to any message reported using error()
*/
class mlStream {
MLINK lp;
std::string context;
public:
explicit mlStream(MLINK link) : lp(link) { }
mlStream(MLINK link, const std::string &context) : lp(link), context(context) { }
/// Retrieve the stored `MLINK`
MLINK link() { return lp; }
/// Throws a \ref mma::LibraryError with a given message.
[[ noreturn ]] void error(const std::string &err) {
std::ostringstream msg;
if (! context.empty())
msg << context << ": ";
msg << err << ".";
throw mma::LibraryError(msg.str());
}
/// Equivalent to `MLNewPacket()`
void newPacket() {
MLNewPacket(lp);
}
};
// Special
/// Must be the first item extracted from an mlStream, checks number of arguments and prepares for reading them.
struct mlCheckArgs {
int argc;
explicit mlCheckArgs(int argc) : argc(argc) { }
};
inline mlStream & operator >> (mlStream &ml, const mlCheckArgs &ca) {
int count;
if (! MLTestHead(ml.link(), "List", &count))
ml.error("argument check: head \"List\" expected");
if (count != ca.argc){
std::ostringstream msg;
msg << ca.argc << " argument" << (ca.argc == 1 ? "" : "s") << " expected, " << count << " received";
ml.error(msg.str());
}
return ml;
}
/** \brief Used for inserting a head with the given argument count into an mlStream.
*
* Typically used with the head `List` when returning multiple results.
*
* The following example returns the complex number `3 - 2I`.
*
* \code
* ml << mlHead("Complex", 2) << 3 << -2;
* \endcode
*/
struct mlHead {
const char *head;
int argc;
mlHead(const char *head, int argc) : head(head), argc(argc) { }
};
inline mlStream & operator << (mlStream &ml, const mlHead &head) {
if (! MLPutFunction(ml.link(), head.head, head.argc)) {
std::ostringstream msg;
msg << "Cannot put head " << head.head << " with " << head.argc << " arguments";
ml.error(msg.str());
}
return ml;
}
/** \brief Used for inserting a symbol into an mlStream
*
* The following example returns `True` or `False` based on a Boolean variable.
*
* \code
* mlStream ml(link);
* bool b;
* // ...
* ml.newPacket();
* ml << (b ? mlSymbol("True") : mlSymbol("False"));
* \endcode
*
* While this is convenient for a single result, Boolean arrays are much faster to transfer as integers.
*/
struct mlSymbol {
const char *symbol;
explicit mlSymbol(const char *symbol) : symbol(symbol) { }
};
inline mlStream & operator << (mlStream &ml, const mlSymbol &symbol) {
if (! MLPutSymbol(ml.link(), symbol.symbol)) {
std::ostringstream msg;
msg << "Cannot put symbol " << symbol.symbol;
ml.error(msg.str());
}
return ml;
}
/** \brief Used for discarding a given number of expressions from an mlStream
*
* The following example reads 3 arguments, but does not use the second one.
*
* \code
* mlStream ml(link);
* ml >> mlCheckArgs(3) >> x >> mlDiscard() >> y;
* \endcode
*/
struct mlDiscard {
const int count;
explicit mlDiscard(int count = 1) : count(count) { }
};
inline mlStream & operator >> (mlStream &ml, const mlDiscard &drop) {
for (int i=0; i < drop.count; ++i)
if (! MLTransferExpression(nullptr, ml.link()))
ml.error("Cannot discard expression");
return ml;
}
// Basic types (integer and floating point)
#define MLSTREAM_DEF_BASIC_GET_INTEGRAL(MTYPE, CTYPE) \
template<typename T, \
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value && sizeof(T) == sizeof(CTYPE), int>::type = 0 > \
inline mlStream & operator >> (mlStream &ml, T &x) { \
if (! MLGet ## MTYPE(ml.link(), reinterpret_cast<CTYPE *>(&x))) \
ml.error(#MTYPE " expected"); \
return ml; \
}
MLSTREAM_DEF_BASIC_GET_INTEGRAL(Integer16, short)
MLSTREAM_DEF_BASIC_GET_INTEGRAL(Integer32, int)
MLSTREAM_DEF_BASIC_GET_INTEGRAL(Integer64, mlint64)
#define MLSTREAM_DEF_BASIC_GET(MTYPE, CTYPE) \
inline mlStream & operator >> (mlStream &ml, CTYPE &x) { \
if (! MLGet ## MTYPE(ml.link(), &x)) \
ml.error(#MTYPE " expected"); \
return ml; \
}
MLSTREAM_DEF_BASIC_GET(Real32, float)
MLSTREAM_DEF_BASIC_GET(Real64, double)
MLSTREAM_DEF_BASIC_GET(Real128, mlextended_double)
#define MLSTREAM_DEF_BASIC_PUT_INTEGRAL(MTYPE, CTYPE) \
template<typename T, \
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value && sizeof(T) == sizeof(CTYPE), int>::type = 0 > \
inline mlStream & operator << (mlStream &ml, T x) { \
if (! MLPut ## MTYPE(ml.link(), static_cast<CTYPE>(x))) \
ml.error("Cannot return " #MTYPE); \
return ml; \
}
MLSTREAM_DEF_BASIC_PUT_INTEGRAL(Integer16, short)
MLSTREAM_DEF_BASIC_PUT_INTEGRAL(Integer32, int)
MLSTREAM_DEF_BASIC_PUT_INTEGRAL(Integer64, mlint64)
#define MLSTREAM_DEF_BASIC_PUT(MTYPE, CTYPE) \
inline mlStream & operator << (mlStream &ml, CTYPE x) { \
if (! MLPut ## MTYPE(ml.link(), x)) \
ml.error("Cannot return " #MTYPE); \
return ml; \
}
MLSTREAM_DEF_BASIC_PUT(Real32, float)
MLSTREAM_DEF_BASIC_PUT(Real64, double)
MLSTREAM_DEF_BASIC_PUT(Real128, mlextended_double)
// Strings
inline mlStream & operator >> (mlStream &ml, std::string &s) {
const unsigned char *sp;
int bytes, chars;
if (! MLGetUTF8String(ml.link(), &sp, &bytes, &chars))
ml.error("String expected");
s.assign(reinterpret_cast<const char *>(sp), bytes);
MLReleaseUTF8String(ml.link(), sp, bytes);
return ml;
}
inline mlStream & operator << (mlStream &ml, const std::string &s) {
if (! MLPutUTF8String(ml.link(), reinterpret_cast<const unsigned char *>(s.c_str()), s.size()))
ml.error("Cannot return UTF8 string");
return ml;
}
inline mlStream & operator << (mlStream &ml, const char *s) {
if (! MLPutString(ml.link(), s))
ml.error("Cannot return string");
return ml;
}
// TensorRef
inline mlStream & operator << (mlStream &ml, mma::IntTensorRef t) {
const int maxrank = 16;
const int rank = t.rank();
const mint *mdims = t.dimensions();
int dims[maxrank];
massert(rank <= maxrank);
std::copy(mdims, mdims + rank, dims);
#ifdef MINT_32
if (! MLPutInteger32Array(ml.link(), reinterpret_cast<int *>(t.data()), dims, NULL, rank))
ml.error("Cannot return Integer Tensor.");
#else
if (! MLPutInteger64Array(ml.link(), reinterpret_cast<mlint64 *>(t.data()), dims, nullptr, rank))
ml.error("Cannot return Integer Tensor.");
#endif
return ml;
}
inline mlStream & operator << (mlStream &ml, mma::RealTensorRef t) {
const int maxrank = 16;
const int rank = t.rank();
const mint *mdims = t.dimensions();
int dims[maxrank];
massert(rank <= maxrank);
std::copy(mdims, mdims + rank, dims);
if (! MLPutReal64Array(ml.link(), t.data(), dims, nullptr, rank))
ml.error("Cannot return Real Tensor");
return ml;
}
// TODO support complex tensors
// Standard containers -- list
template<typename T>
inline mlStream & operator << (mlStream &ml, const std::list<T> &ls) {
ml << mlHead("List", ls.size());
for (typename std::list<T>::const_iterator i = ls.begin(); i != ls.end(); ++i)
ml << *i;
return ml;
}
// Standard containers -- vector
// Put signed integer element types, 16, 32 and 64 bits.
#define MLSTREAM_DEF_VEC_PUT_INTEGRAL(MTYPE, CTYPE) \
template<typename T, \
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value && sizeof(T) == sizeof(CTYPE), int>::type = 0 > \
inline mlStream & operator << (mlStream &ml, const std::vector<T> &vec) { \
const CTYPE *data = vec.empty() ? nullptr : reinterpret_cast<const CTYPE *>(vec.data()); \
if (! MLPut ## MTYPE ## List(ml.link(), data, vec.size())) \
ml.error("Cannot return vector of " #MTYPE); \
return ml; \
}
MLSTREAM_DEF_VEC_PUT_INTEGRAL(Integer16, short)
MLSTREAM_DEF_VEC_PUT_INTEGRAL(Integer32, int)
MLSTREAM_DEF_VEC_PUT_INTEGRAL(Integer64, mlint64)
// Put floating point element types
#define MLSTREAM_DEF_VEC_PUT(MTYPE, CTYPE) \
inline mlStream & operator << (mlStream &ml, const std::vector<CTYPE> &vec) { \
const CTYPE *data = vec.empty() ? nullptr : vec.data(); \
if (! MLPut ## MTYPE ## List(ml.link(), data, vec.size())) \
ml.error("Cannot return vector of " #MTYPE); \
return ml; \
}
MLSTREAM_DEF_VEC_PUT(Real32, float)
MLSTREAM_DEF_VEC_PUT(Real64, double)
MLSTREAM_DEF_VEC_PUT(Real128, mlextended_double)
// Put all other types
template<typename T,
typename std::enable_if<! (std::is_integral<T>::value && std::is_signed<T>::value && (sizeof(T) == sizeof(short) || sizeof(T) == sizeof(int) || sizeof(T) == sizeof(mlint64)) ), int>::type = 0 >
inline mlStream & operator << (mlStream &ml, const std::vector<T> &vec) {
ml << mlHead("List", vec.size());
for (typename std::vector<T>::const_iterator i = vec.begin(); i != vec.end(); ++i)
ml << *i;
return ml;
}
// Get signed integer element types
#define MLSTREAM_DEF_VEC_GET_INTEGRAL(MTYPE, CTYPE) \
template<typename T, \
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value && sizeof(T) == sizeof(CTYPE), int>::type = 0> \
inline mlStream & operator >> (mlStream &ml, std::vector<T> &vec) { \
CTYPE *data; \
int count; \
if (! MLGet ## MTYPE ## List(ml.link(), &data, &count)) \
ml.error(#MTYPE " list expected"); \
vec.assign(data, data+count); \
MLRelease ## MTYPE ## List(ml.link(), data, count); \
return ml; \
}
MLSTREAM_DEF_VEC_GET_INTEGRAL(Integer16, short)
MLSTREAM_DEF_VEC_GET_INTEGRAL(Integer32, int)
MLSTREAM_DEF_VEC_GET_INTEGRAL(Integer64, mlint64)
// Get floating point element types
#define MLSTREAM_DEF_VEC_GET(MTYPE, CTYPE) \
inline mlStream & operator >> (mlStream &ml, std::vector<CTYPE> &vec) { \
CTYPE *data; \
int count; \
if (! MLGet ## MTYPE ## List(ml.link(), &data, &count)) \
ml.error(#MTYPE " list expected"); \
vec.assign(data, data+count); \
MLRelease ## MTYPE ## List(ml.link(), data, count); \
return ml; \
}
MLSTREAM_DEF_VEC_GET(Real32, float)
MLSTREAM_DEF_VEC_GET(Real64, double)
MLSTREAM_DEF_VEC_GET(Real128, mlextended_double)
// Get all other types
template<typename T,
typename std::enable_if<! (std::is_integral<T>::value && std::is_signed<T>::value && (sizeof(T) == sizeof(short) || sizeof(T) == sizeof(int) || sizeof(T) == sizeof(mlint64)) ), int>::type = 0 >
inline mlStream & operator >> (mlStream &ml, std::vector<T> &vec) {
int count;
if (! MLTestHead(ml.link(), "List", &count))
ml.error("Head \"List\" expected");
vec.clear();
vec.resize(count);
for (auto &el : vec)
ml >> el;
return ml;
}
// Put an std::pair
template<typename A, typename B>
inline mlStream & operator << (mlStream &ml, const std::pair<A,B> &pair) {
ml << mlHead("List", 2) << pair.first << pair.second;
return ml;
}
#endif // MLSTREAM_H

5
LTemplate/Kernel/init.m Normal file
View File

@ -0,0 +1,5 @@
(* ::Package:: *)
(* Mathematica Init File *)
Get["LTemplate`LTemplate`"]

21
LTemplate/LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2019 Szabolcs Horvát <szhorvat@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

34
LTemplate/LTemplate.m Normal file
View File

@ -0,0 +1,34 @@
(* Mathematica Package *)
(* Created by IntelliJ IDEA and http://wlplugin.halirutan.de/ *)
(* :Title: LTemplate *)
(* :Context: LTemplate` *)
(* :Author: szhorvat *)
(* :Date: 2015-08-03 *)
(* :Package Version: 0.6 *)
(* :Mathematica Version: 10.0 *)
(* :Copyright: (c) 2019 Szabolcs Horvat *)
(* :License: MIT license, see LICENSE.txt *)
(* :Keywords: LibraryLink, C++, Template, Code generation *)
(* :Discussion: This package simplifies writing LibraryLink code by auto-generating the boilerplate code. *)
BeginPackage["LTemplate`", {"SymbolicC`", "CCompilerDriver`"}]
Unprotect["LTemplate`*"];
`Private`$private = False;
Get["LTemplate`LTemplateInner`"]
ConfigureLTemplate[] (* use the default configuration *)
EndPackage[]
(* Note: Take care not to introduce any new symbols in this section as they would be created in Global` *)
SetAttributes[Evaluate@Names["LTemplate`*"], {Protected, ReadProtected}];
(* Add the class context to $ContextPath *)
If[Not@MemberQ[$ContextPath, LClassContext[]],
PrependTo[$ContextPath, LClassContext[]]
];

45
LTemplate/LTemplate.qbs Normal file
View File

@ -0,0 +1,45 @@
// This is a QBS project file to be used with the Qt Creator IDE
import qbs
Product {
Depends { name: "cpp" }
// Set the path to Mathematica's $InstallationDirectory here:
property string mmaInstallDir: "/Applications/Mathematica 12.0.app/Contents/"
cpp.cxxLanguageVersion: "c++11"
cpp.includePaths: base.concat([
mmaInstallDir + "SystemFiles/IncludeFiles/C/",
mmaInstallDir + "SystemFiles/Links/MathLink/DeveloperKit/MacOSX-x86-64/CompilerAdditions",
"IncludeFiles/",
// The following are the locations of various libraries used by the example code,
// such as boost, CGAL, etc.
"/opt/local/include",
])
cpp.defines: base.concat([
'LTEMPLATE_MESSAGE_SYMBOL="LTemplate`LTemplate"',
"LTEMPLATE_MMA_VERSION=1200",
])
FileTagger {
patterns: "*.inc"
fileTags: ["cpp"]
}
files: [
"IncludeFiles/*.h",
"IncludeFiles/*.inc",
]
Group {
name: "Examples"
prefix: "Documentation/Examples/"
files: ["*/*.h", "*/*.cpp"]
}
}

874
LTemplate/LTemplateInner.m Normal file
View File

@ -0,0 +1,874 @@
(* Mathematica Package *)
(* :Copyright: (c) 2019 Szabolcs Horvat *)
(* :License: MIT license, see LICENSE.txt *)
(* This file is read directly with Get in LTemplate.m or LTemplatePrivate.m *)
LTemplate::usage = "LTemplate[name, {LClass[\[Ellipsis]], LClass[\[Ellipsis]], \[Ellipsis]}] represents a library template.";
LClass::usage = "LClass[name, {fun1, fun2, \[Ellipsis]}] represents a class within a template.";
LFun::usage =
"LFun[name, {arg1, arg2, \[Ellipsis]}, ret] represents a class member function with the given name, argument types and return type.\n" <>
"LFun[name, LinkObject, LinkObject] represents a function that uses MathLink/WSTP based passing. The shorthand LFun[name, LinkObject] can also be used.";
LType::usage =
"LType[head] represents an array-like library type corresponding to head.\n" <>
"LType[head, etype] represents an array-like library type corresponding to head, with element type etype.\n" <>
"LType[head, etype, d] represents an array-like library type corresponding to head, with element type etype and depth/rank d.";
TranslateTemplate::usage = "TranslateTemplate[template] translates the template into C++ code.";
LoadTemplate::usage = "LoadTemplate[template] loads the library defined by the template. The library must already be compiled.";
UnloadTemplate::usage = "UnloadTemplate[template] attempts to unload the library defined by the template.";
CompileTemplate::usage =
"CompileTemplate[template] compiles the library defined by the template. Required source files must be present in the current directory.\n" <>
"CompileTemplate[template, {file1, \[Ellipsis]}] includes additional source files in the compilation.";
FormatTemplate::usage = "FormatTemplate[template] formats the template in an easy to read way.";
NormalizeTemplate::usage = "NormalizeTemplate[template] brings the template and the type specifications within to the canonical form used internally by other LTemplate functions.";
ValidTemplateQ::usage = "ValidTemplateQ[template] returns True if the template syntax is valid.";
Make::usage = "Make[class] creates an instance of class.";
LExpressionList::usage = "LExpressionList[class] returns all existing instances of class.";
LClassContext::usage = "LClassContext[] returns the context where class symbols are created.";
LExpressionID::usage = "LExpressionID[name] represents the data type corresponding to LClass[name, \[Ellipsis]] in templates.";
ConfigureLTemplate::usage = "ConfigureLTemplate[options] must be called after loading the LTemplate package privately.";
Begin["`Private`"] (* Begin Private Context *)
(* Private for now, use LFun[name, LinkObject, LinkObject] instead. *)
LOFun::usage =
"LOFun[name] represents a class member function that uses LinkObject for passing and returning arguments. " <>
"It is equivalent to LFun[name, LinkObject, LinkObject].";
(* Mathematica version checks *)
packageAbort[] := (End[]; EndPackage[]; Abort[]) (* Avoid polluting the context path when aborting early. *)
minVersion = {10.0, 0}; (* oldest supported Mathematica version *)
maxVersion = {12.1, 1}; (* latest Mathematica version the package was tested with *)
version = {$VersionNumber, $ReleaseNumber}
versionString[{major_, release_}] := StringJoin[ToString /@ {NumberForm[major, {Infinity, 1}], ".", release}]
If[Not@OrderedQ[{minVersion, version}],
Print["LTemplate requires at least Mathematica version " <> versionString[minVersion] <> ". Aborting."];
packageAbort[];
]
(* We need to rely on implementation details of SymbolicC, so warn users of yet untested new Mathematica versions. *)
If[Not@OrderedQ[{version, maxVersion}] && Not[$private],
Print[
StringTemplate[
"WARNING: LTemplate has not yet been tested with Mathematica ``.\n" <>
"The latest supported Mathematica version is ``.\n" <>
"Please report any issues you find to szhorvat at gmail.com."
][versionString[version], versionString[maxVersion]]
]
]
(*************** Package configuration ****************)
(* Set up package global variables *)
$packageDirectory = DirectoryName[$InputFileName];
$includeDirectory = FileNameJoin[{$packageDirectory, "IncludeFiles"}];
(* The following symbols are set by ConfigureLTemplate[] *)
$messageSymbol := warnConfig
$lazyLoading := warnConfig
(* Show error and abort when ConfigureLTemplate[] was not called. *)
warnConfig := (Print["FATAL ERROR: Must call ConfigureLTemplate[] when embedding LTemplate into another package. Aborting ..."]; Abort[])
ByteArray[{0}]; (* "Prime" ByteArray to work around 10.4 bug where returning ByteArrays works only after they have been used once *)
LibraryFunction::noinst = "Managed library expression instance does not exist.";
LTemplate::nofun = "Function `` does not exist.";
Options[ConfigureLTemplate] = { "MessageSymbol" -> LTemplate, "LazyLoading" -> False };
ConfigureLTemplate[opt : OptionsPattern[]] :=
With[{sym = OptionValue["MessageSymbol"]},
$messageSymbol = sym;
sym::info = "``";
sym::warning = "``";
sym::error = "``";
sym::assert = "Assertion failed: ``.";
$lazyLoading = OptionValue["LazyLoading"];
]
LClassContext[] = Context[LTemplate] <> "Classes`";
(***************** SymbolicC extensions *******************)
CDeclareAssign::usage = "CDeclareAssign[type, var, value] represents 'type var = value;'.";
SymbolicC`Private`IsCExpression[ _CDeclareAssign ] := True
GenerateCode[CDeclareAssign[typeArg_, idArg_, rhs_], opts : OptionsPattern[]] :=
Module[{type, id},
type = Flatten[{typeArg}];
id = Flatten[{idArg}];
type = Riffle[ Map[ GenerateCode[#, opts] &, type], " "];
id = Riffle[ Map[ GenerateCode[#, opts] &, id], ", "];
GenerateCode[CAssign[type <> " " <> id, rhs], opts]
]
CInlineCode::usage = "CInlineCode[\"some code\"] will prevent semicolons from being added at the end of \"some code\" when used in a list.";
GenerateCode[CInlineCode[arg_], opts : OptionsPattern[]] := GenerateCode[arg, opts]
CTryCatch::usage = "CTryCatch[tryCode, catchArg, catchCode] represents 'try { tryCode } catch (catchArg) { catchCode }'.";
GenerateCode[CTryCatch[try_, arg_, catch_], opts : OptionsPattern[]] :=
GenerateCode[CTry[try], opts] <> "\n" <> GenerateCode[CCatch[arg, catch], opts]
CTry::usage = "CTry[tryCode] represents the fragment 'try { tryCode }'. Use CTryCatch instead.";
GenerateCode[CTry[try_], opts : OptionsPattern[]] :=
"try\n" <> GenerateCode[CBlock[try], opts]
CCatch::usage = "CCatch[catchArg, catchCode] represents the fragment 'catch (catchArg) { catchCode }'. Use CTryCatch instead.";
GenerateCode[CCatch[arg_, catch_], opts : OptionsPattern[]] :=
"catch (" <> SymbolicC`Private`formatArgument[arg, opts] <> ")\n" <>
GenerateCode[CBlock[catch], opts]
(****************** Generic template processing ****************)
numericTypePattern = Integer|Real|Complex;
rawTypePattern = "Integer8"|"UnsignedInteger8"|"Integer16"|"UnsignedInteger16"|"Integer32"|"UnsignedInteger32"|
"Integer64"|"UnsignedInteger64"|"Real32"|"Real64"|"Complex64"|"Complex128";
imageTypePattern = "Bit"|"Byte"|"Bit16"|"Real32"|"Real";
passingMethodPattern = PatternSequence[]|"Shared"|"Manual"|"Constant"|Automatic;
depthPattern = _Integer?Positive | Verbatim[_];
depthNullPattern = PatternSequence[] | depthPattern; (* like depthPattern, but allow empty value*)
arrayPattern = LType[List, numericTypePattern, depthNullPattern]; (* disallow MTensor without explicit element type specification *)
sparseArrayPattern = LType[SparseArray, numericTypePattern, depthNullPattern]; (* disallow SparseArray without explicit element type specification *)
rawArrayPattern = LType[RawArray, rawTypePattern] | LType[RawArray];
numericArrayPattern = LType[NumericArray, rawTypePattern] | LType[NumericArray]
byteArrayPattern = LType[ByteArray];
imagePattern = LType[Image|Image3D, imageTypePattern] | LType[Image|Image3D];
(*
Normalizing a template will:
- Wrap a bare LClass with LTemplate. This way a bare LClass can be used as a shorter notation for a single-class template.
- Convert type names to a canonical form
- Convert LFun[name, LinkObject, LinkObject] to LOFun[name]
*)
normalizeTypesRules = Dispatch@{
(* convert pattern-like type specifications to type names *)
Verbatim[_Integer] -> Integer,
Verbatim[_Real] -> Real,
Verbatim[_Complex] -> Complex,
Verbatim[True|False] -> "Boolean",
Verbatim[False|True] -> "Boolean",
(* convert string heads to symbols *)
(* must only be used on type lists as an LTemplate expression may contain other strings *)
head : "List"|"SparseArray"|"Image"|"Image3D"|"RawArray"|"NumericArray"|"ByteArray" :> Symbol[head],
(* convert LibraryDataType to the more general LType *)
LibraryDataType[args__] :> LType[args]
};
(* These heads are allowed to appear on their own, without being wrapped in LType/LibraryDataType.
This is for consistency with plain LibraryLink. *)
nakedHeads = ByteArray|RawArray|NumericArray|Image|Image3D;
wrapNakedHeadsRules = Dispatch@{
expr : LType[___] :> expr, (* do not wrap if already wrapped *)
type : nakedHeads :> LType[type]
};
elemTypeAliases = Dispatch@{
LType[h: RawArray|NumericArray, "Byte"] :> LType[h, "UnsignedInteger8"],
LType[h: RawArray|NumericArray, "Bit16"] :> LType[h, "UnsignedInteger16"],
(* omit "Integer" because the naming is confusing and people may assume it's "Integer64" *)
(* LType[h: RawArray|NumericArray, "Integer"] :> LType[h, "Integer32"], *)
LType[h: RawArray|NumericArray, "Float"] :> LType[h, "Real32"],
LType[h: RawArray|NumericArray, "Double"] :> LType[h, "Real64"],
LType[h: RawArray|NumericArray, "Real"] :> LType[h, "Real64"],
LType[h: RawArray|NumericArray, "Complex"] :> LType[h, "Complex128"],
LType[h : Image|Image3D, "UnsignedInteger8"] :> LType[h, "Byte"],
LType[h : Image|Image3D, "UnsignedInteger16"] :> LType[h, "Bit16"],
LType[h : Image|Image3D, "Float"] :> LType[h, "Real32"],
LType[h : Image|Image3D, "Double"] :> LType[h, "Real"],
LType[h : Image|Image3D, "Real64"] :> LType[h, "Real"]
};
normalizeFunsRules = Dispatch@{
LFun[name_, LinkObject] :> LOFun[name],
LFun[name_, LinkObject, LinkObject] :> LOFun[name],
LFun[name_, args_List, ret_] :> LFun[name, normalizeTypes[args, 1], normalizeTypes[ret]]
};
(* These rules must only be applied to entire type specifications, not their parts. Use Replace, not ReplaceAll. *)
typeRules = Dispatch@{
(* allowed forms of tensor specifications include {type}, {type, depth}, {type, depth, passing}, but NOT {type, passing} *)
{type : numericTypePattern, depth : depthPattern, pass : passingMethodPattern} :> {LType[List, type, depth], pass},
{type : numericTypePattern, pass : passingMethodPattern} :> {LType[List, type], pass},
type : LType[__] :> {type}
};
normalizeTypes[types_, level_ : 0] := Replace[types /. normalizeTypesRules /. wrapNakedHeadsRules /. elemTypeAliases, typeRules, {level}]
NormalizeTemplate[c : LClass[name_, funs_]] := NormalizeTemplate[LTemplate[name, {c}]]
NormalizeTemplate[t : LTemplate[name_, classes_]] := t /. normalizeFunsRules
NormalizeTemplate[t_] := t
ValidTemplateQ::template = "`` is not a valid template. Templates must follow the syntax LTemplate[name, {class1, class2, \[Ellipsis]}].";
ValidTemplateQ::class = "In ``: `` is not a valid class. Classes must follow the syntax LClass[name, {fun1, fun2, \[Ellipsis]}].";
ValidTemplateQ::fun = "In ``: `` is not a valid function. Functions must follow the syntax LFun[name, {arg1, arg2, \[Ellipsis]}, ret].";
ValidTemplateQ::string = "In ``: String expected instead of ``";
ValidTemplateQ::name = "In ``: `` is not a valid name. Names must start with a letter and may only contain letters and digits.";
ValidTemplateQ::type = "In ``: `` is not a valid type.";
ValidTemplateQ::rettype = "In ``: `` is not a valid return type.";
ValidTemplateQ::dupclass = "In ``: Class `` appears more than once.";
ValidTemplateQ::dupfun = "In ``: Function `` appears more than once.";
ValidTemplateQ[tem_] := validateTemplate@NormalizeTemplate[tem]
validateTemplate[tem_] := (Message[ValidTemplateQ::template, tem]; False)
validateTemplate[LTemplate[name_String, classes_List]] :=
Block[{classlist = {}, location = "template"},
validateName[name] && (And @@ validateClass /@ classes)
]
(* must be called within validateTemplate, uses location, classlist *)
validateClass[class_] := (Message[ValidTemplateQ::class, location, class]; False)
validateClass[LClass[name_, funs_List]] :=
Block[{funlist = {}, inclass, nameValid},
nameValid = validateName[name];
If[MemberQ[classlist, name], Message[ValidTemplateQ::dupclass, location, name]; Return[False]];
AppendTo[classlist, name];
inclass = name;
Block[{location = StringTemplate["class ``"][inclass]},
nameValid && (And @@ validateFun /@ funs)
]
]
(* must be called within validateClass, uses location, funlist *)
validateFun[fun_] := (Message[ValidTemplateQ::fun, location, fun]; False)
validateFun[LFun[name_, args_List, ret_]] :=
Block[{nameValid},
nameValid = validateName[name];
If[MemberQ[funlist, name], Message[ValidTemplateQ::dupfun, location, name]; Return[False]];
AppendTo[funlist, name];
Block[{location = StringTemplate["class ``, function ``"][inclass, name]},
nameValid && (And @@ validateType /@ args) && validateReturnType[ret]
]
]
validateFun[LOFun[name_]] :=
Block[{nameValid},
nameValid = validateName[name];
If[MemberQ[funlist, name], Message[ValidTemplateQ::dupfun, location, name]; Return[False]];
AppendTo[funlist, name];
nameValid
]
(* must be called within validateTemplate, uses location *)
validateType[numericTypePattern|"Boolean"|"UTF8String"|LExpressionID[_String]] := True
validateType[{arrayPattern|sparseArrayPattern|rawArrayPattern|numericArrayPattern|byteArrayPattern|imagePattern, passingMethodPattern}] := True
validateType[type_] := (Message[ValidTemplateQ::type, location, type]; False)
(* must be called within validateTemplate, uses location *)
(* Only "Shared" and Automatic passing allowed in return types. LExpressionID is forbidden. *)
validateReturnType["Void"] := True
validateReturnType[type : LExpressionID[___] | {___, "Manual"|"Constant"}] := (Message[ValidTemplateQ::rettype, location, type]; False)
validateReturnType[type_] := validateType[type]
(* must be called within validateTemplate, uses location *)
validateName[name_] := (Message[ValidTemplateQ::string, location, name]; False)
validateName[name_String] :=
If[StringMatchQ[name, RegularExpression["[a-zA-Z][a-zA-Z0-9]*"]],
True,
Message[ValidTemplateQ::name, location, name]; False
]
(*********** Translate template to library code **********)
TranslateTemplate[tem_] :=
With[{t = NormalizeTemplate[tem]},
If[validateTemplate[t],
ToCCodeString[transTemplate[t], "Indent" -> 1],
$Failed
]
]
libFunArgs = {{"WolframLibraryData", "libData"}, {"mint", "Argc"}, {"MArgument *", "Args"}, {"MArgument", "Res"}};
linkFunArgs = {{"WolframLibraryData", "libData"}, {"MLINK", "mlp"}};
libFunRet = "extern \"C\" DLLEXPORT int";
excType = "const mma::LibraryError &";
excName = "libErr";
varPrefix = "var";
var[k_] := varPrefix <> IntegerString[k]
includeName[classname_String] := classname <> ".h"
collectionName[classname_String] := classname <> "_collection"
collectionType[classname_String] := "std::map<mint, " <> classname <> " *>"
managerName[classname_String] := classname <> "_manager_fun"
fullyQualifiedSymbolName[sym_Symbol] := Context[sym] <> SymbolName[sym]
setupCollection[classname_String] := {
CDeclare[collectionType[classname], collectionName[classname]],
"",
CInlineCode["namespace mma"], (* workaround for gcc bug, "specialization of template in different namespace" *)
CBlock@CFunction["template<> const " <> collectionType[classname] <> " &", "getCollection<" <> classname <> ">", {},
CReturn[collectionName[classname]]
],
"",
CFunction["DLLEXPORT void", managerName[classname], {"WolframLibraryData libData", "mbool mode", "mint id"},
CInlineCode@StringTemplate[ (* TODO: Check if id exists, use assert *)
"\
if (mode == 0) { // create
`collection`[id] = new `class`();
} else { // destroy
if (`collection`.find(id) == `collection`.end()) {
libData->Message(\"noinst\");
return;
}
delete `collection`[id];
`collection`.erase(id);
}\
"][<|"collection" -> collectionName[classname], "class" -> classname|>]
],
"",
CFunction[libFunRet, classname <> "_get_collection", libFunArgs,
{
(* Attention: make sure stuff called here won't throw LibraryError *)
transRet[
{LType[List, Integer, 1]},
CCall["mma::detail::get_collection", collectionName[classname]]
],
CReturn["LIBRARY_NO_ERROR"]
}
],
"",""
}
registerClassManager[classname_String] :=
CBlock[{
"int err",
StringTemplate[
"err = (*libData->registerLibraryExpressionManager)(\"`class`\", `manager`)"
][<|"class" -> classname, "manager" -> managerName[classname]|>],
"if (err != LIBRARY_NO_ERROR) return err"
}]
unregisterClassManager[classname_String] :=
StringTemplate["(*libData->unregisterLibraryExpressionManager)(\"``\")"][classname]
transTemplate[LTemplate[libname_String, classes_]] :=
Block[{classlist = {}, classTranslations},
classTranslations = transClass /@ classes;
{
CComment["This file was automatically generated by LTemplate. DO NOT EDIT.", {"", "\n"}],
CComment["https://github.com/szhorvat/LTemplate", {"", "\n"}],
"",
CDefine["LTEMPLATE_MMA_VERSION", ToString@Round[100 $VersionNumber + $ReleaseNumber]],
"",
CInclude["LTemplate.h"],
CInclude["LTemplateHelpers.h"],
CInclude /@ includeName /@ classlist,
"","",
CDefine["LTEMPLATE_MESSAGE_SYMBOL", CString[fullyQualifiedSymbolName[$messageSymbol]]],
"",
CInclude["LTemplate.inc"],
"","",
setupCollection /@ classlist,
CFunction["extern \"C\" DLLEXPORT mint",
"WolframLibrary_getVersion", {},
"return WolframLibraryVersion"
],
"",
CFunction["extern \"C\" DLLEXPORT int",
"WolframLibrary_initialize", {"WolframLibraryData libData"},
{
CAssign["mma::libData", "libData"],
registerClassManager /@ classlist,
"return LIBRARY_NO_ERROR"
}
],
"",
CFunction["extern \"C\" DLLEXPORT void",
"WolframLibrary_uninitialize", {"WolframLibraryData libData"},
{
unregisterClassManager /@ classlist,
"return"
}
],
"","",
classTranslations
}
]
(* must be called within transTemplate *)
transClass[LClass[classname_String, funs_]] :=
Block[{},
AppendTo[classlist, classname];
transFun[classname] /@ funs
]
funName[classname_][name_] := classname <> "_" <> name
catchExceptions[classname_, funname_] :=
Module[{membername = "\"" <> classname <> "::" <> funname <> "()\""},
{
CCatch[{excType, excName},
{
CMember[excName, "report()"],
CReturn[CMember[excName, "error_code()"]]
}
]
,
CCatch[
{"const std::exception &", "exc"},
{
CCall["mma::detail::handleUnknownException", {"exc.what()", membername}],
CReturn["LIBRARY_FUNCTION_ERROR"]
}
]
,
CCatch["...",
{
CCall["mma::detail::handleUnknownException", {"NULL", membername}],
CReturn["LIBRARY_FUNCTION_ERROR"]
}
]
}
]
transFun[classname_][LFun[name_String, args_List, ret_]] :=
Block[{index = 0},
{
CFunction[libFunRet, funName[classname][name], libFunArgs,
{
CDeclare["mma::detail::MOutFlushGuard", "flushguard"],
(* TODO: check Argc is correct, use assert *)
"const mint id = MArgument_getInteger(Args[0])",
CInlineCode@StringTemplate[
"if (`1`.find(id) == `1`.end()) { libData->Message(\"noinst\"); return LIBRARY_FUNCTION_ERROR; }"
][collectionName[classname]],
"",
CTry[
(* try *) {
transArg /@ args,
"",
transRet[
ret,
CPointerMember[CArray[collectionName[classname], "id"], CCall[name, var /@ Range@Length[args]]]
]
}],
(* catch *)
catchExceptions[classname, name],
"",
CReturn["LIBRARY_NO_ERROR"]
}
],
"", ""
}
]
transFun[classname_][LOFun[name_String]] :=
{
CFunction[libFunRet, funName[classname][name], linkFunArgs,
{
CDeclare["mma::detail::MOutFlushGuard", "flushguard"],
CTry[
(* try *) {
CInlineCode@StringTemplate[
"
int id;
int args = 2;
if (! MLTestHeadWithArgCount(mlp, \"List\", &args))
return LIBRARY_FUNCTION_ERROR;
if (! MLGetInteger(mlp, &id))
return LIBRARY_FUNCTION_ERROR;
if (`collection`.find(id) == `collection`.end()) {
libData->Message(\"noinst\");
return LIBRARY_FUNCTION_ERROR;
}
`collection`[id]->`funname`(mlp);
"
][<| "collection" -> collectionName[classname], "funname" -> name |>]
}
],
(* catch *)
catchExceptions[classname, name],
"",
CReturn["LIBRARY_NO_ERROR"]
}
]
}
transArg[type_] :=
Module[{name, cpptype, getfun, setfun},
index++;
name = var[index];
{cpptype, getfun, setfun} = Replace[type, types];
{
CDeclareAssign[cpptype, name, StringTemplate["`1`(Args[`2`])"][getfun, index]]
}
]
transRet[type_, value_] :=
Module[{name = "res", cpptype, getfun, setfun},
{cpptype, getfun, setfun} = Replace[type, types];
{
CDeclareAssign[cpptype, name, value],
CCall[setfun, {"Res", name}]
}
]
transRet["Void", value_] := value
numericTypes = <|
Integer -> "mint",
Real -> "double",
Complex -> "mma::complex_t"
|>;
rawTypes = <|
"Integer8" -> "int8_t",
"UnsignedInteger8" -> "uint8_t",
"Integer16" -> "int16_t",
"UnsignedInteger16" -> "uint16_t",
"Integer32" -> "int32_t",
"UnsignedInteger32" -> "uint32_t",
"Integer64" -> "int64_t",
"UnsignedInteger64" -> "uint64_t",
"Real32" -> "float",
"Real64" -> "double",
"Complex32" -> "mma::complex_float_t",
"Complex64" -> "mma::complex_double_t"
|>;
imageTypes = <|
"Bit" -> "mma::im_bit_t",
"Byte" -> "mma::im_byte_t",
"Bit16" -> "mma::im_bit16_t",
"Real32" -> "mma::im_real32_t",
"Real" -> "mma::im_real_t"
|>;
types = Dispatch@{
Integer -> {"mint", "MArgument_getInteger", "MArgument_setInteger"},
Real -> {"double", "MArgument_getReal", "MArgument_setReal"},
Complex -> {"std::complex<double>", "mma::detail::getComplex", "mma::detail::setComplex"},
"Boolean" -> {"bool", "MArgument_getBoolean", "MArgument_setBoolean"},
"UTF8String" -> {"const char *", "mma::detail::getString", "mma::detail::setString"},
{LType[List, type_, ___], ___} :>
With[{ctype = numericTypes[type]},
{"mma::TensorRef<" <> ctype <> ">", "mma::detail::getTensor<" <> ctype <> ">", "mma::detail::setTensor<" <> ctype <> ">"}
],
{LType[SparseArray, type_, ___], ___} :>
With[{ctype = numericTypes[type]},
{"mma::SparseArrayRef<" <> ctype <> ">", "mma::detail::getSparseArray<" <> ctype <> ">", "mma::detail::setSparseArray<" <> ctype <> ">"}
],
{LType[RawArray, type_], ___} :>
With[
{ctype = rawTypes[type]},
{"mma::RawArrayRef<" <> ctype <> ">", "mma::detail::getRawArray<" <> ctype <> ">", "mma::detail::setRawArray<" <> ctype <> ">"}
],
{LType[RawArray], ___} -> {"mma::GenericRawArrayRef", "mma::detail::getGenericRawArray", "mma::detail::setGenericRawArray"},
{LType[NumericArray, type_], ___} :>
With[
{ctype = rawTypes[type]},
{"mma::NumericArrayRef<" <> ctype <> ">", "mma::detail::getNumericArray<" <> ctype <> ">", "mma::detail::setNumericArray<" <> ctype <> ">"}
],
{LType[NumericArray], ___} -> {"mma::GenericNumericArrayRef", "mma::detail::getGenericNumericArray", "mma::detail::setGenericNumericArray"},
(* Starting with LTemplate 0.6, ByteArray is mapped to NumericArrayRef instead of RawArrayRef *)
(* {LType[ByteArray], ___} -> {"mma::RawArrayRef<uint8_t>", "mma::detail::getRawArray<uint8_t>", "mma::detail::setRawArray<uint8_t>"}, *)
{LType[ByteArray], ___} -> {"mma::NumericArrayRef<uint8_t>", "mma::detail::getNumericArray<uint8_t>", "mma::detail::setNumericArray<uint8_t>"},
{LType[Image, type_], ___} :>
With[
{ctype = imageTypes[type]},
{"mma::ImageRef<" <> ctype <> ">", "mma::detail::getImage<" <> ctype <> ">", "mma::detail::setImage<" <> ctype <> ">"}
],
{LType[Image], ___} -> {"mma::GenericImageRef", "mma::detail::getGenericImage", "mma::detail::setGenericImage"},
{LType[Image3D, type_], ___} :>
With[
{ctype = imageTypes[type]},
{"mma::Image3DRef<" <> ctype <> ">", "mma::detail::getImage3D<" <> ctype <> ">", "mma::detail::setImage3D<" <> ctype <> ">"}
],
{LType[Image3D], ___} -> {"mma::GenericImage3DRef", "mma::detail::getGenericImage3D", "mma::detail::setGenericImage3D"},
(* This is a special type that translates integer managed expression IDs on the Mathematica side
into a class reference on the C++ side. It cannot be returned. *)
LExpressionID[classname_String] :> {classname <> " &", "mma::detail::getObject<" <> classname <> ">(" <> collectionName[classname] <> ")", ""}
};
(**************** Load library ***************)
(* TODO: Break out loading and compilation into separate files
This is to make it easy to include them in other projects *)
getCollection (* underlies LExpressionList, the get_collection library function is associated with it in loadClass *)
symName[classname_String] := LClassContext[] <> classname
LoadTemplate[tem_] :=
With[{t = NormalizeTemplate[tem]},
If[validateTemplate[t],
Check[loadTemplate[t], $Failed],
$Failed
]
]
(* We use FindLibrary for two reasons:
1. If the library is not found, we want to fail early with LibraryFunction::notfound
2. It is important to pass the full library path to LibraryFunctionLoad[]. If only a simple name is passed,
it will use FindLibrary[] to find the appropriate file. FindLibrary[] is several orders of magnitude slower than just
loading a function from a shared library. In fact, with this optimization, lazy loading might be pointless, as with
full library paths, LibraryFunctionLoad[] is faster than other operations done during template loading.
*)
loadTemplate[tem : LTemplate[libname_String, classes_]] :=
With[{lib = FindLibrary[libname]},
Quiet@unloadTemplate[tem];
If[lib =!= $Failed,
loadClass[lib] /@ classes,
Message[LibraryFunction::notfound, libname]
];
]
loadClass[libname_][tem : LClass[classname_String, funs_]] := (
ClearAll[#]& @ symName[classname];
loadFun[libname, classname] /@ funs;
With[{sym = Symbol@symName[classname]},
MessageName[sym, "usage"] = formatTemplate[tem];
sym[id_Integer][(f_String)[___]] /; (Message[LTemplate::nofun, StringTemplate["``::``"][sym, f]]; False) := $Failed;
getCollection[sym] = LibraryFunctionLoad[libname, funName[classname]["get_collection"], {}, LibraryDataType[List, Integer, 1]];
];
)
loadFun[libname_, classname_][LFun[name_String, args_List, ret_]] :=
With[{classsym = Symbol@symName[classname], funname = funName[classname][name],
loadargs = Prepend[Replace[args, loadingTypes, {1}], Integer],
loadret = Replace[ret, loadingTypes]
},
If[$lazyLoading,
classsym[idx_Integer]@name[argumentsx___] :=
With[{lfun = LibraryFunctionLoad[libname, funname, loadargs, loadret]},
classsym[id_Integer]@name[arguments___] := lfun[id, arguments];
classsym[idx]@name[argumentsx]
]
,
With[{lfun = LibraryFunctionLoad[libname, funname, loadargs, loadret]},
classsym[id_Integer]@name[arguments___] := lfun[id, arguments];
]
]
];
loadFun[libname_, classname_][LOFun[name_String]] :=
With[{classsym = Symbol@symName[classname], funname = funName[classname][name]},
If[$lazyLoading,
classsym[idx_Integer]@name[argumentsx___] :=
With[{lfun = LibraryFunctionLoad[libname, funname, LinkObject, LinkObject]},
classsym[id_Integer]@name[arguments___] := lfun[id, {arguments}];
classsym[idx]@name[argumentsx]
]
,
With[{lfun = LibraryFunctionLoad[libname, funname, LinkObject, LinkObject]},
classsym[id_Integer]@name[arguments___] := lfun[id, {arguments}];
]
]
]
(* For types that need to be translated to LibraryFunctionLoad compatible forms before loading. *)
loadingTypes = Dispatch@{
LExpressionID[_] -> Integer,
{LType[h: RawArray|NumericArray, ___], passing___} :> {h, passing},
{LType[args__], passing___} :> {LibraryDataType[args], passing}
};
UnloadTemplate[tem_] :=
With[{t = NormalizeTemplate[tem]},
If[validateTemplate[t],
unloadTemplate[t],
$Failed
]
]
unloadTemplate[LTemplate[libname_String, classes_]] :=
Module[{res},
res = LibraryUnload[libname];
With[{syms = Symbol /@ symName /@ Cases[classes, LClass[name_, __] :> name]},
ClearAll /@ syms;
Quiet@Unset[getCollection[#]]& /@ syms;
];
res
]
(* TODO: verify class exists for Make and LExpressionList *)
Make[class_Symbol] := Make@SymbolName[class] (* SymbolName returns the name of the symbol without a context *)
Make[classname_String] := CreateManagedLibraryExpression[classname, Symbol@symName[classname]]
LExpressionList[class_Symbol] := class /@ getCollection[class][]
LExpressionList[classname_String] := LExpressionList@Symbol@symName[classname]
(********************* Compile template ********************)
CompileTemplate::comp = "The compiler specification `` is invalid. It must be a symbol.";
If[TrueQ[$noCompile],
(* If CCompilerDriver has not been loaded: *)
CompileTemplate::disabled = "Template compilation is disabled.";
CompileTemplate[___] := (Message[CompileTemplate::disabled]; $Failed);
,
(* If CCompilerDriver is available: *)
CompileTemplate[tem_, sources_List, opt : OptionsPattern[CreateLibrary]] :=
With[{t = NormalizeTemplate[tem]},
If[validateTemplate[t],
compileTemplate[t, sources, opt],
$Failed
]
];
CompileTemplate[tem_, opt : OptionsPattern[CreateLibrary]] := CompileTemplate[tem, {}, opt];
]
compileTemplate[tem: LTemplate[libname_String, classes_], sources_, opt : OptionsPattern[CreateLibrary]] :=
Catch[
Module[{sourcefile, code, includeDirs, classlist, print, driver},
print[args__] := Apply[Print, Style[#, Darker@Blue]& /@ {args}];
(* Determine the compiler driver that will be used. *)
(* It is unclear if the "Compiler" option of CreateLibrary supports option lists as a compiler specification
like $CCompiler does. Trying to use one frequently leads to errors as of M11.2. This may or may not be a bug.
For now we forbid anything but symbol compiler specifications, such as CCompilerDriver`ClangCompiler`ClangCompiler *)
driver = OptionValue["Compiler"];
If[driver === Automatic, driver = DefaultCCompiler[]];
If[driver === $Failed, Throw[$Failed, compileTemplate]];
If[Not@MatchQ[driver, _Symbol],
Message[CompileTemplate::comp, driver];
Throw[$Failed, compileTemplate]
];
print["Current directory is: ", Directory[]];
classlist = Cases[classes, LClass[s_String, __] :> s];
sourcefile = "LTemplate-" <> libname <> ".cpp";
If[Not@FileExistsQ[#],
print["File ", #, " does not exist. Aborting."]; Throw[$Failed, compileTemplate]
]& /@ (# <> ".h"&) /@ classlist;
print["Unloading library ", libname, " ..."];
Quiet@LibraryUnload[libname];
print["Generating library code ..."];
code = TranslateTemplate[tem];
If[FileExistsQ[sourcefile], print[sourcefile, " already exists and will be overwritten."]];
Export[sourcefile, code, "String"];
print["Compiling library code ..."];
includeDirs = Flatten[{OptionValue["IncludeDirectories"], $includeDirectory}];
With[{driver = driver},
Internal`InheritedBlock[{driver},
SetOptions[driver,
"SystemCompileOptions" -> Flatten@{
OptionValue[driver, "SystemCompileOptions"],
Switch[{$OperatingSystem, driver["Name"][]},
{"Windows", "Visual Studio"}, {},
{"Windows", "Intel Compiler"}, "/Qstd=c++11",
{"MacOSX", "Clang"}, {If[$VersionNumber <= 10.3, "-mmacosx-version-min=10.9", Unevaluated@Sequence[]], "-std=c++11"},
{_, _}, "-std=c++11"
]
}
];
CreateLibrary[
AbsoluteFileName /@ Flatten[{sourcefile, sources}], libname,
"IncludeDirectories" -> includeDirs,
Sequence @@ FilterRules[{opt}, Except["IncludeDirectories"]]
]
]
]
],
compileTemplate
]
(****************** Pretty print a template ********************)
FormatTemplate[template_] :=
With[{t = NormalizeTemplate[template]},
(* If the template is invalid, we report errors but we do not abort.
Pretty-printing is still useful for invalid templates to facilitate finding mistakes.
*)
validateTemplate[t];
formatTemplate@NormalizeTemplate[t]
]
formatTemplate[template_] :=
Block[{LFun, LOFun, LClass, LTemplate, LType, LExpressionID},
With[{tem = template},
LType /: {LType[head_, rest___], passing : passingMethodPattern} :=
If[{passing} =!= {}, passing <> " ", ""] <>
ToString[head] <>
If[{rest} =!= {}, "<" <> StringTake[ToString[{rest}], {2,-2}] <> ">", ""];
LExpressionID[head_String] := "LExpressionID<" <> head <> ">";
LFun[name_, args_, ret_] := StringTemplate["`` ``(``)"][ToString[ret], name, StringJoin@Riffle[ToString /@ args, ", "]];
LOFun[name_] := StringTemplate["LinkObject ``(LinkObject)"][name];
LClass[name_, funs_] := StringTemplate["class ``:\n``"][name, StringJoin@Riffle[" " <> ToString[#] & /@ funs, "\n"]];
LTemplate[name_, classes_] := StringTemplate["template ``\n\n"][name] <> Riffle[ToString /@ classes, "\n\n"];
tem
]
]
End[] (* End Private Context *)

View File

@ -0,0 +1,22 @@
(* Mathematica Package *)
(* :Package Version: 0.5.4 *)
(* :Copyright: (c) 2019 Szabolcs Horvat *)
(* :License: MIT license, see LICENSE.txt *)
(*
* To include LTemplate privately in another package, load LTemplatePrivate.m using Get[],
* then immediately call ConfigureLTemplate[].
*)
BeginPackage["`LTemplate`", {"SymbolicC`", "CCompilerDriver`"}]
(* Note: Do not Protect symbols when LTemplate is loaded privately. *)
`Private`$private = True;
Quiet[
Get@FileNameJoin[{DirectoryName[$InputFileName], "LTemplateInner.m"}],
General::shdw (* suppress false shadowing warnings if public LTemplate was loaded first *)
]
EndPackage[]

View File

@ -0,0 +1,26 @@
(* Mathematica Package *)
(* :Package Version: 0.5.4 *)
(* :Copyright: (c) 2019 Szabolcs Horvat *)
(* :License: MIT license, see LICENSE.txt *)
(*
* To include LTemplate privately in another package, and disable compilation support,
* load LTemplatePrivateNoCompile.m using Get[], then immediately call ConfigureLTemplate[].
* Disabling compilation support will avoid loading CCompilerDriver` and therefore improve
* loading performance on Windows. Packages that ship with pre-compiled binaries do not need
* compilation support in the LTemplate they embed.
*)
BeginPackage["`LTemplate`", {"SymbolicC`"}]
(* Note: Do not Protect symbols when LTemplate is loaded privately. *)
`Private`$private = True;
`Private`$noCompile = True;
Quiet[
Get@FileNameJoin[{DirectoryName[$InputFileName], "LTemplateInner.m"}],
General::shdw (* suppress false shadowing warnings if public LTemplate was loaded first *)
]
EndPackage[]