Example #1
0
SecureVector<byte>
ECDSA_Signature_Operation::sign(const byte msg[], size_t msg_len,
                                RandomNumberGenerator& rng)
   {
   rng.add_entropy(msg, msg_len);

   BigInt m(msg, msg_len);

   BigInt r = 0, s = 0;

   while(r == 0 || s == 0)
      {
      // This contortion is necessary for the tests
      BigInt k;
      k.randomize(rng, order.bits());

      while(k >= order)
         k.randomize(rng, order.bits() - 1);

      PointGFp k_times_P = base_point * k;
      r = mod_order.reduce(k_times_P.get_affine_x());
      s = mod_order.multiply(inverse_mod(k, order), mul_add(x, r, m));
      }

   SecureVector<byte> output(2*order.bytes());
   r.binary_encode(&output[output.size() / 2 - r.bytes()]);
   s.binary_encode(&output[output.size() - s.bytes()]);
   return output;
   }
    string SimulateRead(const SequencingParameters& p,
                        const std::string& tpl,
                        RandomNumberGenerator& rng)
    {
        std::string read;
        read.reserve(tpl.length() * 2);

        int pos = 0;
        while (pos < (int)tpl.length())
        {
            char base = tpl[pos];
            char prevBase = pos > 0 ? tpl[pos-1] : 'N';
            int channel = Channel(base);

            //
            // Tabulate the different possible move probabilities, then choose one
            //
            bool canMerge =  base == prevBase;
            vector<double> errorProbs = ErrorProbs(p, channel, canMerge);
            int choice = rng.RandomChoice(errorProbs);

            if (choice == (int) errorProbs.size() - 1) {  // Match
                read.push_back(base);
                pos++;

            } else if (choice < 4) {                     // Insert
                vector<double> insertProbs = vector<double>(errorProbs.begin(),
                                                            errorProbs.begin() + 4);
                int eChannel = rng.RandomChoice(insertProbs);
                char eBase = "TGAC"[eChannel];
                read.push_back(eBase);

            } else if (choice == 4) {                   // Dark
                pos++;

            } else if (choice == 5) {                   // Miscall
                read.push_back(rng.RandomBase());
                pos++;

            } else {                                   // Merge
                assert (canMerge);
                pos++;
            }
        }

        return read;
    }
static void test_stdnormal_sw(RandomNumberGenerator &rng) {
    vector<double> samples(SHAPIRO_WILK_DF);
    size_t i;

    for (i = 0; i < samples.size(); i++)
	samples[i] = rng.stdnormal();
    assert(shapiro_wilk_test(samples));
}
Example #4
0
void PolynomialMod2::Randomize(RandomNumberGenerator &rng, size_t nbits)
{
	const size_t nbytes = nbits/8 + 1;
	SecByteBlock buf(nbytes);
	rng.GenerateBlock(buf, nbytes);
	buf[0] = (byte)Crop(buf[0], nbits % 8);
	Decode(buf, nbytes);
}
Example #5
0
Ray PerspectiveCamera::generateRay(const Point2d &sample) const
{
	Point3d ori(0);
	Ray ray(ori, normalize(Vector3d(rasterToCamera_(Point3d(sample.x_, sample.y_, 0)))));

	if (focal_distance_ > 0) {
		static RandomNumberGenerator rng;
		Point2d tmp = Point2d(rng.Uniform2(), rng.Uniform2());
		ori = Point3d(tmp.x_, tmp.y_, 0) * radius_;
		double z = -(focal_distance_ / ray.direction().z_);
		Point3d hit(ray.direction() * z);
		ray.setDirection(normalize(hit - ori));
	}

	ray.setOrigin(cameraToWorld_(ori));
	return std::move(ray);
}
/// <summary>
/// Main Function
void TEST_RandomChar(RandomNumberGenerator& generator,RandomNumberGenerator::CharacterType characterType)
{
	char randomCharacter=generator.getRandomCharacter(characterType);
	
		cout << "SUCCESS : " << randomCharacter << endl;
	
	

}
static void test_uniform_integer(RandomNumberGenerator &rng) {
    vector<size_t> counts(PSI_DF);
    vector<double> probabilities(PSI_DF);
    size_t i;

    for (i = 0; i < probabilities.size(); i++)
        probabilities[i] = 1/static_cast<double>(PSI_DF);
    for (i = 0; i < NSAMPLES; i++)
        counts[rng.nexti(PSI_DF)]++;
    assert(psi_test(counts, probabilities, NSAMPLES));

    // Check that the psi test has sufficient statistical power to
    // detect the modulo bias.
    std::fill(counts.begin(), counts.end(), 0);
    for (i = 0; i < NSAMPLES; i++)
        counts[rng.nexti(2*PSI_DF + 1) % PSI_DF]++;
    assert(!psi_test(counts, probabilities, NSAMPLES));
}
Example #8
0
void testCosineDistribution()
{
    Plot2D plot_radial_hist( output_path + "/cosine_radial_hist.png", plot_size, plot_size );
    Plot2D plot_angle_hist( output_path + "/cosine_angle_hist.png", plot_size, plot_size, -0.5f * M_PI, 0.5f * M_PI );
    float x = 0.0f, y = 0.0f, z = 0.0f;

    // Build a histogram of random angles using a cosine distribution
    const int bins = 30;
    const float angle_range = 0.5f * M_PI;
    const float bin_width = angle_range / bins;
    int hist[bins] = {};

    for( auto i = 0; i < 1000000; i++ ) {
        float angle = rng.cosineQuarterWave();
        x = cosf( angle );
        y = sinf( angle );
        int bin = angle / angle_range * (bins - 1);
        hist[bin]++;
    }

    int *max_it = std::max_element( hist, hist + bins );
    int hist_max = *max_it;

    plot_radial_hist.drawAxes();
    plot_angle_hist.drawAxes();

    // Draw histogram bins
    plot_radial_hist.strokeColor( 1.0, 0.0, 0.0 );
    plot_angle_hist.strokeColor( 1.0, 0.0, 0.0 );
    for( auto i = 0; i < bins; i++ ) {
        float angle = (float) i / (bins - 1) * angle_range;
        float r = hist[i] / (float) hist_max;
        float x1 = cosf( angle ) * r;
        float y1 = sinf( angle ) * r;
        angle = (float) (i + 1) / (bins - 1) * angle_range;
        float x2 = cosf( angle ) * r;
        float y2 = sinf( angle ) * r;

        plot_radial_hist.drawLine( x1, y1, 0.0, 0.0 );
        plot_radial_hist.drawLine( x1, y1, x2, y2 );
        plot_radial_hist.drawLine( 0.0, 0.0, x2, y2 );
        plot_angle_hist.drawLine( angle, 0.0, angle, r );
        plot_angle_hist.drawLine( angle, r, angle + bin_width, r );
        plot_angle_hist.drawLine( angle + bin_width, r, angle + bin_width, 0.0 );
    }

    // Reference
    plot_angle_hist.strokeColor( 1.0, 0.0, 0.0 );
    for( auto i = 0; i < 100; i++ ) {
        float angle1 = (float) i / (bins - 1) * angle_range;
        float angle2 = (float) (i + 1) / (bins - 1) * angle_range;
        float r1 = cos(angle1);
        float r2 = cos(angle2);
        plot_angle_hist.drawLine( angle1, r1, angle2, r2 );
    }
}
Example #9
0
void testUniformCircle()
{
    Plot2D plot( output_path + "/random_circle.png", plot_size, plot_size );

    float x, y;
    for( auto i = 0; i < points_per_plot; i++ ) {
        rng.uniformUnitCircle( x, y );
        plot.addPoint( x, y );
    }
}
Example #10
0
void CECPQ1_offer(uint8_t send[CECPQ1_OFFER_BYTES],
                  CECPQ1_key* offer_key_output,
                  RandomNumberGenerator& rng)
   {
   offer_key_output->m_x25519 = rng.random_vec(32);
   curve25519_basepoint(send, offer_key_output->m_x25519.data());

   newhope_keygen(send + 32, &offer_key_output->m_newhope,
                  rng, Newhope_Mode::BoringSSL);
   }
Example #11
0
void testUniformSquare()
{
    Plot2D plot( output_path + "/random_square.png", plot_size, plot_size );

    for( auto i = 0; i < points_per_plot; i++ ) {
        float x = rng.uniformRange( -0.9, 0.9 );
        float y = rng.uniformRange( -0.9, 0.9 );
        plot.addPoint( x, y );
    }
}
Example #12
0
double FossilSafeScaleMove::doMove( void ) {
    
    // Get random number generator
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    double val = scaler->getValue();
    storedValue = val;
    
//    double min = scaler->getMin();
//    double max = scaler->getMax();
    
//    double size = max - min;
    
    double u      = std::exp( lambda * (rng->uniform01() - 0.5));
    double newVal = val * u;
    
    val = newVal;
    scaler->setValue( new double(val) );
    
    TimeTree& t = tree->getValue();
//    double rescale = storedValue / val;
    
    bool failed = false;
    std::vector<TopologyNode*> nodes = t.getNodes();
    
    for (size_t i = 0; i < fossilIdx.size(); i++)
    {
        const size_t nodeIdx = nodes[ fossilIdx[i] ]->getIndex();
        storedTipAges[nodeIdx] = t.getAge(nodeIdx);
        t.setAge( nodeIdx, tipAges[nodeIdx] / val );
        if ( tipAges[ nodeIdx ] > nodes[ nodeIdx ]->getParent().getAge() * val )
        {
            // reject: rescaled tree has negative branch lengths!
            // std::cout << "reject, negative brlen\n";
            failed = true;
        }
    }
    
    if (failed)
        return RbConstants::Double::neginf;
    
	return log(u);
}
Example #13
0
Animal::Animal() : Object(OBJ_TYPE_ANIMAL) {
    energy = 80.0;
    speed = 80.0;
    
    if (!samplesInitialized) {
        for (int i = 0; i < 16; i++) {
            voiceSamples[i] = 0;
        }
        samplesInitialized = true;
    }
    
    voice = dna.getVoice();
    RandomNumberGenerator *rng = RandomNumberGenerator::getInstance();
    voiceInterval = ((double) rng->getInt(500, 5000)) / 1000.0;
    addSensor(dna.getSightSensor());
    addSensor(dna.getDigestiveSystem());
    addSensor(dna.getHearingSensor());
    addSensor(dna.getNervousSystem());
}
Example #14
0
void testUniformSurfaceUnitHalfSphere()
{
    Plot2D plot( output_path + "/random_half_sphere.png", plot_size, plot_size );
    Vector4 dir( 1.0, 1.0, 1.0 ), v;

    for( auto i = 0; i < points_per_plot; i++ ) {
        rng.uniformSurfaceUnitHalfSphere( dir, v );
        plot.addPoint( v.x, v.y );
    }
}
Example #15
0
void testUniformVolumeUnitSphere()
{
    Plot2D plot( output_path + "/random_volume_sphere.png", plot_size, plot_size );
    float x = 0.0f, y = 0.0f, z = 0.0f;

    for( auto i = 0; i < points_per_plot; i++ ) {
        rng.uniformVolumeUnitSphere( x, y, z );
        plot.addPoint( x, y );
    }
}
Example #16
0
File: tss.cpp Project: louiz/botan
std::vector<RTSS_Share>
RTSS_Share::split(byte M, byte N,
                  const byte S[], u16bit S_len,
                  const byte identifier[16],
                  RandomNumberGenerator& rng)
   {
   if(M == 0 || N == 0 || M > N)
      throw Encoding_Error("RTSS_Share::split: M == 0 or N == 0 or M > N");

   SHA_256 hash; // always use SHA-256 when generating shares

   std::vector<RTSS_Share> shares(N);

   // Create RTSS header in each share
   for(byte i = 0; i != N; ++i)
      {
      shares[i].m_contents += std::make_pair(identifier, 16);
      shares[i].m_contents += rtss_hash_id(hash.name());
      shares[i].m_contents += M;
      shares[i].m_contents += get_byte(0, S_len);
      shares[i].m_contents += get_byte(1, S_len);
      }

   // Choose sequential values for X starting from 1
   for(byte i = 0; i != N; ++i)
      shares[i].m_contents.push_back(i+1);

   // secret = S || H(S)
   secure_vector<byte> secret(S, S + S_len);
   secret += hash.process(S, S_len);

   for(size_t i = 0; i != secret.size(); ++i)
      {
      std::vector<byte> coefficients(M-1);
      rng.randomize(coefficients.data(), coefficients.size());

      for(byte j = 0; j != N; ++j)
         {
         const byte X = j + 1;

         byte sum = secret[i];
         byte X_i = X;

         for(size_t k = 0; k != coefficients.size(); ++k)
            {
            sum ^= gfp_mul(X_i, coefficients[k]);
            X_i  = gfp_mul(X_i, X);
            }

         shares[j].m_contents.push_back(sum);
         }
      }

   return shares;
   }
/** Perform the move */
double SimplexSingleElementScale::performSimpleMove( void ) {
    
    // Get random number generator    
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    // get the current value
    std::vector<double>& value = variable->getValue();
    
    // store the value
    storedValue = value;
    
    // we need to know the number of categories
    size_t cats = value.size();
    
    // randomly draw a new index
    size_t chosenIndex = size_t( floor(rng->uniform01()*double(cats)) );
    double currentValue = value[chosenIndex];
    
    // draw new rates and compute the hastings ratio at the same time
    double a = alpha * currentValue + 1.0;
    double b = alpha * (1.0-currentValue) + 1.0;
    double new_value = RbStatistics::Beta::rv(a, b, *rng);
    
    // set the value
    value[chosenIndex] = new_value;
    
    // rescale
    double sum = 0;
	for(size_t i=0; i<cats; i++) {
		sum += value[i];
    }
	for(size_t i=0; i<cats; i++)
		value[i] /= sum;
    
    // compute the Hastings ratio
    double forward = RbStatistics::Beta::lnPdf(a, b, new_value);
    double new_a = alpha * value[chosenIndex] + 1.0;
    double new_b = alpha * (1.0-value[chosenIndex]) + 1.0;
    double backward = RbStatistics::Beta::lnPdf(new_a, new_b, currentValue);
    
    return backward - forward;
}
Example #18
0
/*!
 * This function generates a Poisson-distributed random variable using
 * the ratio-of-uniforms rejectin method.
 *
 * \brief Poisson random variables using the ratio-of-uniforms method.
 * \param lambda is the rate parameter of the Poisson.
 * \return Returns a Poisson-distributed random variable.
 * \throws Does not throw an error.
 * \see Stadlober, E. 1990. The ratio of uniforms approach for generating
 *      discrete random variates. Journal of Computational and Applied
 *      Mathematics 31:181-189.
 */
int RbStatistics::Helper::poissonRatioUniforms(double lambda, RandomNumberGenerator& rng) {

    static double p_L_last = -1.0;  /* previous L */
    static double p_a;              /* hat center */
    static double p_h;              /* hat width */
    static double p_g;              /* ln(L) */
    static double p_q;              /* value at mode */
    static int p_bound;             /* upper bound */
    int mode;                       /* mode */
    double u;                       /* uniform random */
    double lf;                      /* ln(f(x)) */
    double x;                       /* real sample */
    int k;                          /* integer sample */

    if (p_L_last != lambda) {
        p_L_last = lambda;
        p_a = lambda + 0.5;
        mode = (int)lambda;
        p_g  = log(lambda);
        p_q = mode * p_g - RbMath::lnFactorial(mode);
        p_h = sqrt(2.943035529371538573 * (lambda + 0.5)) + 0.8989161620588987408;
        p_bound = (int)(p_a + 6.0 * p_h);
    }

    while(1) {
        u = rng.uniform01();
        if (u == 0.0)
            continue;
        x = p_a + p_h * (rng.uniform01() - 0.5) / u;
        if (x < 0 || x >= p_bound)
            continue;
        k = (int)(x);
        lf = k * p_g - RbMath::lnFactorial(k) - p_q;
        if (lf >= u * (4.0 - u) - 3.0)
            break;
        if (u * (u - lf) > 1.0)
            continue;
        if (2.0 * log(u) <= lf)
            break;
    }
    return(k);
}
static void test_uniform01(RandomNumberGenerator &rng) {
    vector<size_t> counts(PSI_DF);
    vector<double> probabilities(PSI_DF);
    size_t i;

    for (i = 0; i < probabilities.size(); i++)
        probabilities[i] = 1/static_cast<double>(PSI_DF);
    for (i = 0; i < NSAMPLES; i++)
        counts[static_cast<size_t>(floor(rng.next()*PSI_DF))]++;
    assert(psi_test(counts, probabilities, NSAMPLES));
}
Example #20
0
int main( int argc, char ** argv ) {
    
    double a = 0.8;
    
    const bool runInserts = true;
    bool runDeletes = true;
    
    const uint64_t ngen = 2;
    const uint64_t ninserts = uint64_t( a * double( m*n ) );
    
    table = new bool[ m*n ];
    indices = new uint64_t[ ninserts ];

    memset(   table, 0, m*n*sizeof( bool ) );
    memset( indices, 0, ninserts*sizeof( uint64_t ) );
    
    load = 0ULL;
    uint64_t u = 0ULL;

    if( runInserts ) {
        for( uint64_t i = 0ULL; i < ninserts; i++ ) {

            indices[ i ] = Insert();
        
            if( i % (ninserts/10) == 0ULL ) {
                cout << "i = " << SETDEC( 10 ) << i << ", load = " << load << endl;
            }
            u++;
        }
    }
    
    if( runDeletes ) {
        for( uint64_t i = 0ULL; i < (m*n*ngen); i++ ) {
            
            // delete:
            const uint64_t delIdx = rng.RandU64() % u;
            Delete( indices[ delIdx ] );
        
            indices[ delIdx ] = Insert();

            if( i % (m*n/10) == 0ULL ) {
                cout << "i = " << SETDEC( 10 ) << i << ", load = " << load << endl;
            }
        }
    }
    
    const uint64_t keys_over = u - load;
    const double o = double( keys_over ) / (m*n);
    
    cout << "keys inserted: " << u << endl;
    cout << "keys in table: " << load << endl;
    cout << "keys overflow: " << keys_over << endl;
    cout << "overflow pcnt: " << (100*o) << endl;
}
TEST(ComplexMatrixIOTest,ThousandByThousandMatirx) {
	ComplexMatrix cm(1000,1000);
	RandomNumberGenerator random;
	for (int i=0; i<cm.GetRows(); ++i) {
		for (int j=0; j<cm.GetCols(); ++j) {
			cm(i,j) = random.randomComplex();
		}
	}
	complexMatrixToBytes(cm,"cm.bin");
	ComplexMatrix cm2;
	bytesToComplexMatrix(cm2, "cm.bin");
	EXPECT_EQ(cm.GetRows(), cm2.GetRows());
	EXPECT_EQ(cm.GetCols(), cm2.GetCols());
	for (int i=0; i<cm.GetRows(); ++i) {
		for (int j=0; j<cm.GetCols(); ++j) {
			EXPECT_DOUBLE_EQ(cm(i,j).real, cm2(i,j).real);
			EXPECT_DOUBLE_EQ(cm(i,j).imag, cm2(i,j).imag);
		}
	}
}
Example #22
0
void testUniformConeDirection()
{
    Plot2D plot( output_path + "/random_cone.png", plot_size, plot_size );
    Vector4 dir( 1.0, 1.0, 1.0 ), v;
    const float angle = 0.3f;

    for( auto i = 0; i < points_per_plot; i++ ) {
        rng.uniformConeDirection( dir, angle, v );
        plot.addPoint( v.x, v.y );
    }
}
void SphereEmitter::Emit(const float gameTime, 
		const unsigned int availableIndiceCount, physx::PxParticleCreationData& creationData)
{
	unsigned int emissionCount(GetEmissionCount(gameTime, availableIndiceCount));

	//If we have creation data and indices can be used
	if(emissionCount > 0)
	{
		//reset forces
		forces.clear();
		positions.clear();

		RandomNumberGenerator* random = RandomNumberGenerator::GetInstance();
		
		//Generate initial force and update available indices
		for (unsigned int i = 0; i < emissionCount; i++)
		{
			float ranSpeed = random->GenerateRandom(minSpeed, maxSpeed);

			physx::PxVec3 ranDirection = physx::PxVec3(
				random->GenerateRandom(minimumDirection.x, maximumDirection.x),
				random->GenerateRandom(minimumDirection.y, maximumDirection.y),
				random->GenerateRandom(minimumDirection.z, maximumDirection.z));

			if(EmitFromShell)
				positions.push_back(position + (ranDirection * Radius));
			else
				positions.push_back(position + (ranDirection * random->GenerateRandom(0.0f, Radius)));

			if(TowardsSphereCenter)
				forces.push_back(-ranDirection * ranSpeed);
			else
				forces.push_back(ranDirection * ranSpeed);
		}

		//set creation data parameters
		creationData.numParticles = emissionCount;
		creationData.positionBuffer = physx::PxStrideIterator<physx::PxVec3>(&positions[0]);
		creationData.velocityBuffer = physx::PxStrideIterator<physx::PxVec3>(&forces[0]);
	}
}
Example #24
0
/**
 * Simulate new speciation times.
 */
double MultiRateBirthDeathProcess::simulateDivergenceTime(double origin, double present) const
{
    
    // Get the rng
    RandomNumberGenerator* rng = GLOBAL_RNG;
    
    // get the parameters
    double age = present - origin;
    double b = lambda->getValue()[0];
    double d = mu->getValue()[0];
    double rho = 1.0;
    
    // get a random draw
    double u = rng->uniform01();
    
    // compute the time for this draw
    double t = ( log( ( (b-d) / (1 - (u)*(1-((b-d)*exp((d-b)*age))/(rho*b+(b*(1-rho)-d)*exp((d-b)*age) ) ) ) - (b*(1-rho)-d) ) / (rho * b) ) + (d-b)*age )  /  (d-b);
    
    
    return present - t;
}
Example #25
0
/**
* Gather entropy from SecRandomCopyBytes
*/
size_t Darwin_SecRandom::poll(RandomNumberGenerator& rng)
   {
   secure_vector<uint8_t> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);

   if(0 == SecRandomCopyBytes(kSecRandomDefault, buf.size(), buf.data()))
      {
      rng.add_entropy(buf.data(), buf.size());
      return buf.size() * 8;
      }

   return 0;
   }
double RbStatistics::Logistic::rv(double location, double scale, RandomNumberGenerator& rng) {

    if (scale == 0){
        return (location);

    }
    else{

        double u = rng.uniform01();
        return location + scale * log(u / (1. - u));
    }
}
Example #27
0
/**
* Gather 256 bytes entropy from getentropy(2).  Note that maximum
* buffer size is limited to 256 bytes.  On OpenBSD this does neither
* block nor fail.
*/
size_t Getentropy::poll(RandomNumberGenerator& rng)
   {
   secure_vector<uint8_t> buf(256);

   if(::getentropy(buf.data(), buf.size()) == 0)
      {
      rng.add_entropy(buf.data(), buf.size());
      return buf.size() * 8;
      }

   return 0;
   }
/**
 * Perform the proposal.
 *
 * A scaling Proposal draws a random uniform number u ~ unif(-0.5,0.5)
 * and Slides the current vale by a scaling factor
 * sf = exp( lambda * u )
 * where lambda is the tuning parameter of the Proposal to influence the size of the proposals.
 *
 * \return The hastings ratio.
 */
double VectorFixedSingleElementSlideProposal::doProposal( void )
{
    
    // Get random number generator
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    RbVector<double> &val = variable->getValue();
    
    // copy value
    storedValue = val[index];
    
    // Generate new value (no reflection, so we simply abort later if we propose value here outside of support)
    double u = rng->uniform01();
    double delta  = ( lambda * ( u - 0.5 ) );
    
    val[index] += delta;
    
    variable->addTouchedElementIndex(index);
    
    return 0.0;
}
Example #29
0
// TEMP - trying to see if i can uniformly generate a random number on a triangle
//        This works.
// TODO - try to generalize this to any triangle
void testBasicTriangle2D()
{
    Plot2D plot( output_path + "/test_basic_triangle_2d.png", plot_size, plot_size,
                 -0.1, 1.1, -0.1, 1.1 );

    float x, y;
    for( auto i = 0; i < points_per_plot; i++ ) {
        rng.uniformUnitTriangle2D( x, y );

        plot.addPoint( x, y );
    }
}
Example #30
0
/** Perform the move */
double SubtreeScale::performSimpleMove( void ) {
    
    // Get random number generator    
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    TimeTree& tau = variable->getValue();
    
    // pick a random node which is not the root and neither the direct descendant of the root
    TopologyNode* node;
    do {
        double u = rng->uniform01();
        size_t index = size_t( std::floor(tau.getNumberOfNodes() * u) );
        node = &tau.getNode(index);
    } while ( node->isRoot() || node->isTip() );
    
    TopologyNode& parent = node->getParent();
    
    // we need to work with the times
    double parent_age  = parent.getAge();
    double my_age      = node->getAge();
    
    // now we store all necessary values
    storedNode = node;
    storedAge = my_age;
        
    // draw new ages and compute the hastings ratio at the same time
    double my_new_age = parent_age * rng->uniform01();
    
    double scalingFactor = my_new_age / my_age;
    
    size_t nNodes = node->getNumberOfNodesInSubtree(false);
    
    // rescale the subtrees
    TreeUtilities::rescaleSubtree(&tau, node, scalingFactor );
    
    // compute the Hastings ratio
    double lnHastingsratio = (nNodes > 1 ? log( scalingFactor ) * (nNodes-1) : 0.0 );
    
    return lnHastingsratio;
}