Download src/bob_rng.f90 from Snapkitty/sov-kernel-monster: direct link, hf CLI and curl.
- Browser
- Download file 7.01 kB
-
https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_rng.f90
- Command line
-
hf download hf://Snapkitty/sov-kernel-monster/src/bob_rng.f90
-
curl -L -o bob_rng.f90 https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_rng.f90
7.01 kB
| ! BOB Quantum Civilization Engine - Random Number Generation | |
| ! Module: bob_rng | |
| ! Purpose: Deterministic seeded pseudo-random number generation | |
| ! Standard: Fortran 2018 | |
| module bob_rng | |
| use bob_kinds | |
| use bob_errors | |
| implicit none | |
| private | |
| !> Random number generator state | |
| type, public :: bob_rng_state | |
| integer(i8) :: seed = 0_i8 | |
| integer(i8) :: state(4) = 0_i8 ! xoshiro256** state | |
| integer(i8) :: call_count = 0_i8 | |
| logical(lk) :: is_initialized = .false. | |
| contains | |
| procedure :: init => rng_init | |
| procedure :: uniform => rng_uniform | |
| procedure :: normal => rng_normal | |
| procedure :: integer_range => rng_integer_range | |
| procedure :: choice => rng_choice | |
| end type bob_rng_state | |
| public :: bob_rng_create | |
| public :: bob_rng_destroy | |
| public :: bob_rng_seed | |
| contains | |
| !> Initialize RNG with seed | |
| subroutine rng_init(this, seed) | |
| class(bob_rng_state), intent(inout) :: this | |
| integer(i8), intent(in) :: seed | |
| integer :: i | |
| this%seed = seed | |
| this%call_count = 0_i8 | |
| ! Initialize xoshiro256** state using splitmix64 | |
| this%state(1) = splitmix64(seed) | |
| this%state(2) = splitmix64(this%state(1)) | |
| this%state(3) = splitmix64(this%state(2)) | |
| this%state(4) = splitmix64(this%state(3)) | |
| this%is_initialized = .true. | |
| end subroutine rng_init | |
| !> Generate uniform random number in [0, 1) | |
| function rng_uniform(this) result(r) | |
| class(bob_rng_state), intent(inout) :: this | |
| real(wp) :: r | |
| integer(i8) :: bits | |
| if (.not. this%is_initialized) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "RNG not initialized", "rng_uniform") | |
| r = ZERO | |
| return | |
| end if | |
| bits = xoshiro256ss(this%state) | |
| this%call_count = this%call_count + 1 | |
| ! Convert to [0, 1) using upper 53 bits | |
| r = real(ishft(bits, -11), wp) * (ONE / real(ishft(1_i8, 53), wp)) | |
| call bob_clear_error() | |
| end function rng_uniform | |
| !> Generate normal random number (Box-Muller transform) | |
| function rng_normal(this, mean, stddev) result(r) | |
| class(bob_rng_state), intent(inout) :: this | |
| real(wp), intent(in), optional :: mean, stddev | |
| real(wp) :: r | |
| real(wp) :: u1, u2, z0 | |
| real(wp) :: mu, sigma | |
| mu = ZERO | |
| sigma = ONE | |
| if (present(mean)) mu = mean | |
| if (present(stddev)) sigma = stddev | |
| ! Box-Muller transform | |
| u1 = this%uniform() | |
| u2 = this%uniform() | |
| z0 = sqrt(-TWO * log(u1)) * cos(TWO * PI * u2) | |
| r = mu + sigma * z0 | |
| end function rng_normal | |
| !> Generate random integer in [min_val, max_val] | |
| function rng_integer_range(this, min_val, max_val) result(r) | |
| class(bob_rng_state), intent(inout) :: this | |
| integer(i8), intent(in) :: min_val, max_val | |
| integer(i8) :: r | |
| real(wp) :: u | |
| if (min_val > max_val) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "min_val > max_val", "rng_integer_range") | |
| r = min_val | |
| return | |
| end if | |
| u = this%uniform() | |
| r = min_val + int(u * real(max_val - min_val + 1, wp), i8) | |
| ! Clamp to range | |
| if (r > max_val) r = max_val | |
| call bob_clear_error() | |
| end function rng_integer_range | |
| !> Choose random element from array | |
| function rng_choice(this, array, n) result(idx) | |
| class(bob_rng_state), intent(inout) :: this | |
| integer(i8), intent(in) :: n | |
| integer(i8), intent(in) :: array(n) | |
| integer(i8) :: idx | |
| if (n <= 0) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "Array size must be positive", "rng_choice") | |
| idx = 0 | |
| return | |
| end if | |
| idx = this%integer_range(1_i8, n) | |
| call bob_clear_error() | |
| end function rng_choice | |
| !> xoshiro256** algorithm | |
| function xoshiro256ss(state) result(r) | |
| integer(i8), intent(inout) :: state(4) | |
| integer(i8) :: r, t | |
| ! result = rotl(state[1] * 5, 7) * 9 | |
| r = rotl64(state(2) * 5_i8, 7) * 9_i8 | |
| t = ishft(state(2), 17) | |
| state(3) = ieor(state(3), state(1)) | |
| state(4) = ieor(state(4), state(2)) | |
| state(2) = ieor(state(2), state(3)) | |
| state(1) = ieor(state(1), state(4)) | |
| state(3) = ieor(state(3), t) | |
| state(4) = rotl64(state(4), 45) | |
| end function xoshiro256ss | |
| !> Rotate left 64-bit integer | |
| function rotl64(x, k) result(r) | |
| integer(i8), intent(in) :: x | |
| integer, intent(in) :: k | |
| integer(i8) :: r | |
| r = ior(ishft(x, k), ishft(x, k - 64)) | |
| end function rotl64 | |
| !> splitmix64 for seeding | |
| function splitmix64(x) result(r) | |
| integer(i8), intent(in) :: x | |
| integer(i8) :: r, z | |
| z = x + int(z'9e3779b97f4a7c15', i8) | |
| z = ieor(z, ishft(z, -30)) * int(z'bf58476d1ce4e5b9', i8) | |
| z = ieor(z, ishft(z, -27)) * int(z'94d049bb133111eb', i8) | |
| r = ieor(z, ishft(z, -31)) | |
| end function splitmix64 | |
| !> C ABI: Create RNG | |
| function bob_rng_create(seed) result(rng_ptr) bind(C, name="bob_rng_create") | |
| use, intrinsic :: iso_c_binding | |
| integer(c_int64_t), value :: seed | |
| type(c_ptr) :: rng_ptr | |
| type(bob_rng_state), pointer :: rng | |
| allocate(rng) | |
| call rng%init(seed) | |
| rng_ptr = c_loc(rng) | |
| end function bob_rng_create | |
| !> C ABI: Destroy RNG | |
| subroutine bob_rng_destroy(rng_ptr) bind(C, name="bob_rng_destroy") | |
| use, intrinsic :: iso_c_binding | |
| type(c_ptr), value :: rng_ptr | |
| type(bob_rng_state), pointer :: rng | |
| if (.not. c_associated(rng_ptr)) return | |
| call c_f_pointer(rng_ptr, rng) | |
| deallocate(rng) | |
| end subroutine bob_rng_destroy | |
| !> C ABI: Seed RNG | |
| function bob_rng_seed(rng_ptr, seed) result(status) bind(C, name="bob_rng_seed") | |
| use, intrinsic :: iso_c_binding | |
| type(c_ptr), value :: rng_ptr | |
| integer(c_int64_t), value :: seed | |
| integer(c_int) :: status | |
| type(bob_rng_state), pointer :: rng | |
| if (.not. c_associated(rng_ptr)) then | |
| status = BOB_ERROR_INVALID_ARGUMENT | |
| return | |
| end if | |
| call c_f_pointer(rng_ptr, rng) | |
| call rng%init(seed) | |
| status = BOB_SUCCESS | |
| end function bob_rng_seed | |
| end module bob_rng | |
| ! Made with Bob | |