Program Listing for File random.h

Return to documentation for file (src/VALfiles/random.h)

/************************************************************************
 * Copyright 2008, Strathclyde Planning Group,
 * Department of Computer and Information Sciences,
 * University of Strathclyde, Glasgow, UK
 * http://planning.cis.strath.ac.uk/
 *
 * Maria Fox, Richard Howey and Derek Long - VAL
 * Stephen Cresswell - PDDL Parser
 *
 * This file is part of VAL, the PDDL validator.
 *
 * VAL is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * VAL 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 VAL.  If not, see <http://www.gnu.org/licenses/>.
 *
 ************************************************************************/


/******************************************************************************
 *
 *  random.h
 *
 *  Header file for random number generator class declarations and definitions.
 *
 *  This header file does not depend on any of the other VecMat files, and it
 *  can be used independently of the rest of the software.
 *
 ******************************************************************************
 *
 *  VecMat Software, version 1.05
 *  By Kevin Dolan (2002)
 *  kdolan@mailaps.org
 *
 *****************************************************************************/

#include <cmath>
#include <ctime>

#ifndef __RANDOM_H
#define __RANDOM_H

namespace VAL {

// These classes must use 32 bit integers. If int is not 32 bit for your
// compiler, then replace the following typedefs with a type that is.
typedef unsigned int UINT32;
typedef int          INT32;

static const UINT32 CM_   = 69069;
static const UINT32 CA_   = 1234567;
static const UINT32 MASK_ = 65535;
static const UINT32 MWC1_ = 36939;
static const UINT32 MWC2_ = 18000;

class BaseGen
// Generate uniformly distributed unsigned 32 bit integers on the closed
// interval (0, 2^32 - 1).
{
protected:
    mutable UINT32 z_, w_, jsr_, jc_;

public:
    BaseGen(UINT32 seed = 0)
    {
        if (!seed) seed = static_cast<UINT32>(time(0));
        jc_  = seed;
        z_   = (jc_ = CM_ * jc_ + CA_);
        w_   = (jc_ = CM_ * jc_ + CA_);
        jsr_ = (jc_ = CM_ * jc_ + CA_);
        jc_  = CM_ * jc_ + CA_;
    }

    BaseGen(const BaseGen& gen)
    {
        jc_  = gen();
        z_   = (jc_ = CM_ * jc_ + CA_);
        w_   = (jc_ = CM_ * jc_ + CA_);
        jsr_ = (jc_ = CM_ * jc_ + CA_);
        jc_  = CM_ * jc_ + CA_;
    }

    ~BaseGen() {;}

    BaseGen& operator=(const BaseGen& gen)
    {
        jc_  = gen();
        z_   = (jc_ = CM_ * jc_ + CA_);
        w_   = (jc_ = CM_ * jc_ + CA_);
        jsr_ = (jc_ = CM_ * jc_ + CA_);
        jc_  = CM_ * jc_ + CA_;
        return *this;
    }

    UINT32 operator()() const
    {
        z_    = MWC1_ * (z_ & MASK_) + (z_ >> 16);
        w_    = MWC2_ * (w_ & MASK_) + (w_ >> 16);
        jsr_ ^= (jsr_ << 17); jsr_ ^= (jsr_ >> 13); jsr_ ^= (jsr_ << 5);
        jc_   = CM_ * jc_ + CA_;
        return (((z_ << 16) + (w_ & MASK_)) ^ jc_) + jsr_;
    }
};


class IntGen
// Generate uniformly distributed integers from a closed interval.
{
protected:
    BaseGen gen_;
    INT32   low_, delta_, shift_;
    mutable UINT32 bit_, word_;
    UINT32  mask_;

public:
    explicit IntGen(UINT32 seed = 0, int a = 0, int b = 0) : gen_(seed)
    {
        if (a == b)
        {
            low_  = 0;
            delta_ = 1;
        }
        else
        {
            low_  = (a < b) ? a : b;
            delta_ = (a > b) ? a : b;
        }
        delta_ -= low_;
        shift_  = 0;
        mask_   = 1;
        while (INT32(mask_) <= delta_)
        {
            ++shift_;
            mask_ <<= 1;
        }
        bit_  = 0;
        word_ = gen_();
        --mask_;
    }

    IntGen(const IntGen& uni) : gen_(uni.gen_), low_(uni.low_), delta_(uni.delta_),
        shift_(uni.shift_), mask_(uni.mask_)
    {
        bit_  = 0;
        word_ = gen_();
    }

    ~IntGen() {;}

    int operator()() const
    {
        UINT32 val;
        do {
            val = word_ & mask_;
            word_ >>= shift_;


            bit_   += shift_;
            if (bit_ > 31)
            {
                bit_  = 0;
                word_ = gen_();
            }
        } while (INT32(val) > delta_);
        return low_ + val;
    }

    IntGen& operator=(const IntGen& uni)
    {
        low_   = uni.low_;
        delta_ = uni.delta_;
        gen_   = uni.gen_;
        shift_ = uni.shift_;
        bit_   = 0;
        word_  = gen_();
        mask_  = uni.mask_;
        return *this;
    }

    void set_range(int a = 0, int b = 0)
    {
        if (a == b)
        {
            low_   = 0;
            delta_ = 1;
        }
        else
        {
            low_   = (a < b) ? a : b;
            delta_ = (a > b) ? a : b;
        }
        delta_ -= low_;
        shift_  = 0;
        mask_   = 1;
        while (INT32(mask_) <= delta_)
        {
            ++shift_;
            mask_ <<= 1;
        }
        bit_  = 0;
        word_ = gen_();
        --mask_;
        return;
    }

    int low() const
    {
        return low_;
    }

    int high() const
    {
        return low_ + delta_;
    }
};


class UniformGen
// Generate uniformly distributed doubles from an open interval.
{
protected:
    BaseGen gen_;
    double  mean_, delta_;

public:

    explicit UniformGen(UINT32 seed = 0, double a = 0, double b = 0) : gen_(seed)
    {
        if (a == b)
        {
            mean_  = 0.5;
            delta_ = 0.5;
        }
        else
        {
            mean_  = (b + a) / 2.0;
            delta_ = fabs(b - a) / 2.0;
        }
        delta_ *= 4.656613e-10;
    }

    UniformGen(const UniformGen& uni) : gen_(uni.gen_), mean_(uni.mean_), delta_(uni.delta_) {;}

    ~UniformGen() {;}

    double operator()() const
    {
        return mean_ + static_cast<INT32>(gen_()) * delta_;
    }

    UniformGen& operator=(const UniformGen& uni)
    {
        mean_  = uni.mean_;
        delta_ = uni.delta_;
        gen_   = uni.gen_;
        return *this;
    }

    void set_range(double a = 0, double b = 0)
    {
        if (a == b)
        {
            mean_  = 0.5;
            delta_ = 0.5;
        }
        else
        {
            mean_  = (b + a) / 2.0;
            delta_ = fabs(b - a) / 2.0;
        }
        delta_ *= 4.656613e-10;
    }

    double low() const
    {
        return mean_ - delta_;
    }

    double high() const
    {
        return mean_ + delta_;
    }
};


class NormalGen
// Generate normally distributed random numbers, using the Monty Python method.
{
protected:
    BaseGen gen_;
    double  mean_, stdv_;


public:


    explicit NormalGen(UINT32 seed = 0, double m = 0, double v = 1) : gen_(seed),
        mean_(m), stdv_(v)
    {
        if (stdv_ < 0) stdv_ = - stdv_;
    }

    NormalGen(const NormalGen& nrm) : gen_(nrm.gen_), mean_(nrm.mean_),
        stdv_(nrm.stdv_) {;}

    ~NormalGen() {;}

    double operator()() const
    {
        double x, y, v;
        x = static_cast<INT32>(gen_()) * 1.167239e-9;
        if (fabs(x) < 1.17741) return (mean_ + stdv_ * x);
        y = gen_() * 2.328306e-10;
        if (log(y) < (0.6931472 - 0.5 * x * x)) return (mean_ + stdv_ * x);
        x = (x > 0) ? (0.8857913 * (2.506628 - x)) :
            (-0.8857913 * (2.506628 + x));
        if (log(1.8857913 - y) < (0.5718733 - 0.5 * x * x))
            return (mean_ + stdv_ * x);
        do
        {
            v = static_cast<INT32>(gen_()) * 4.656613e-10;
            x = -log(fabs(v)) * 0.3989423;
            y = -log(gen_() * 2.328306e-10);
        }
        while (y + y < x * x);
        return ((v > 0) ? (mean_ + stdv_ * (2.506628 + x)) :
            (mean_ + stdv_ * (-2.506628 - x)));
    }

    NormalGen& operator=(const NormalGen& nrm)
    {
        mean_ = nrm.mean_;
        stdv_ = nrm.stdv_;
        gen_  = nrm.gen_;
        return *this;
    }

    void set_range(double m = 0, double v = 1.0)
    {
        mean_ = m;
        stdv_ = v;
        if (stdv_ < 0) stdv_ = - stdv_;
    }

    double mean() const
    {
        return mean_;
    }

    double stdv() const
    {
        return stdv_;
    }


};

struct Generators
{
  static UniformGen randomNumberUniGenerator;
  static NormalGen randomNumberNormGenerator;
};


double getRandomNumberNormal();
double getRandomNumberUniform();
double getRandomNumberPsuedoNormal();

};

#endif