// Copyright (c) 2014 The mathutil Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mathutil // import "modernc.org/mathutil"

import (
	
	
	
)

// FC32 is a full cycle PRNG covering the 32 bit signed integer range.
// In contrast to full cycle generators shown at e.g. http://en.wikipedia.org/wiki/Full_cycle,
// this code doesn't produce values at constant delta (mod cycle length).
// The 32 bit limit is per this implementation, the algorithm used has no intrinsic limit on the cycle size.
// Properties include:
//	- Adjustable limits on creation (hi, lo).
//	- Positionable/randomly accessible (Pos, Seek).
//	- Repeatable (deterministic).
//	- Can run forward or backward (Next, Prev).
//	- For a billion numbers cycle the Next/Prev PRN can be produced in cca 100-150ns.
//	  That's like 5-10 times slower compared to PRNs generated using the (non FC) rand package.
type FC32 struct {
	cycle   int64     // On average: 3 * delta / 2, (HQ: 2 * delta)
	delta   int64     // hi - lo
	factors [][]int64 // This trades some space for hopefully a bit of speed (multiple adding vs multiplying).
	lo      int
	mods    []int   // pos % set
	pos     int64   // Within cycle.
	primes  []int64 // Ordered. ∏ primes == cycle.
	set     []int64 // Reordered primes (magnitude order bases) according to seed.
}

// NewFC32 returns a newly created FC32 adjusted for the closed interval [lo, hi] or an Error if any.
// If hq == true then trade some generation time for improved (pseudo)randomness.
func (,  int,  bool) ( *FC32,  error) {
	if  >  {
		return nil, fmt.Errorf("invalid range %d > %d", , )
	}

	if uint64()-uint64() > math.MaxUint32 {
		return nil, fmt.Errorf("range out of int32 limits %d, %d", , )
	}

	 := int64() - int64()
	// Find the primorial covering whole delta
	, ,  := int64(1), []int64{}, uint32(2)
	if  {
		++
	}
	for {
		 = append(, int64())
		 *= int64()
		if  >  {
			break
		}
		, _ = NextPrime()
	}

	// Adjust the set so n ∊ [delta, 2 * delta] (HQ: [delta, 3 * delta])
	// while keeping the cardinality of the set (correlates with the statistic "randomness quality")
	// at max, i.e. discard atmost one member.
	 := -1 // no candidate prime
	if  > 2*(+1) {
		for ,  := range  {
			 :=  / 
			if  < +1 {
				break
			}

			 =  // mark the highest candidate prime set index
		}
	}
	if  >= 0 { // shrink the inner cycle
		 =  / []
		 = delete(, )
	}
	 = &FC32{
		cycle:   ,
		delta:   ,
		factors: make([][]int64, len()),
		lo:      ,
		mods:    make([]int, len()),
		primes:  ,
	}
	.Seed(1) // the default seed should be always non zero
	return
}

// Cycle reports the length of the inner FCPRNG cycle.
// Cycle is atmost the double (HQ: triple) of the generator period (hi - lo + 1).
func ( *FC32) () int64 {
	return .cycle
}

// Next returns the first PRN after Pos.
func ( *FC32) () int {
	return .step(1)
}

// Pos reports the current position within the inner cycle.
func ( *FC32) () int64 {
	return .pos
}

// Prev return the first PRN before Pos.
func ( *FC32) () int {
	return .step(-1)
}

// Seed uses the provided seed value to initialize the generator to a deterministic state.
// A zero seed produces a "canonical" generator with worse randomness than for most non zero seeds.
// Still, the FC property holds for any seed value.
func ( *FC32) ( int64) {
	 := uint64()
	.set = mix(.primes, &)
	 := int64(1)
	for ,  := range .set {
		 := make([]int64, )
		 := int64(0)
		for  := range  {
			[] = 
			 += 
		}
		 *= 
		.factors[] = mix(, &)
	}
}

// Seek sets Pos to |pos| % Cycle.
func ( *FC32) ( int64) { //vet:ignore
	if  < 0 {
		 = -
	}
	 %= .cycle
	.pos = 
	for ,  := range .set {
		.mods[] = int( % )
	}
}

func ( *FC32) ( int) int {
	for { // avg loops per step: 3/2 (HQ: 2)
		 := int64(0)
		 := .pos
		 += int64()
		switch {
		case  < 0:
			 = .cycle - 1
		case  >= .cycle:
			 = 0
		}
		.pos = 
		for ,  := range .mods {
			 += 
			 := int(.set[])
			switch {
			case  < 0:
				 =  - 1
			case  >= :
				 = 0
			}
			.mods[] = 
			 += .factors[][]
		}
		if  <= .delta {
			return int() + .lo
		}
	}
}

func ( []int64,  int) ( []int64) {
	for ,  := range  {
		if  !=  {
			 = append(, )
		}
	}
	return
}

func ( []int64,  *uint64) ( []int64) {
	for len() != 0 {
		* = rol(*)
		 := int(* % uint64(len()))
		 = append(, [])
		 = delete(, )
	}
	return
}

func ( uint64) ( uint64) {
	 =  << 1
	if int64() < 0 {
		 |= 1
	}
	return
}

// FCBig is a full cycle PRNG covering ranges outside of the int32 limits.
// For more info see the FC32 docs.
// Next/Prev PRN on a 1e15 cycle can be produced in about 2 µsec.
type FCBig struct {
	cycle   *big.Int     // On average: 3 * delta / 2, (HQ: 2 * delta)
	delta   *big.Int     // hi - lo
	factors [][]*big.Int // This trades some space for hopefully a bit of speed (multiple adding vs multiplying).
	lo      *big.Int
	mods    []int    // pos % set
	pos     *big.Int // Within cycle.
	primes  []int64  // Ordered. ∏ primes == cycle.
	set     []int64  // Reordered primes (magnitude order bases) according to seed.
}

// NewFCBig returns a newly created FCBig adjusted for the closed interval [lo, hi] or an Error if any.
// If hq == true then trade some generation time for improved (pseudo)randomness.
func (,  *big.Int,  bool) ( *FCBig,  error) {
	if .Cmp() > 0 {
		return nil, fmt.Errorf("invalid range %d > %d", , )
	}

	 := big.NewInt(0)
	.Add(, ).Sub(, )

	// Find the primorial covering whole delta
	, , ,  := big.NewInt(1), []int64{}, big.NewInt(0), uint32(2)
	if  {
		++
	}
	for {
		 = append(, int64())
		.SetInt64(int64())
		.Mul(, )
		if .Cmp() > 0 {
			break
		}
		, _ = NextPrime()
	}

	// Adjust the set so n ∊ [delta, 2 * delta] (HQ: [delta, 3 * delta])
	// while keeping the cardinality of the set (correlates with the statistic "randomness quality")
	// at max, i.e. discard atmost one member.
	 := big.NewInt(1)
	.Add(, )
	 := big.NewInt(0)
	.Lsh(, 1)
	 := -1 // no candidate prime
	if .Cmp() > 0 {
		 := big.NewInt(0)
		for ,  := range  {
			.SetInt64()
			.Set()
			.Div(, )
			if .Cmp() < 0 {
				break
			}

			 =  // mark the highest candidate prime set index
		}
	}
	if  >= 0 { // shrink the inner cycle
		.SetInt64([])
		.Div(, )
		 = delete(, )
	}
	 = &FCBig{
		cycle:   ,
		delta:   ,
		factors: make([][]*big.Int, len()),
		lo:      ,
		mods:    make([]int, len()),
		pos:     big.NewInt(0),
		primes:  ,
	}
	.Seed(1) // the default seed should be always non zero
	return
}

// Cycle reports the length of the inner FCPRNG cycle.
// Cycle is atmost the double (HQ: triple) of the generator period (hi - lo + 1).
func ( *FCBig) () *big.Int {
	return .cycle
}

// Next returns the first PRN after Pos.
func ( *FCBig) () *big.Int {
	return .step(1)
}

// Pos reports the current position within the inner cycle.
func ( *FCBig) () *big.Int {
	return .pos
}

// Prev return the first PRN before Pos.
func ( *FCBig) () *big.Int {
	return .step(-1)
}

// Seed uses the provided seed value to initialize the generator to a deterministic state.
// A zero seed produces a "canonical" generator with worse randomness than for most non zero seeds.
// Still, the FC property holds for any seed value.
func ( *FCBig) ( int64) {
	 := uint64()
	.set = mix(.primes, &)
	 := big.NewInt(1)
	 := big.NewInt(0)
	 := big.NewInt(0)
	for ,  := range .set {
		 := make([]*big.Int, )
		.SetInt64(0)
		for  := range  {
			[] = big.NewInt(0)
			[].Set()
			.Add(, )
		}
		.SetInt64()
		.Mul(, )
		.factors[] = mixBig(, &)
	}
}

// Seek sets Pos to |pos| % Cycle.
func ( *FCBig) ( *big.Int) {
	.pos.Set()
	.pos.Abs(.pos)
	.pos.Mod(.pos, .cycle)
	 := big.NewInt(0)
	 := big.NewInt(0)
	for ,  := range .set {
		.SetInt64()
		.mods[] = int(.Mod(.pos, ).Int64())
	}
}

func ( *FCBig) ( int) ( *big.Int) {
	 = big.NewInt(0)
	 := big.NewInt(int64())
	for { // avg loops per step: 3/2 (HQ: 2)
		.pos.Add(.pos, )
		switch {
		case .pos.Sign() < 0:
			.pos.Add(.pos, .cycle)
		case .pos.Cmp(.cycle) >= 0:
			.pos.SetInt64(0)
		}
		for ,  := range .mods {
			 += 
			 := int(.set[])
			switch {
			case  < 0:
				 =  - 1
			case  >= :
				 = 0
			}
			.mods[] = 
			.Add(, .factors[][])
		}
		if .Cmp(.delta) <= 0 {
			.Add(, .lo)
			return
		}
		.SetInt64(0)
	}
}

func ( []*big.Int,  int) ( []*big.Int) {
	for ,  := range  {
		if  !=  {
			 = append(, )
		}
	}
	return
}

func ( []*big.Int,  *uint64) ( []*big.Int) {
	for len() != 0 {
		* = rol(*)
		 := int(* % uint64(len()))
		 = append(, [])
		 = deleteBig(, )
	}
	return
}