Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Standardize and Cache Random Seeds #745

Merged
merged 12 commits into from
Oct 24, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

#include "complex/DataStructure/DataPath.hpp"
#include "complex/DataStructure/Geometry/ImageGeom.hpp"
#include "complex/Filter/Actions/CreateArrayAction.hpp"
#include "complex/Filter/Actions/EmptyAction.hpp"
#include "complex/Parameters/ArraySelectionParameter.hpp"
#include "complex/Parameters/BoolParameter.hpp"
#include "complex/Parameters/DataObjectNameParameter.hpp"
#include "complex/Parameters/GeometrySelectionParameter.hpp"
#include "complex/Parameters/NumberParameter.hpp"

Expand Down Expand Up @@ -52,9 +54,12 @@ Parameters AddBadDataFilter::parameters() const
Parameters params;

// Create the parameter descriptors that are needed for this filter
params.insertSeparator(Parameters::Separator{"Optional Variables"});
params.insertSeparator(Parameters::Separator{"Seeded Randomness"});
params.insertLinkableParameter(std::make_unique<BoolParameter>(k_UseSeed_Key, "Use Seed for Random Generation", "When true the user will be able to put in a seed for random generation", false));
params.insert(std::make_unique<NumberParameter<uint64>>(k_SeedValue_Key, "Seed", "The seed fed into the random generator", std::mt19937::default_seed));
params.insert(std::make_unique<NumberParameter<uint64>>(k_SeedValue_Key, "Seed Value", "The seed fed into the random generator", std::mt19937::default_seed));
params.insert(std::make_unique<DataObjectNameParameter>(k_SeedArrayName_Key, "Stored Seed Value Array Name", "Name of array holding the seed value", "AddBadData SeedValue"));

params.insertSeparator(Parameters::Separator{"Optional Variables"});
params.insertLinkableParameter(std::make_unique<BoolParameter>(k_PoissonNoise_Key, "Add Random Noise", "If true the user may set the poisson volume fraction", false));
params.insert(std::make_unique<Float32Parameter>(k_PoissonVolFraction_Key, "Volume Fraction of Random Noise", "A value between 0 and 1 inclusive that is compared against random generation", 0.0f));
params.insertLinkableParameter(std::make_unique<BoolParameter>(k_BoundaryNoise_Key, "Add Boundary Noise", "If true the user may set the boundary volume fraction", false));
Expand Down Expand Up @@ -91,6 +96,7 @@ IFilter::PreflightResult AddBadDataFilter::preflightImpl(const DataStructure& da
auto pBoundaryVolFractionValue = filterArgs.value<float32>(k_BoundaryVolFraction_Key);
auto pGBEuclideanDistancesArrayPathValue = filterArgs.value<DataPath>(k_GBEuclideanDistancesArrayPath_Key);
auto pImageGeometryPathValue = filterArgs.value<DataPath>(k_ImageGeometryPath_Key);
auto pSeedArrayNameValue = filterArgs.value<std::string>(k_SeedArrayName_Key);

PreflightResult preflightResult;
complex::Result<OutputActions> resultOutputActions;
Expand Down Expand Up @@ -118,6 +124,11 @@ IFilter::PreflightResult AddBadDataFilter::preflightImpl(const DataStructure& da
return {MakeErrorResult<OutputActions>(-76237, fmt::format("Image geometry must have a valid cell Attribute Matrix"))};
}

{
auto createAction = std::make_unique<CreateArrayAction>(DataType::uint64, std::vector<usize>{1}, std::vector<usize>{1}, DataPath({pSeedArrayNameValue}));
resultOutputActions.value().appendAction(std::move(createAction));
}

// Return both the resultOutputActions and the preflightUpdatedValues via std::move()
return {std::move(resultOutputActions), std::move(preflightUpdatedValues)};
}
Expand All @@ -126,6 +137,15 @@ IFilter::PreflightResult AddBadDataFilter::preflightImpl(const DataStructure& da
Result<> AddBadDataFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel) const
{
auto seed = filterArgs.value<uint64>(k_SeedValue_Key);
if(!filterArgs.value<bool>(k_UseSeed_Key))
{
seed = static_cast<std::mt19937_64::result_type>(std::chrono::steady_clock::now().time_since_epoch().count());
}

// Store Seed Value in Top Level Array
dataStructure.getDataRefAs<UInt64Array>(DataPath({filterArgs.value<std::string>(k_SeedArrayName_Key)}))[0] = seed;

AddBadDataInputValues inputValues;

inputValues.PoissonNoise = filterArgs.value<bool>(k_PoissonNoise_Key);
Expand All @@ -134,7 +154,6 @@ Result<> AddBadDataFilter::executeImpl(DataStructure& dataStructure, const Argum
inputValues.BoundaryVolFraction = filterArgs.value<float32>(k_BoundaryVolFraction_Key);
inputValues.GBEuclideanDistancesArrayPath = filterArgs.value<DataPath>(k_GBEuclideanDistancesArrayPath_Key);
inputValues.ImageGeometryPath = filterArgs.value<DataPath>(k_ImageGeometryPath_Key);
inputValues.UseSeed = filterArgs.value<bool>(k_UseSeed_Key);
inputValues.SeedValue = filterArgs.value<uint64>(k_SeedValue_Key);

return AddBadData(dataStructure, messageHandler, shouldCancel, &inputValues)();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class COMPLEXCORE_EXPORT AddBadDataFilter : public IFilter
static inline constexpr StringLiteral k_ImageGeometryPath_Key = "image_geometry_path";
static inline constexpr StringLiteral k_UseSeed_Key = "use_seed";
static inline constexpr StringLiteral k_SeedValue_Key = "seed_value";
static inline constexpr StringLiteral k_SeedArrayName_Key = "seed_array_name";

/**
* @brief Returns the name of the filter.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "AddBadData.hpp"

#include "complex/DataStructure/DataArray.hpp"
#include "complex/DataStructure/DataGroup.hpp"
#include "complex/DataStructure/Geometry/ImageGeom.hpp"
#include "complex/Utilities/DataGroupUtilities.hpp"
#include "complex/Utilities/FilterUtilities.hpp"
Expand Down Expand Up @@ -46,14 +45,7 @@ Result<> AddBadData::operator()()
{
std::random_device randomDevice; // Will be used to obtain a seed for the random number engine
std::mt19937 generator(randomDevice()); // Standard mersenne_twister_engine seeded with rd()
std::mt19937::result_type seed = m_InputValues->SeedValue;

if(!m_InputValues->UseSeed)
{
seed = static_cast<std::mt19937::result_type>(std::chrono::steady_clock::now().time_since_epoch().count());
}

generator.seed(seed);
generator.seed(m_InputValues->SeedValue);
std::uniform_real_distribution<float32> distribution(0.0F, 1.0F);

auto& imgGeom = m_DataStructure.getDataRefAs<ImageGeom>(m_InputValues->ImageGeometryPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ struct COMPLEXCORE_EXPORT AddBadDataInputValues
float32 BoundaryVolFraction;
DataPath GBEuclideanDistancesArrayPath;
DataPath ImageGeometryPath;
bool UseSeed;
uint64 SeedValue;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace
{
// -----------------------------------------------------------------------------
std::vector<float32> GenerateRandomDistribution(float32 minDistance, float32 maxDistance, int32 numBins, const std::array<float32, 3>& boxDims, const std::array<float32, 3>& boxRes,
bool useSeedFromUser, uint64 userSeedValue)
uint64 userSeedValue)
{
std::vector<float32> freq(numBins, 0);
std::vector<float32> randomCentroids;
Expand All @@ -36,12 +36,7 @@ std::vector<float32> GenerateRandomDistribution(float32 minDistance, float32 max

std::random_device randomDevice; // Will be used to obtain a seed for the random number engine
std::mt19937_64 generator(randomDevice()); // Standard mersenne_twister_engine seeded with rd()
std::mt19937::result_type seed = userSeedValue;
if(!useSeedFromUser)
{
seed = static_cast<std::mt19937::result_type>(std::chrono::steady_clock::now().time_since_epoch().count());
}
generator.seed(seed);
generator.seed(userSeedValue);
std::uniform_real_distribution<double> distribution(0.0, 1.0);

randomCentroids.resize(largeNumber * 3);
Expand Down Expand Up @@ -270,7 +265,7 @@ Result<> FindFeatureClustering::operator()()

randomRDF.resize(currentNumBins + 1);
// Call this function to generate the random distribution, which is normalized by the total number of distances
randomRDF = GenerateRandomDistribution(min, max, m_InputValues->NumberOfBins, boxDims, boxRes, m_InputValues->UseSeed, m_InputValues->SeedValue);
randomRDF = GenerateRandomDistribution(min, max, m_InputValues->NumberOfBins, boxDims, boxRes, m_InputValues->SeedValue);

// Scale the random distribution by the number of distances in this particular instance
const float32 normFactor = totalPptFeatures * (totalPptFeatures - 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ struct COMPLEXCORE_EXPORT FindFeatureClusteringInputValues
int32 NumberOfBins;
int32 PhaseNumber;
bool RemoveBiasedFeatures;
bool UseSeed;
uint64 SeedValue;
DataPath EquivalentDiametersArrayPath;
DataPath FeaturePhasesArrayPath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ Result<> PointSampleTriangleGeometry::operator()()
auto tupleShape = {static_cast<usize>(m_Inputs->pNumberOfSamples)};
vertex.getVertexAttributeMatrix()->resizeTuples(tupleShape);

std::mt19937_64::result_type seed = static_cast<std::mt19937_64::result_type>(std::chrono::steady_clock::now().time_since_epoch().count());
std::mt19937_64 generator(seed);
std::mt19937_64 generator(m_Inputs->Seed);
std::uniform_real_distribution<> distribution(0.0f, 1.0f);

// Create the Triangle Ids vector and fill it from zero to size-1 incrementally
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ struct COMPLEXCORE_EXPORT PointSampleTriangleGeometryInputs
DataPath pVertexGeometryPath;
DataPath pVertexGroupDataPath;
MultiArraySelectionParameter::ValueType pCreatedDataArrayPaths;
uint64 Seed;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
#include "complex/Parameters/BoolParameter.hpp"
#include "complex/Utilities/DataArrayUtilities.hpp"

#include <chrono>

using namespace complex;

#define CX_DEFAULT_CONSTRUCTORS(className) \
Expand Down Expand Up @@ -210,11 +208,6 @@ Result<> ScalarSegmentFeatures::operator()()
// Generate the random voxel indices that will be used for the seed points to start a new grain growth/agglomeration
auto totalPoints = inputDataArray->getNumberOfTuples();

const int64 rangeMin = 0;
const int64 rangeMax = totalPoints - 1;
Int64Distribution distribution;
initializeVoxelSeedGenerator(distribution, rangeMin, rangeMax);

// // Add compare function to arguments
// Arguments newArgs = args;
// newArgs.insert(k_CompareFunctKey, compare.get());
Expand All @@ -232,9 +225,15 @@ Result<> ScalarSegmentFeatures::operator()()
activeArray->getDataStore()->fill(1);
(*activeArray)[0] = 0;

// By default we randomize grains
// Randomize the feature Ids for purely visual clarify. Having random Feature Ids
// allows users visualizing the data to better discern each grain otherwise the coloring
// would look like a smooth gradient. This is a user input parameter
if(m_InputValues->pShouldRandomizeFeatureIds)
{
const int64 rangeMin = 0;
const int64 rangeMax = totalPoints - 1;
Int64Distribution distribution;
initializeStaticVoxelSeedGenerator(distribution, rangeMin, rangeMax);
totalPoints = gridGeom->getNumberOfCells();
randomizeFeatureIds(m_FeatureIdsArray, totalPoints, totalFeatures, distribution);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ class SharedFeatureFaceImpl
using SeedGenerator = std::mt19937_64;
using Int64Distribution = std::uniform_int_distribution<int64>;
// -----------------------------------------------------------------------------
SeedGenerator initializeVoxelSeedGenerator(Int64Distribution& distribution, const int64 rangeMin, const int64 rangeMax)
SeedGenerator initializeStaticVoxelSeedGenerator(Int64Distribution& distribution, const int64 rangeMin, const int64 rangeMax)
{
auto seed = static_cast<SeedGenerator::result_type>(std::chrono::steady_clock::now().time_since_epoch().count());
SeedGenerator generator;
generator.seed(seed);
generator.seed(SeedGenerator::default_seed);
distribution = std::uniform_int_distribution<int64>(rangeMin, rangeMax);

return generator;
Expand All @@ -81,7 +80,7 @@ void RandomizeFaceIds(complex::Int32Array& featureIds, uint64 totalFeatures, Int
// Generate an even distribution of numbers between the min and max range
const int64 rangeMin = 1;
const int64 rangeMax = totalFeatures - 1;
auto generator = initializeVoxelSeedGenerator(distribution, rangeMin, rangeMax);
auto generator = initializeStaticVoxelSeedGenerator(distribution, rangeMin, rangeMax);

DataStructure tmpStructure;
auto rndNumbers = Int64Array::CreateWithStore<DataStore<int64>>(tmpStructure, std::string("_INTERNAL_USE_ONLY_NewFeatureIds"), std::vector<usize>{totalFeatures}, std::vector<usize>{1});
Expand Down Expand Up @@ -216,7 +215,7 @@ Result<> SharedFeatureFace::operator()()
const int64 rangeMin = 0;
const int64 rangeMax = static_cast<int64>(surfaceMeshFeatureFaceNumTriangles.getNumberOfTuples() - 1);
Int64Distribution distribution;
initializeVoxelSeedGenerator(distribution, rangeMin, rangeMax);
initializeStaticVoxelSeedGenerator(distribution, rangeMin, rangeMax);
::RandomizeFaceIds(surfaceMeshFeatureFaceIds, index, distribution);
}
return {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "UncertainRegularGridSampleSurfaceMesh.hpp"

#include "complex/DataStructure/DataArray.hpp"
#include "complex/DataStructure/DataGroup.hpp"

#include <random>

Expand Down Expand Up @@ -39,14 +38,7 @@ void UncertainRegularGridSampleSurfaceMesh::generatePoints(std::vector<Point3Df>

std::random_device randomDevice; // Will be used to obtain a seed for the random number engine
std::mt19937 generator(randomDevice()); // Standard mersenne_twister_engine seeded with rd()
std::mt19937::result_type seed = m_InputValues->SeedValue;

if(!m_InputValues->UseSeed)
{
seed = static_cast<std::mt19937::result_type>(std::chrono::steady_clock::now().time_since_epoch().count());
}

generator.seed(seed);
generator.seed(m_InputValues->SeedValue);
std::uniform_real_distribution<float32> distribution(0.0F, 1.0F);

for(usize k = 0; k < dims[2]; k++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace complex
{
struct COMPLEXCORE_EXPORT UncertainRegularGridSampleSurfaceMeshInputValues
{
bool UseSeed;
uint64 SeedValue;
VectorUInt64Parameter::ValueType Dimensions;
VectorFloat32Parameter::ValueType Spacing;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,13 @@ Parameters FindFeatureClusteringFilter::parameters() const
params.insert(std::make_unique<Int32Parameter>(k_NumberOfBins_Key, "Number of Bins for RDF", "Number of bins to split the RDF", 1));
params.insert(std::make_unique<Int32Parameter>(k_PhaseNumber_Key, "Phase Index", "Ensemble number for which to calculate the RDF and clustering list", 1));
params.insertLinkableParameter(std::make_unique<BoolParameter>(k_RemoveBiasedFeatures_Key, "Remove Biased Features", "Remove the biased features", false));

params.insertSeparator(Parameters::Separator{"Seeded Randomness"});
params.insertLinkableParameter(
std::make_unique<BoolParameter>(k_SetRandomSeed_Key, "Set Random Seed", "When checked, allows the user to set the seed value used to randomly generate the points in the RDF", true));
params.insert(std::make_unique<UInt64Parameter>(k_SeedValue_Key, "Seed Value", "The seed value used to randomly generate the points in the RDF", std::mt19937::default_seed));
params.insert(std::make_unique<DataObjectNameParameter>(k_SeedArrayName_Key, "Stored Seed Value Array Name", "Name of array holding the seed value", "FindFeatureClustering SeedValue"));

params.insertSeparator(Parameters::Separator{"Cell Feature Data"});
params.insert(std::make_unique<ArraySelectionParameter>(k_EquivalentDiametersArrayPath_Key, "Equivalent Diameters", "Diameter of a sphere with the same volume as the Feature", DataPath{},
ArraySelectionParameter::AllowedTypes{DataType::float32}, ArraySelectionParameter::AllowedComponentShapes{{1}}));
Expand All @@ -83,6 +87,7 @@ Parameters FindFeatureClusteringFilter::parameters() const
params.insertSeparator(Parameters::Separator{"Created Cell Ensemble Data"});
params.insert(std::make_unique<DataObjectNameParameter>(k_RDFArrayName_Key, "Radial Distribution Function", "A histogram of the normalized frequency at each bin", "RDF"));
params.insert(std::make_unique<DataObjectNameParameter>(k_MaxMinArrayName_Key, "Max and Min Separation Distances", "The max and min distance found between Features", "RDFMaxMinDistances"));

// Associate the Linkable Parameter(s) to the children parameters that they control
params.linkParameters(k_RemoveBiasedFeatures_Key, k_BiasedFeaturesArrayPath_Key, true);
params.linkParameters(k_SetRandomSeed_Key, k_SeedValue_Key, true);
Expand All @@ -109,6 +114,7 @@ IFilter::PreflightResult FindFeatureClusteringFilter::preflightImpl(const DataSt
auto pClusteringListArrayNameValue = filterArgs.value<std::string>(k_ClusteringListArrayName_Key);
auto pRDFArrayNameValue = filterArgs.value<std::string>(k_RDFArrayName_Key);
auto pMaxMinArrayNameValue = filterArgs.value<std::string>(k_MaxMinArrayName_Key);
auto pSeedArrayNameValue = filterArgs.value<std::string>(k_SeedArrayName_Key);

const DataPath clusteringListPath = pFeaturePhasesArrayPathValue.getParent().createChildPath(pClusteringListArrayNameValue);

Expand All @@ -129,7 +135,7 @@ IFilter::PreflightResult FindFeatureClusteringFilter::preflightImpl(const DataSt
}

const auto& cellEnsembleAM = dataStructure.getDataRefAs<AttributeMatrix>(pCellEnsembleAttributeMatrixNameValue);
const std::vector<usize> tupleShape = cellEnsembleAM.getShape();
const std::vector<usize>& tupleShape = cellEnsembleAM.getShape();
{
auto createArrayAction = std::make_unique<CreateArrayAction>(DataType::float32, tupleShape, std::vector<usize>{static_cast<usize>(pNumberOfBinsValue)},
pCellEnsembleAttributeMatrixNameValue.createChildPath(pRDFArrayNameValue));
Expand All @@ -146,21 +152,34 @@ IFilter::PreflightResult FindFeatureClusteringFilter::preflightImpl(const DataSt
resultOutputActions.value().appendAction(std::move(createArrayAction));
}

{
auto createAction = std::make_unique<CreateArrayAction>(DataType::uint64, std::vector<usize>{1}, std::vector<usize>{1}, DataPath({pSeedArrayNameValue}));
resultOutputActions.value().appendAction(std::move(createAction));
}

return {std::move(resultOutputActions), std::move(preflightUpdatedValues)};
}

//------------------------------------------------------------------------------
Result<> FindFeatureClusteringFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel) const
{
auto seed = filterArgs.value<uint64>(k_SeedValue_Key);
if(!filterArgs.value<bool>(k_SetRandomSeed_Key))
{
seed = static_cast<std::mt19937_64::result_type>(std::chrono::steady_clock::now().time_since_epoch().count());
}

// Store Seed Value in Top Level Array
dataStructure.getDataRefAs<UInt64Array>(DataPath({filterArgs.value<std::string>(k_SeedArrayName_Key)}))[0] = seed;

FindFeatureClusteringInputValues inputValues;

inputValues.ImageGeometryPath = filterArgs.value<DataPath>(k_SelectedImageGeometry_Key);
inputValues.NumberOfBins = filterArgs.value<int32>(k_NumberOfBins_Key);
inputValues.PhaseNumber = filterArgs.value<int32>(k_PhaseNumber_Key);
inputValues.RemoveBiasedFeatures = filterArgs.value<bool>(k_RemoveBiasedFeatures_Key);
inputValues.UseSeed = filterArgs.value<bool>(k_SetRandomSeed_Key);
inputValues.SeedValue = filterArgs.value<uint64>(k_SeedValue_Key);
inputValues.SeedValue = seed;
inputValues.EquivalentDiametersArrayPath = filterArgs.value<DataPath>(k_EquivalentDiametersArrayPath_Key);
inputValues.FeaturePhasesArrayPath = filterArgs.value<DataPath>(k_FeaturePhasesArrayPath_Key);
inputValues.CentroidsArrayPath = filterArgs.value<DataPath>(k_CentroidsArrayPath_Key);
Expand Down
Loading
Loading