Skip to content

File randomuniform.h

File List > code_source > templat > include > TempLat > util > random > randomuniform.h

Go to the documentation of this file

#ifndef TEMPLAT_UTIL_RANDOM_RANDOMUNIFORM_H
#define TEMPLAT_UTIL_RANDOM_RANDOMUNIFORM_H

/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
   Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
   Released under the MIT license, see LICENSE.md. */

// File info: Main contributor(s): Wessel Valkenburg, Franz R. Sattler, Year: 2025

#include <cstdint>
#include <random>
#include <sstream>

#include "TempLat/util/hash/keccakhash.h"
#include "TempLat/parallel/device.h"
#include "TempLat/parallel/device_memory.h"

#include <Random123/philox.h>

namespace TempLat
{
  template <typename T, typename RNG = r123::Philox2x64> class RandomUniform
  {
    using INT = typename RNG::ctr_type::value_type;

  public:
    // Put public methods here. These should change very little over time.

    using IntegerType = INT;

    RandomUniform(const std::string &stringSeed)
        : mStringSeed(stringSeed), mHashSeed(KeccakHash::compute(stringSeed)),
          mSeed(static_cast<INT>((uint64_t)mHashSeed))
    {
    }

    std::string saveState() const
    {
      std::ostringstream oss;
      oss << *mStringSeed;
      return oss.str();
    }

    void loadState(const std::string &state)
    {
      // saveState() serializes the full seed string verbatim, so restore it whole -- do not use
      // operator>>, which would truncate a seed at the first whitespace.
      *mStringSeed = state;
      mHashSeed = KeccakHash::compute(*mStringSeed);
      mSeed = static_cast<INT>((uint64_t)mHashSeed);
    }

    auto getSeed() const { return mSeed; }

    const std::string &getSeedString() const { return *mStringSeed; }

    DEVICE_INLINE_FUNCTION
    T get(INT r, INT c, INT gen) const { return getPair(r, c, gen)[0]; }

    DEVICE_INLINE_FUNCTION
    device::array<T, 2> getPair(INT r, INT c, INT gen) const
    {
      const RNG rng;

      // create a counter and key for the generator
      const typename RNG::ctr_type counter = {{r, c}};
      const typename RNG::key_type key = {{mSeed + gen}};
      // draw a pair of numbers
      const typename RNG::ctr_type result = rng(counter, key);

      return {{integer_to_float(result[0]), integer_to_float(result[1])}};
    }

    template <typename R> DEVICE_INLINE_FUNCTION T integer_to_float(R value) const
    {
      return (static_cast<T>(value) - static_cast<T>(std::numeric_limits<R>::min())) /
             static_cast<T>(std::numeric_limits<R>::max());
    }

    friend bool operator==(const RandomUniform &a, const RandomUniform &b) { return a.getSeed() == b.getSeed(); }

    friend std::ostream &operator<<(std::ostream &ostream, const RandomUniform &pr)
    {
      ostream << "RandomUniform - seed string: \"" << pr.getSeedString() << "\" - seed value: " << pr.getSeed() << "\n";
      return ostream;
    }

  private:
    /* Put all member variables and private methods here. These may change arbitrarily. */
    device::memory::host_string mStringSeed;
    KeccakHash::ResultType mHashSeed;
    INT mSeed;
  };
} // namespace TempLat

#endif