
Fast, deterministic integer permutations producing keyed, reversible bijections over ranges. Memory-efficient, invertible shuffles with cycle-walking, xor-shift-multiply mixing, seeded determinism, and full/unsigned domain support.
Fast, deterministic integer permutation library for Kotlin.
Shuffle or obfuscate large integer domains efficiently using bijective, reversible hash mixing.
Not intended for cryptographic use. Suitable for data masking, sampling, and reproducible pseudo-randomization where reversibility is required. You decide if your use-case is cryptographic.
kpermute generates stable, deterministic pseudo-random permutations over
integer ranges. Each seed defines a unique bijection between [0, size).
The result acts like a keyed shuffle, repeatable, memory-efficient, and invertible.
Typical use cases:
Add the dependency from Maven Central:
implementation("com.eignex:kpermute:1.1.2")val idPerm = longPermutation(seed = 1L)
val longId = 49102490812045L
val encoded = idPerm.encode(longId)
println("encoded: $encoded (always prints 3631103739497407856)")val largeList = object : AbstractList<Int>() {
override val size: Int get() = Int.MAX_VALUE
override fun get(index: Int) = index
}
val perm = intPermutation(largeList.size)
val shuffled = largeList.permuted(perm)
println("shuffled: ${shuffled.take(20)}")
val unshuffled = shuffled.unpermuted(perm)
println("unshuffled: ${unshuffled.take(20)}")val rangePerm = intPermutation(-100..199)
println("encode(-50): ${rangePerm.encode(-50)}")
println("decode(...): ${rangePerm.decode(rangePerm.encode(-50))}")val fullPerm = intPermutation(-1, seed = 1L)
println(fullPerm.encode(0)) // 1339315335
println(fullPerm.encode(1)) // -897806455KPermute builds keyed, reversible permutations over integer domains using xor-shift-multiply mixers and cycle-walking. It never stores lookup tables and always supports decoding back to the original value.
Each permutation has a size:
size > 0 → finite domain [0, size)
size == -1 / -1L → full 32- or 64-bit domainsize < 0 (not -1) → unsigned variants via UIntPermutation /
ULongPermutation
Factory functions select implementations:
| Domain Type | Implementation | Description |
|---|---|---|
Tiny (≤16) |
Array[Int/Long]Permutation |
Uses shuffled array and inverse |
| Finite | Half[Int/Long]Permutation |
Uses cycle-walking |
| Full bit-width | Full[Int/Long]Permutation |
No cycle-walking |
| Unsigned variants | U[Int/Long]Permutation |
Modulo 2^32 or 2^64
|
Range factories like intPermutation(range) and longPermutation(range) wrap
these with a range(...) view, so you can permute directly on intervals such as
-100..199.
Each permutation round:
x ^= x >>> s) to diffuse bits.All steps are invertible using modular inverses and xor-shift
inversion 1 3 4 5.
For non-power-of-two domains, KPermute uses cycle-walking 1 2: permute
in
the next power-of-two space and retry until the output falls in [0, size).
Fast, deterministic integer permutation library for Kotlin.
Shuffle or obfuscate large integer domains efficiently using bijective, reversible hash mixing.
Not intended for cryptographic use. Suitable for data masking, sampling, and reproducible pseudo-randomization where reversibility is required. You decide if your use-case is cryptographic.
kpermute generates stable, deterministic pseudo-random permutations over
integer ranges. Each seed defines a unique bijection between [0, size).
The result acts like a keyed shuffle, repeatable, memory-efficient, and invertible.
Typical use cases:
Add the dependency from Maven Central:
implementation("com.eignex:kpermute:1.1.2")val idPerm = longPermutation(seed = 1L)
val longId = 49102490812045L
val encoded = idPerm.encode(longId)
println("encoded: $encoded (always prints 3631103739497407856)")val largeList = object : AbstractList<Int>() {
override val size: Int get() = Int.MAX_VALUE
override fun get(index: Int) = index
}
val perm = intPermutation(largeList.size)
val shuffled = largeList.permuted(perm)
println("shuffled: ${shuffled.take(20)}")
val unshuffled = shuffled.unpermuted(perm)
println("unshuffled: ${unshuffled.take(20)}")val rangePerm = intPermutation(-100..199)
println("encode(-50): ${rangePerm.encode(-50)}")
println("decode(...): ${rangePerm.decode(rangePerm.encode(-50))}")val fullPerm = intPermutation(-1, seed = 1L)
println(fullPerm.encode(0)) // 1339315335
println(fullPerm.encode(1)) // -897806455KPermute builds keyed, reversible permutations over integer domains using xor-shift-multiply mixers and cycle-walking. It never stores lookup tables and always supports decoding back to the original value.
Each permutation has a size:
size > 0 → finite domain [0, size)
size == -1 / -1L → full 32- or 64-bit domainsize < 0 (not -1) → unsigned variants via UIntPermutation /
ULongPermutation
Factory functions select implementations:
| Domain Type | Implementation | Description |
|---|---|---|
Tiny (≤16) |
Array[Int/Long]Permutation |
Uses shuffled array and inverse |
| Finite | Half[Int/Long]Permutation |
Uses cycle-walking |
| Full bit-width | Full[Int/Long]Permutation |
No cycle-walking |
| Unsigned variants | U[Int/Long]Permutation |
Modulo 2^32 or 2^64
|
Range factories like intPermutation(range) and longPermutation(range) wrap
these with a range(...) view, so you can permute directly on intervals such as
-100..199.
Each permutation round:
x ^= x >>> s) to diffuse bits.All steps are invertible using modular inverses and xor-shift
inversion 1 3 4 5.
For non-power-of-two domains, KPermute uses cycle-walking 1 2: permute
in
the next power-of-two space and retry until the output falls in [0, size).