Skip to content

File randomgaussian.h

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

Go to the documentation of this file

#ifndef TEMPLAT_UTIL_RANDOM_RANDOMGAUSSIAN_H
#define TEMPLAT_UTIL_RANDOM_RANDOMGAUSSIAN_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 <iomanip>
#include <sstream>

#include "TempLat/util/random/randomuniform.h"

namespace TempLat
{
  MakeException(RandomGaussianWrongCallOrderException);
  template <typename T> class RandomGaussian
  {
    using INT = typename RandomUniform<T>::IntegerType;

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

    using IntegerType = INT;

    RandomGaussian(const std::string &seed) : mRandomUniform(seed) {}

    auto getSeed() const { return mRandomUniform.getSeed(); }
    auto getSeedString() const { return mRandomUniform.getSeedString(); }

    DEVICE_INLINE_FUNCTION
    auto getPair(INT r, INT c, INT g, bool real = false, bool unitary = false) const
    { // Even if this is not completely consistent with the name, it is convenient to be able to use this class to
      // generate numbers with a real gaussian distribution or uniformly on the unit disk.
      return getNextGaussianPair(r, c, g, real, unitary);
    }

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

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

    std::string saveState() const { return mRandomUniform.saveState(); }

    void loadState(const std::string &state) { mRandomUniform.loadState(state); }

  private:
    /* Put all member variables and private methods here. These may change arbitrarily. */
    RandomUniform<T> mRandomUniform;

    static constexpr T cTwoPi =
        6.2831853071795864769252867665590057683943387987502116419498891846156328125724179972560696506842341359642961730265646132941876892;

    DEVICE_INLINE_FUNCTION
    device::array<T, 2u> getNextGaussianPair(INT r, INT c, INT g, bool real = false, bool unitary = false) const
    { // Even if this is not completely consistent with the name, it is convenient to be able to use this class to
      // generate numbers with a real gaussian distribution or uniformly on the unit disk.

      const auto result = mRandomUniform.getPair(r, c, g);

      const T &r0 = result[0];
      const T &r1 = result[1];

      const T boxMullerR = unitary ? 1 : (r0 == 0 ? std::numeric_limits<T>::max() : device::sqrt(-2 * device::log(r0)));
      const T boxMullerTheta = real ? 0 : cTwoPi * r1;

      return device::array<T, 2u>{boxMullerR * device::cos(boxMullerTheta), boxMullerR * device::sin(boxMullerTheta)};
    }
  };
} // namespace TempLat

#endif