| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // W.Hormann, G.Derflinger: |
| // "Rejection-Inversion to Generate Variates |
| // from Monotone Discrete Distributions" |
| // http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz |
| |
| package rand |
| |
| import "math" |
| |
| // A Zipf generates Zipf distributed variates. |
| type Zipf struct { |
| r *Rand |
| imax float64 |
| v float64 |
| q float64 |
| s float64 |
| oneminusQ float64 |
| oneminusQinv float64 |
| hxm float64 |
| hx0minusHxm float64 |
| } |
| |
| func (z *Zipf) h(x float64) float64 { |
| return math.Exp(z.oneminusQ*math.Log(z.v+x)) * z.oneminusQinv |
| } |
| |
| func (z *Zipf) hinv(x float64) float64 { |
| return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v |
| } |
| |
| // NewZipf returns a [Zipf] variate generator. |
| // The generator generates values k ∈ [0, imax] |
| // such that P(k) is proportional to (v + k) ** (-s). |
| // Requirements: s > 1 and v >= 1. |
| func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf { |
| z := new(Zipf) |
| if s <= 1.0 || v < 1 { |
| return nil |
| } |
| z.r = r |
| z.imax = float64(imax) |
| z.v = v |
| z.q = s |
| z.oneminusQ = 1.0 - z.q |
| z.oneminusQinv = 1.0 / z.oneminusQ |
| z.hxm = z.h(z.imax + 0.5) |
| z.hx0minusHxm = z.h(0.5) - math.Exp(math.Log(z.v)*(-z.q)) - z.hxm |
| z.s = 1 - z.hinv(z.h(1.5)-math.Exp(-z.q*math.Log(z.v+1.0))) |
| return z |
| } |
| |
| // Uint64 returns a value drawn from the [Zipf] distribution described |
| // by the [Zipf] object. |
| func (z *Zipf) Uint64() uint64 { |
| if z == nil { |
| panic("rand: nil Zipf") |
| } |
| k := 0.0 |
| |
| for { |
| r := z.r.Float64() // r on [0,1] |
| ur := z.hxm + r*z.hx0minusHxm |
| x := z.hinv(ur) |
| k = math.Floor(x + 0.5) |
| if k-x <= z.s { |
| break |
| } |
| if ur >= z.h(k+0.5)-math.Exp(-math.Log(k+z.v)*z.q) { |
| break |
| } |
| } |
| return uint64(k) |
| } |