Lattice Builder Manual
Software Package for Constructing Rank-1 Lattices
Extending Lattice Builder

Implementing a New Figure of Merit

Assume that we want to introduce a new coordinate-uniform figure of merit. The first thing we need to do is to add a new functor and a new kernel, by writing the following to latbuilder/include/latbuilder/Functor/MyFigure.h:

#include <sstream>
namespace LatBuilder { namespace Functor {
class MyFigure {
public:
typedef Real value_type;
typedef Real result_type;
bool symmetric() const
{ return true; }
static constexpr Compress suggestedCompression()
{ return Compress::SYMMETRIC; }
result_type operator()(const value_type& x, Modulus n = 0) const
{ return x * (1.0 - x); /* change this to suit your needs */ }
std::string name() const
{ return "my-figure"; }
};
inline
std::ostream& operator<<(std::ostream& os, const MyFigure& functor)
{ return os << functor.name(); }
}}

and the following to latbuilder/include/latbuilder/Kernel/MyFigure.h:

#include "latbuilder/Kernel/FunctorAdaptor.h"
#include "latbuilder/Functor/MyFigure.h"
namespace LatBuilder { namespace Kernel {
class MyFigure : public FunctorAdaptor<Functor::MyFigure> {
public:
MyFigure():
FunctorAdaptor<Functor>(Functor())
{}
};
}}

Then, teach the kernel parser to recognize the string my-figure as our new figure of merit by appending the try block in Parser::Kernel::parse() with the following code:

else if (str == "my-figure") {
func(LatBuilder::Kernel::MyFigure(), std::forward<ARGS>(args)...);
return;
}

Also make sure to add the relevant include file in latbuilder/include/latbuilder/Parser/Kernel.h:

#include "latbuilder/Kernel/MyFigure.h"

Then it should work out of the box if you recompile Lattice Builder, then run latbuilder with the option –figure-of-merit CU:my-figure.

Implementing Custom Weights

To compute weight values for any of the supported weight types (product, order-dependent, POD, projection-dependent), it is possible to use the enter an expression function from the web user interface. But let us assuming that we want to do this by deriving a new class of weights from an existing one. Consider product weights that depend a single parameter \(\eta\) and that take the value

\[ \gamma_{\mathfrak u} = \prod_{j \in \mathfrak u} (1 / j^\eta) \]

for projection \(\mathfrak u\). First, we define the new weights class that overrides ProductWeights::getWeightForCoordinate() in latcommon/include/latcommon/MyWeights.h:

#include "latcommon/ProductWeights.h"
namespace LatCommon {
class MyWeights : public ProductWeights {
public:
explicit MyWeights(Weight parameter=1.0) : m_parameter(parameter) {}
virtual ~MyWeights() {}
virtual Weight getWeightForCoordinate(Coordinates::size_type coordinate) const
{ return std::pow(coordinate + 1, -m_parameter); }
protected:
virtual void format(std::ostream& os) const
{ os << "MyWeights(" << m_parameter << ")"; }
Weight m_parameter;
};
}

Next, we declare a new member function in Parser::Weights in latbuilder/include/latbuilder/Parser/Weights.h:

static std::unique_ptr<LatCommon::Weights>
parseMyWeights(const std::string& arg, Real powerScale);

and implement it in latbuilder/src/Parser/Weights.cc:

std::unique_ptr<LatCommon::Weights>
Weights::parseMyWeights(const std::string& arg, Real powerScale)
{
auto ka = splitPair<std::string, Real>(arg, ':');
if (ka.first != "my-weights") return nullptr;
auto w = new LatCommon::MyWeights(ka.second);
return std::unique_ptr<LatCommon::Weights>(w);
}

after, of course, adding the new header with:

#include "latcommon/MyWeights.h"

We also need to add a conditional block in Parser::Weights::parse:

if (auto p = parseMyWeights(arg, powerScale))
return p;

Then, after recompiling Lattice Builder, the new weights should be available to use by invoking latbuilder with the option –weights MyWeights:1.5, for example.