#!/usr/bin/env python
"""
Xorshift Family Generators for HDC
HDC-compatible wrapper for Xorshift random number generation.
"""
import random
from typing import Any, Dict, List, Optional, Union
from pyhdc.generation.base import HDCGenerator
class XorshiftGenerator(HDCGenerator):
"""
Base class for Xorshift family generators.
Xorshift generators use XOR and shift operations for fast pseudorandom
number generation with good statistical properties.
"""
def __init__(
self,
state_size: int = 1,
word_bits: int = 64,
seed: Optional[Union[int, List[int]]] = None,
) -> None:
"""
Initialize Xorshift generator.
Args:
state_size: Number of words in state
word_bits: Bits per word (32 or 64)
seed: Optional seed (int or list of ints)
"""
self._state_size = state_size
self._word_bits = word_bits
self._word_mask = (1 << word_bits) - 1
super().__init__(seed)
def _configure_internal(self) -> None:
"""Configure the Xorshift state."""
if self._seed is None:
self._state = [
random.randint(1, self._word_mask) for _ in range(self._state_size)
]
elif isinstance(self._seed, int):
if self._seed == 0:
raise ValueError("Seed cannot be zero")
# Split integer seed into multiple words
self._state = []
for i in range(self._state_size):
word = (self._seed >> (i * self._word_bits)) & self._word_mask
if word == 0:
word = (self._seed % (self._word_mask - 1)) + 1
self._state.append(word)
elif isinstance(self._seed, list):
if len(self._seed) != self._state_size:
raise ValueError(f"Seed list must have {self._state_size} elements")
if all(s == 0 for s in self._seed):
raise ValueError("Seed cannot be all zeros")
self._state = [s & self._word_mask for s in self._seed]
else:
raise ValueError("Seed must be int, list of ints, or None")
self._initial_state = self._state.copy()
def _next_value(self) -> int:
"""Generate next value (implemented by subclasses)."""
raise NotImplementedError("Subclasses must implement _next_value")
def _next_bit(self) -> int:
"""Generate next bit."""
return self._next_value() & 1
def _next_word(self, word_size: int = 32) -> int:
"""Generate next word."""
if word_size <= self._word_bits:
return self._next_value() & ((1 << word_size) - 1)
else:
# Combine multiple outputs
result = 0
bits_collected = 0
while bits_collected < word_size:
value = self._next_value()
result |= value << bits_collected
bits_collected += self._word_bits
return result & ((1 << word_size) - 1)
def set_parameters(
self, seed: Optional[Union[int, List[int]]] = None, **kwargs
) -> None:
"""Set Xorshift parameters."""
if seed is not None:
self._seed = seed
self._configure_internal()
def get_parameters(self) -> Dict[str, Any]:
"""Get current parameters."""
return {
"state_size": self._state_size,
"word_bits": self._word_bits,
"seed": self._seed,
}
def reset(self) -> None:
"""Reset to initial state."""
self._state = self._initial_state.copy()
def get_state(self) -> List[int]:
"""Get current state."""
return self._state.copy()
[docs]
class Xorshift32Generator(XorshiftGenerator):
"""32-bit Xorshift generator with (13,17,5) parameters."""
def __init__(self, seed: Optional[int] = None) -> None:
"""Initialize Xorshift32."""
super().__init__(state_size=1, word_bits=32, seed=seed)
def _next_value(self) -> int:
"""Generate next 32-bit value."""
x = self._state[0]
x ^= (x << 13) & self._word_mask
x ^= (x >> 17) & self._word_mask
x ^= (x << 5) & self._word_mask
self._state[0] = x
return x
[docs]
class Xorshift64Generator(XorshiftGenerator):
"""64-bit Xorshift generator with (13,7,17) parameters."""
def __init__(self, seed: Optional[int] = None) -> None:
"""Initialize Xorshift64."""
super().__init__(state_size=1, word_bits=64, seed=seed)
def _next_value(self) -> int:
"""Generate next 64-bit value."""
x = self._state[0]
x ^= (x << 13) & self._word_mask
x ^= (x >> 7) & self._word_mask
x ^= (x << 17) & self._word_mask
self._state[0] = x
return x
[docs]
class Xorshift128Generator(XorshiftGenerator):
"""128-bit Xorshift generator (4 x 32-bit words)."""
def __init__(self, seed: Optional[Union[int, List[int]]] = None) -> None:
"""Initialize Xorshift128."""
super().__init__(state_size=4, word_bits=32, seed=seed)
def _next_value(self) -> int:
"""Generate next 32-bit value."""
t = self._state[3]
s = self._state[0]
self._state[3] = self._state[2]
self._state[2] = self._state[1]
self._state[1] = s
t ^= (t << 11) & self._word_mask
t ^= (t >> 8) & self._word_mask
t ^= s ^ ((s >> 19) & self._word_mask)
self._state[0] = t
return t
[docs]
class XorshiftPlusGenerator(XorshiftGenerator):
"""Xorshift+ generator with addition for improved low-bit randomness."""
def __init__(self, seed: Optional[Union[int, List[int]]] = None) -> None:
"""Initialize Xorshift+."""
super().__init__(state_size=2, word_bits=64, seed=seed)
def _next_value(self) -> int:
"""Generate next value using xorshift+ algorithm."""
x = self._state[0]
y = self._state[1]
self._state[0] = y
x ^= (x << 23) & self._word_mask
self._state[1] = (
x ^ y ^ ((x >> 17) & self._word_mask) ^ ((y >> 26) & self._word_mask)
)
return (self._state[1] + y) & self._word_mask
[docs]
class XorshiftStarGenerator(XorshiftGenerator):
"""Xorshift* generator with multiplication for better statistics."""
def __init__(self, seed: Optional[Union[int, List[int]]] = None) -> None:
"""Initialize Xorshift*."""
super().__init__(state_size=2, word_bits=64, seed=seed)
self._multiplier = 0x2545F4914F6CDD1D
def _next_value(self) -> int:
"""Generate next value using xorshift* algorithm."""
x = self._state[0]
y = self._state[1]
self._state[0] = y
x ^= (x << 23) & self._word_mask
self._state[1] = (
x ^ y ^ ((x >> 17) & self._word_mask) ^ ((y >> 26) & self._word_mask)
)
return (self._state[1] * self._multiplier) & self._word_mask
[docs]
class Xoshiro256StarStarGenerator(XorshiftGenerator):
"""Xoshiro256** - modern xorshift with excellent properties."""
def __init__(self, seed: Optional[Union[int, List[int]]] = None) -> None:
"""Initialize Xoshiro256**."""
super().__init__(state_size=4, word_bits=64, seed=seed)
def _rotl64(self, x: int, k: int) -> int:
"""Rotate 64-bit integer left."""
k &= 63
return ((x << k) | (x >> (64 - k))) & self._word_mask
def _next_value(self) -> int:
"""Generate next value using xoshiro256** algorithm."""
result = self._rotl64(self._state[1] * 5, 7) * 9
result &= self._word_mask
t = (self._state[1] << 17) & self._word_mask
self._state[2] ^= self._state[0]
self._state[3] ^= self._state[1]
self._state[1] ^= self._state[2]
self._state[0] ^= self._state[3]
self._state[2] ^= t
self._state[3] = self._rotl64(self._state[3], 45)
return result
[docs]
def jump(self) -> None:
"""Jump ahead by 2^128 steps."""
JUMP = [
0x180EC6D33CFD0ABA,
0xD5A61266F0C9392C,
0xA9582618E03FC9AA,
0x39ABDC4529B1661C,
]
s0 = s1 = s2 = s3 = 0
for jump_val in JUMP:
for b in range(64):
if jump_val & (1 << b):
s0 ^= self._state[0]
s1 ^= self._state[1]
s2 ^= self._state[2]
s3 ^= self._state[3]
self._next_value()
self._state[0] = s0
self._state[1] = s1
self._state[2] = s2
self._state[3] = s3
[docs]
class Xoroshiro128PlusGenerator(XorshiftGenerator):
"""Xoroshiro128+ - fast variant with 128-bit state."""
def __init__(self, seed: Optional[Union[int, List[int]]] = None) -> None:
"""Initialize Xoroshiro128+."""
super().__init__(state_size=2, word_bits=64, seed=seed)
def _rotl64(self, x: int, k: int) -> int:
"""Rotate 64-bit integer left."""
k &= 63
return ((x << k) | (x >> (64 - k))) & self._word_mask
def _next_value(self) -> int:
"""Generate next value using xoroshiro128+ algorithm."""
s0 = self._state[0]
s1 = self._state[1]
result = (s0 + s1) & self._word_mask
s1 ^= s0
self._state[0] = self._rotl64(s0, 24) ^ s1 ^ ((s1 << 16) & self._word_mask)
self._state[1] = self._rotl64(s1, 37)
return result
[docs]
def jump(self) -> None:
"""Jump ahead by 2^64 steps."""
JUMP = [0xDF900294D8F554A5, 0x170865DF4B3201FC]
s0 = s1 = 0
for jump_val in JUMP:
for b in range(64):
if jump_val & (1 << b):
s0 ^= self._state[0]
s1 ^= self._state[1]
self._next_value()
self._state[0] = s0
self._state[1] = s1
[docs]
class Xoroshiro128StarStarGenerator(XorshiftGenerator):
"""Xoroshiro128** - improved statistics over Plus variant."""
def __init__(self, seed: Optional[Union[int, List[int]]] = None) -> None:
"""Initialize Xoroshiro128**."""
super().__init__(state_size=2, word_bits=64, seed=seed)
def _rotl64(self, x: int, k: int) -> int:
"""Rotate 64-bit integer left."""
k &= 63
return ((x << k) | (x >> (64 - k))) & self._word_mask
def _next_value(self) -> int:
"""Generate next value using xoroshiro128** algorithm."""
s0 = self._state[0]
s1 = self._state[1]
result = self._rotl64(s0 * 5, 7) * 9
result &= self._word_mask
s1 ^= s0
self._state[0] = self._rotl64(s0, 24) ^ s1 ^ ((s1 << 16) & self._word_mask)
self._state[1] = self._rotl64(s1, 37)
return result
[docs]
class SplitMix64Generator(XorshiftGenerator):
"""SplitMix64 - good for seeding other generators."""
def __init__(self, seed: Optional[int] = None) -> None:
"""Initialize SplitMix64."""
super().__init__(state_size=1, word_bits=64, seed=seed)
self._gamma = 0x9E3779B97F4A7C15
def _next_value(self) -> int:
"""Generate next value using SplitMix64 algorithm."""
self._state[0] = (self._state[0] + self._gamma) & self._word_mask
z = self._state[0]
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9
z &= self._word_mask
z = (z ^ (z >> 27)) * 0x94D049BB133111EB
z &= self._word_mask
z = z ^ (z >> 31)
return z
# Utility for seeding complex generators
def splitmix64_seed(initial_seed: int, count: int) -> List[int]:
"""
Use SplitMix64 to generate multiple seed values.
Args:
initial_seed: Initial seed value
count: Number of seed values to generate
Returns:
List of seed values
"""
splitmix = SplitMix64Generator(initial_seed)
return splitmix.generate_words(count, 64)
# Predefined Xorshift configurations
[docs]
class CommonXorshiftGenerators:
"""Factory for common Xorshift configurations."""
@staticmethod
def fast_32bit(seed: Optional[int] = None) -> Xorshift32Generator:
"""Fast 32-bit generator for simple applications."""
return Xorshift32Generator(seed)
@staticmethod
def standard_64bit(seed: Optional[int] = None) -> Xorshift64Generator:
"""Standard 64-bit generator."""
return Xorshift64Generator(seed)
@staticmethod
def high_quality(seed: Optional[int] = None) -> Xoshiro256StarStarGenerator:
"""High-quality generator recommended for general use."""
if seed is None:
return Xoshiro256StarStarGenerator()
else:
seeds = splitmix64_seed(seed, 4)
return Xoshiro256StarStarGenerator(seeds)
@staticmethod
def fastest(seed: Optional[int] = None) -> Xoroshiro128PlusGenerator:
"""Fastest generator in the family."""
if seed is None:
return Xoroshiro128PlusGenerator()
else:
seeds = splitmix64_seed(seed, 2)
return Xoroshiro128PlusGenerator(seeds)
@staticmethod
def balanced(seed: Optional[int] = None) -> Xoroshiro128StarStarGenerator:
"""Balanced speed/quality generator."""
if seed is None:
return Xoroshiro128StarStarGenerator()
else:
seeds = splitmix64_seed(seed, 2)
return Xoroshiro128StarStarGenerator(seeds)
@staticmethod
def for_seeding(seed: Optional[int] = None) -> SplitMix64Generator:
"""Generator optimized for seeding other generators."""
return SplitMix64Generator(seed)
# Legacy aliases for backward compatibility
Xorshift = Xorshift64Generator
XorshiftStar64 = XorshiftStarGenerator
XorshiftPlus64 = XorshiftPlusGenerator