Lattice Builder Manual Software Package for Constructing Rank-1 Lattices
High-Level API Tutorial

This tutorial shows how to use high-level features of the Lattice Builder application programming interface (API), in the context of simulation software.

Simulation software written in an arbitrary language can always make use of Lattice Builder by invoking the command-line tool with appropriate options (see the Command-Line Tutorial) and by parsing its text output to extract the generating vector from the results. This is what the Lattice Builder Web Application does. Calling an external command can be done in most programming languages.

From software written in C++, it is also possible avoids the overhead of loading and executing an external program by directly calling functions of the Lattice Builder library instead of invoking the command-line tool. In fact, the command-line tool is just an interface to the API described in this tutorial.

The complete code of the examples in this tutorial can be found under the latbuilder/examples/tutorial/ directory.

The Parser namespace contains the tools to make calls to Lattice Builder using text arguments similar to those of the command-line tool (see Command-Line Tutorial). The Parser::Search class provides a parse() method that returns a pointer to a Task::Search instance. The arguments to parse() are all text of the same format as the command-line arguments (in the following order) to:

• --construction
• --lattice-type
• --size
• --dimension
• --figure-of-merit
• --weights
• --filters
• --multilevel-filters
• --combiner

# Constructing and Using Ordinary Lattice Rules

The following piece of code calls Lattice Builder to perform a fast CBC construction of an ordinary lattice rule with $$n=2^8$$ points in dimension 10 using the coordinate-uniform implementation (required by fast CBC) of the $$\mathcal P_2$$ criterion, with product weights with $$\gamma_j=0.1$$ for all $$j$$, using no filters:

LatticePoints search()
{
cmd.construction = "fast-CBC";
cmd.size = "2^8";
cmd.dimension = "10";
cmd.figure = "CU:P2";
cmd.weights = std::vector<std::string>{"product:0.1"};
cmd.weightsPowerScale = 1.0;
cmd.normType = "2";
auto search = cmd.parse();
std::cout << *search << std::endl;
search->execute();
std::cout << "BEST LATTICE: " << search->bestLattice() << std::endl;
std::cout << "MERIT: " << search->bestMeritValue() << std::endl;
const auto& lat = search->bestLattice();
return LatticePoints(lat.sizeParam().numPoints(), lat.gen());
}

The combiner argument is set to a valid value, but it is not used. The resulting lattice definition can be retrieved with search->bestLattice(). Our function returns an instance of the virtual container LatticePoints, defined in tutorial/LatticePoints.h as:

// Copyright (c) 2012 David Munger, Pierre L'Ecuyer, Université de Montréal.
//
// This file is part of Lattice Builder.
//
// Lattice Builder is free software: you can redistribute it and/or modify
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Lattice Builder is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Lattice Builder. If not, see <http://www.gnu.org/licenses/>.
#ifndef LATTICE_POINTS_H
#define LATTICE_POINTS_H
// virtual container for lattice points
class LatticePoints {
public:
// standard container type definitions
typedef std::vector<double> value_type;
typedef size_t size_type;
LatticePoints(size_type numPoints, std::vector<unsigned long> gen):
m_numPoints(numPoints),
m_intGen(std::move(gen)),
m_gen(m_intGen.size())
{ updateGen(); }
// returns the number of points of the lattice rule
size_type numPoints() const { return m_numPoints; }
// returns the number of points of the lattice rule
size_type size() const { return m_numPoints; }
// returns the lattice dimension
size_type dimension() const { return m_gen.size(); }
// returns the i-th lattice point
value_type operator[](size_type i) const
{
std::vector<double> point(dimension());
for (size_type j = 0; j < point.size(); j++) {
double x = i * m_gen[j];
point[j] = x - int(x);
}
return point;
}
private:
size_type m_numPoints;
std::vector<unsigned long> m_intGen;
std::vector<double> m_gen;
void updateGen()
{
for (size_type j = 0; j < m_gen.size(); j++)
m_gen[j] = double(m_intGen[j]) / m_numPoints;
}
};
#endif

which can be used to enumerate the lattice points. The following piece of code shows how it could be used by simulation software.

void simulate(const LatticePoints& lat)
{
for (size_t i = 0; i < lat.size(); i++)
std::cout << "point " << i << ":\t" << lat[i] << std::endl;
}

In this example, we just print the points to standard output; in practice we would use them to integrate multidimensional functions. The complete example can be found in tutorial/ParserFastCBC.cc.

# Constructing and Using Embedded Lattice Rules

To construct embedded lattices, we change the lattice type to embedded and the combiner to sum:

cmd.construction = "fast-CBC";
cmd.size = "2^8";
cmd.dimension = "10";
cmd.figure = "CU:P2";
cmd.weights = std::vector<std::string>{"product:0.1"};
cmd.weightsPowerScale = 1.0;
cmd.normType = "2";
cmd.multilevelFilters = std::vector<std::string>{"norm:P2-SL10", "low-pass:1.0"};
cmd.combiner = "sum";
auto search = cmd.parse();

We also add normalization and low-pass filters:

cmd.multilevelFilters = std::vector<std::string>{"norm:P2-SL10", "low-pass:1.0"};

And, our search() functions now returns an instance of EmbeddedLatticePoints instead of LatticePoints:

const auto& lat = search->bestLattice();
return EmbeddedLatticePoints(lat.sizeParam().base(), lat.sizeParam().maxLevel(), lat.gen());

The virtual container EmbeddedLatticePoints is defined in tutorial/EmbeddedLatticePoints.h as:

// Copyright (c) 2012 David Munger, Pierre L'Ecuyer, Université de Montréal.
//
// This file is part of Lattice Builder.
//
// Lattice Builder is free software: you can redistribute it and/or modify
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Lattice Builder is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Lattice Builder. If not, see <http://www.gnu.org/licenses/>.
#ifndef EMBEDDED_LATTICE_POINTS_H
#define EMBEDDED_LATTICE_POINTS_H
// virtual container for lattice points
class EmbeddedLatticePoints {
public:
// standard container type definitions
typedef std::vector<double> value_type;
typedef size_t size_type;
EmbeddedLatticePoints(size_type base, size_type maxLevel, std::vector<unsigned long> gen):
m_base(base),
m_maxLevel(maxLevel),
m_intGen(std::move(gen)),
m_gen(m_intGen.size())
{ reset(); }
// returns to level 0
void reset() { m_level = 0; m_numPoints = 1; updateGen(); }
// increases the level
void extend() { m_level++; m_numPoints *= m_base; updateGen(); }
// returns the base for the number of points
size_type base() const { return m_base; }
// returns the maximum level number
size_type maxLevel() const { return m_maxLevel; }
// returns the current level number
size_type level() const { return m_level; }
// returns the total number of points on the current level
size_type numPoints() const { return m_numPoints; }
// returns the number of points on the current level but not on previous
// levels
size_type size() const { return numPoints() <= 1 ? numPoints() : (base() - 1) * numPoints() / base(); }
// returns the lattice dimension
size_type dimension() const { return m_gen.size(); }
// returns the i-th lattice point that lies on the current levels but not on
// previous levels
value_type operator[](size_type i) const
{
std::vector<double> point(dimension());
for (size_type j = 0; j < point.size(); j++) {
double x = map(i) * m_gen[j];
point[j] = x - int(x);
}
return point;
}
private:
size_type m_base;
size_type m_maxLevel;
std::vector<unsigned long> m_intGen;
std::vector<double> m_gen;
size_type m_numPoints;
size_type m_level;
size_type map(size_type i) const { return numPoints() <= 1 ? i : (base() + 1) * (i + 1) / base(); }
void updateGen()
{
for (size_type j = 0; j < m_gen.size(); j++)
m_gen[j] = double(m_intGen[j]) / m_numPoints;
}
};
#endif

Finally, we modify our simulate() function to use the points level by level:

void simulate(EmbeddedLatticePoints lat)
{
while (lat.level() <= lat.maxLevel()) {
std::cout << "==> level " << lat.level() << std::endl;
for (size_t i = 0; i < lat.size(); i++)
std::cout << "point " << i << ":\t" << lat[i] << std::endl;
lat.extend();
}
}

The complete example can be found in tutorial/ParserFastCBCEmbedded.cc.