Skip to content

Commit

Permalink
adding Faure samplers, fixing memory and UI bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
wkjarosz committed Dec 13, 2023
1 parent cb66bd9 commit 023f602
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 12 deletions.
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ if(sobol_ADDED)
set_target_properties(sobol PROPERTIES CXX_STANDARD 17)
endif()

CPMAddPackage("gh:Andrew-Helmer/stochastic-generation#7dfaf471277424b1d9940ef15f8c925086c5fec3")
CPMAddPackage("gh:wkjarosz/stochastic-generation#b2dbbb3a24d5c461514fc1f7b61082d30db78c1c")
if(stochastic-generation_ADDED)
message(STATUS "stochastic-generation library added")
# stochastic-generation has no CMake support, so we create our own target
Expand Down Expand Up @@ -218,6 +218,7 @@ add_library(
samplerlib OBJECT
STATIC
include/sampler/CSVFile.h
include/sampler/Faure.h
include/sampler/fwd.h
include/sampler/halton_sampler.h
include/sampler/Halton.h
Expand All @@ -240,6 +241,7 @@ add_library(
include/sampler/Sobol.h
include/sampler/Sudoku.h
src/sampler/CSVFile.cpp
src/sampler/Faure.cpp
src/sampler/Halton.cpp
src/sampler/Jittered.cpp
src/sampler/LP.cpp
Expand Down
58 changes: 58 additions & 0 deletions include/sampler/Faure.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/** \file Faure.h
\author Wojciech Jarosz
*/
#pragma once

#include <sampler/Sampler.h>
#include <vector>

/// Stochastic Faure quasi-random number sequence.
/**
A wrapper for Helmer's Owen-scrambled stochastic (0,s) Faure sampler with s=3,5,7,11
*/
class Faure : public TSamplerMinMaxDim<1, 11>
{
public:
Faure(unsigned dimensions = 2, unsigned numSamples = 1);

void sample(float[], unsigned i) override;

/// Returns an appropriate grid resolution to help visualize stratification
int coarseGridRes(int samples) const override
{
return int(std::pow(samples, (1.f / s())));
}

unsigned dimensions() const override
{
return m_numDimensions;
}
void setDimensions(unsigned n) override;

bool randomized() const override
{
return m_owen;
}
void setRandomized(bool b = true) override
{
m_owen = b;
regenerate();
}

std::string name() const override;

int numSamples() const override
{
return m_numSamples;
}
int setNumSamples(unsigned n) override;

protected:
void regenerate();
unsigned s() const;

unsigned m_numSamples;
unsigned m_numDimensions;
bool m_owen;
std::vector<double> m_samples;
};
24 changes: 13 additions & 11 deletions src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "portable-file-dialogs.h"

#include <sampler/CSVFile.h>
#include <sampler/Faure.h>
#include <sampler/Halton.h>
#include <sampler/Hammersley.h>
#include <sampler/Jittered.h>
Expand Down Expand Up @@ -88,6 +89,7 @@ SampleViewer::SampleViewer()
m_samplers.emplace_back(new SSobol(m_num_dimensions));
m_samplers.emplace_back(new ZeroTwo(1, m_num_dimensions, false));
m_samplers.emplace_back(new ZeroTwo(1, m_num_dimensions, true));
m_samplers.emplace_back(new Faure(m_num_dimensions, 1));
m_samplers.emplace_back(new Halton(m_num_dimensions));
m_samplers.emplace_back(new HaltonZaremba(m_num_dimensions));
m_samplers.emplace_back(new Hammersley<Halton>(m_num_dimensions, 1));
Expand Down Expand Up @@ -639,9 +641,6 @@ void SampleViewer::draw_editor()
m_gpu_points_dirty = m_cpu_points_dirty = m_gpu_grids_dirty = true;
HelloImGui::Log(HelloImGui::LogLevel::Debug, "Regenerated %d points.", m_point_count);
}
// now that the user has finished editing, sync the GUI value
if (ImGui::IsItemDeactivatedAfterEdit())
m_target_point_count = m_point_count;

tooltip(
"Set the target number of points to generate. For samplers that only support certain numbers of points "
Expand Down Expand Up @@ -770,8 +769,13 @@ void SampleViewer::draw_editor()
if (big_header(ICON_FA_RANDOM " Dimension mapping"))
// =========================================================
{
if (ImGui::SliderInt3("XYZ", &m_dimension[0], 0, m_num_dimensions - 1, "%d", ImGuiSliderFlags_AlwaysClamp))
int3 dims = m_dimension;
if (ImGui::SliderInt3("XYZ", &dims[0], 0, m_num_dimensions - 1, "%d", ImGuiSliderFlags_AlwaysClamp))
{
m_gpu_points_dirty = true;
m_dimension = dims;
}

tooltip("Set which dimensions should be used for the XYZ dimensions of the displayed 3D points.");

ImGui::Dummy({0, HelloImGui::EmSize(0.25f)});
Expand Down Expand Up @@ -878,7 +882,6 @@ void SampleViewer::process_hotkeys()
else if (ImGui::IsKeyPressed(ImGuiKey_D))
{
m_num_dimensions = std::clamp(m_num_dimensions + (ImGui::IsKeyDown(ImGuiMod_Shift) ? 1 : -1), 2, 10);
m_dimension = linalg::clamp(m_dimension, int3{0}, int3{m_num_dimensions - 1});
m_gpu_points_dirty = m_cpu_points_dirty = m_gpu_grids_dirty = true;
}
else if (ImGui::IsKeyPressed(ImGuiKey_R))
Expand Down Expand Up @@ -946,7 +949,6 @@ void SampleViewer::update_points(bool regenerate)
generator->setRandomized(m_randomize);

generator->setDimensions(m_num_dimensions);
m_num_dimensions = generator->dimensions();

int num_pts = generator->setNumSamples(m_target_point_count);
m_point_count = num_pts >= 0 ? num_pts : m_target_point_count;
Expand Down Expand Up @@ -986,7 +988,6 @@ void SampleViewer::update_points(bool regenerate)
for (int i = 0; i < m_points.sizeX(); ++i)
{
float v = m_points(i, std::clamp(m_subset_axis, 0, m_num_dimensions - 1));
v += 0.5f;
if (v >= (m_subset_level + 0.0f) / m_num_subset_levels && v < (m_subset_level + 1.0f) / m_num_subset_levels)
{
// copy all dimensions (rows) of point i
Expand All @@ -997,9 +998,9 @@ void SampleViewer::update_points(bool regenerate)
}
}

int3 dims = linalg::clamp(m_dimension, int3{0}, int3{m_num_dimensions - 1});
for (size_t i = 0; i < m_3d_points.size(); ++i)
m_3d_points[i] = float3{m_subset_points(i, m_dimension.x), m_subset_points(i, m_dimension.y),
m_subset_points(i, m_dimension.z)};
m_3d_points[i] = float3{m_subset_points(i, dims.x), m_subset_points(i, dims.y), m_subset_points(i, dims.z)};

//
// Upload points to the GPU
Expand Down Expand Up @@ -1355,8 +1356,9 @@ string SampleViewer::export_XYZ_points(const string &format)
m_show_coarse_grid, m_show_bbox);
}

out += (format == "eps") ? draw_points_eps(mvp, m_dimension, m_subset_points, get_draw_range())
: draw_points_svg(mvp, m_dimension, m_subset_points, get_draw_range(), radius);
int3 dims = linalg::clamp(m_dimension, int3{0}, int3{m_num_dimensions - 1});
out += (format == "eps") ? draw_points_eps(mvp, dims, m_subset_points, get_draw_range())
: draw_points_svg(mvp, dims, m_subset_points, get_draw_range(), radius);

out += (format == "eps") ? footer_eps() : footer_svg();
return out;
Expand Down
82 changes: 82 additions & 0 deletions src/sampler/Faure.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/** \file Faure.cpp
\author Wojciech Jarosz
*/

#include <assert.h>
#include <iostream>
#include <sampler/Faure.h>
#include <sampler/Misc.h>

#include "sampling/sfaure.h"

Faure::Faure(unsigned dimensions, unsigned numSamples) : m_numSamples(numSamples), m_numDimensions(dimensions)
{
regenerate();
}

unsigned Faure::s() const
{
if (m_numDimensions <= 3)
return 3;
else if (m_numDimensions <= 5)
return 5;
else if (m_numDimensions <= 7)
return 7;
else // if (m_numDimensions <= 11)
return 11;
}

std::string Faure::name() const
{
return "Stochastic Faure (0," + std::to_string(s()) + ")";
}

void Faure::regenerate()
{
std::cout << "regenerating " << m_numSamples << std::endl;
// compute all points, and store them
m_samples.clear();
m_samples.resize(m_numSamples * s());

if (m_numSamples > 0)
{
if (m_numDimensions <= 3)
sampling::GetStochasticFaure03Samples(m_numSamples, s(), false, 1, m_owen, &m_samples[0]);
else if (m_numDimensions <= 5)
sampling::GetStochasticFaure05Samples(m_numSamples, s(), false, 1, m_owen, &m_samples[0]);
else if (m_numDimensions <= 7)
sampling::GetStochasticFaure07Samples(m_numSamples, s(), false, 1, m_owen, &m_samples[0]);
else if (m_numDimensions <= 11)
sampling::GetStochasticFaure011Samples(m_numSamples, s(), false, 1, m_owen, &m_samples[0]);
}
}

void Faure::setDimensions(unsigned n)
{
auto newD = std::clamp(n, (unsigned)MIN_DIMENSION, (unsigned)MAX_DIMENSION);
if (newD != m_numDimensions)
{
m_numDimensions = newD;
regenerate();
}
}

int Faure::setNumSamples(unsigned n)
{
auto oldN = m_numSamples;
m_numSamples = (n == 0) ? 1 : n;
if (oldN < m_numSamples)
regenerate();

return m_numSamples;
}

void Faure::sample(float r[], unsigned i)
{
assert(i < m_numSamples);
for (unsigned d = 0; d < dimensions(); ++d)
{
assert(s() * i + d < m_samples.size());
r[d] = m_samples[s() * i + d];
}
}

0 comments on commit 023f602

Please sign in to comment.