Skip to content

Commit

Permalink
Cleanup and some signed arbitrary randomness fixes (#45).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Jul 26, 2024
1 parent 3bda393 commit ab296e7
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 44 deletions.
8 changes: 4 additions & 4 deletions Sources/CoreKit/BinaryInteger+Random.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,16 @@ extension BinaryInteger {
} else {
let divisor = Divisor<IX>(size: Element.self)
var division = index.division(divisor).unchecked()
// finite unsigned behavior
increment: if !Self.isSigned {

increment: do {
division.remainder &+= 1
guard division.remainder == divisor.value else { break increment }
division.quotient &+= 1
division.remainder = 0
}

let down = Shift<Element.Magnitude>(masking: division.remainder.complement())
let last = Element(raw: randomness.next(as: Element.Magnitude.self)).down(down)
let down = division.remainder.complement()
let last = Element(raw: randomness.next(as: Element.Magnitude.self)) &>> (((((((down)))))))
return Self.arbitrary(uninitialized: division.ceil().unchecked(), repeating: last.appendix) {
guard !$0.isEmpty else { return }
let lastIndex: IX = $0.count.decremented().unchecked()
Expand Down
13 changes: 6 additions & 7 deletions Sources/CoreKit/Randomness+Full.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,16 @@ extension Randomness {
//=------------------------------------------------------------------------=

/// Generates more randomness.
@inlinable internal mutating func systems<T>(as type: T.Type = T.self) -> T where T: UnsignedInteger {
guard let size = IX(size: T.self) else {
Swift.preconditionFailure(String.pleaseDoNotGenerateCodeForThisPath())
}

///
/// - Requires: The given `type` must be a systems integer.
///
@inlinable internal mutating func systems<T>(as type: T.Type = T.self) -> T where T: UnsignedInteger {
if T.size <= Element.size {
return T(load: self.next())
}

Swift.assert(size % IX(size: Element.self) == IX.zero)
let ratio = size.down(Shift(unchecked: UX(size: Element.self).ascending(Bit.zero)))
Swift.assert(IX(size: T.self)! % IX(size: Element.self) == IX.zero)
let ratio = IX(size: T.self)!.down(Shift(unchecked: UX(size: Element.self).ascending(Bit.zero)))
var random = T()

for index in Range(uncheckedBounds: (IX.zero, ratio)) {
Expand Down
6 changes: 2 additions & 4 deletions Sources/CoreKit/Randomness+Range.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ extension Randomness {
///
/// - Requires: The `limit` must not be infinite.
///
/// - Requires: The given `type` must be a arbitrary integer.
///
/// ### Algorithm
///
/// Systems integers use an adaptation of "Fast Random Integer Generation in
Expand All @@ -133,11 +135,7 @@ extension Randomness {
///
/// Arbitrary integers accept-reject random bit patterns.
///
///
@inline(never) @inlinable internal mutating func arbitrary<T>(upTo comparison: Signum, relativeTo limit: /* borrowing */ T) -> T where T: UnsignedInteger {
//=--------------------------------------=
precondition(T.isArbitrary, String.pleaseDoNotGenerateCodeForThisPath())
//=--------------------------------------=
if limit.isInfinite {
Swift.preconditionFailure(String.overflow())
}
Expand Down
9 changes: 0 additions & 9 deletions Sources/CoreKit/Stdlib/String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,4 @@ extension String {
) -> String {
"overflow in \(function) at \(file):\(line)"
}

/// A message describing the location of an unreachable error.
@inlinable package static func pleaseDoNotGenerateCodeForThisPath(
function: StaticString = #function,
file: StaticString = #file,
line: UInt = #line
) -> String {
"unreachable path taken in \(function) at \(file):\(line)"
}
}
2 changes: 1 addition & 1 deletion Sources/InfiniIntKit/InfiniInt+Comparison.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ extension InfiniInt {

@inlinable public borrowing func hash(into hasher: inout Hasher) {
self.withUnsafeBinaryIntegerElements {
hasher.combine(bytes: UnsafeRawBufferPointer($0.body.buffer()))
hasher.combine(bytes: $0.body.bytes())
hasher.combine($0.appendix)
}
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/InfiniIntKit/InfiniInt+Count.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ extension InfiniInt {
// MARK: Utilities
//=------------------------------------------------------------------------=

@inlinable public func count(_ bit: Bit) -> Count<IX> {
@inlinable public borrowing func count(_ bit: Bit) -> Count<IX> {
self.withUnsafeBinaryIntegerElements {
$0.count(bit)
}
}

@inlinable public func ascending(_ bit: Bit) -> Count<IX> {
@inlinable public borrowing func ascending(_ bit: Bit) -> Count<IX> {
self.withUnsafeBinaryIntegerElements {
$0.ascending(bit)
}
}

@inlinable public func descending(_ bit: Bit) -> Count<IX> {
@inlinable public borrowing func descending(_ bit: Bit) -> Count<IX> {
self.withUnsafeBinaryIntegerElements {
$0.descending(bit)
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/InfiniIntKit/InfiniInt+Division.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ extension InfiniInt {
// MARK: Transformations
//=------------------------------------------------------------------------=

@inlinable consuming public func quotient (_ divisor: consuming Divisor<Self>) -> Fallible<Self> {
@inlinable public consuming func quotient (_ divisor: consuming Divisor<Self>) -> Fallible<Self> {
self.division(divisor).map({ $0.quotient })
}

@inlinable consuming public func remainder(_ divisor: consuming Divisor<Self>) -> Self {
@inlinable public consuming func remainder(_ divisor: consuming Divisor<Self>) -> Self {
self.division(divisor).value.remainder
}

@inline(never) @inlinable consuming public func division(_ divisor: consuming Divisor<Self>) -> Fallible<Division<Self, Self>> {
@inline(never) @inlinable public consuming func division(_ divisor: consuming Divisor<Self>) -> Fallible<Division<Self, Self>> {
//=--------------------------------------=
let rhsAppendixIsSet = Bool(divisor.value.appendix)
//=--------------------------------------=
Expand Down
4 changes: 2 additions & 2 deletions Sources/InfiniIntKit/InfiniInt+Multiplication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import CoreKit
extension InfiniInt {

//=------------------------------------------------------------------------=
// MARK: Transformations
// MARK: Transformations x 1 by 1 as 1
//=------------------------------------------------------------------------=

@inline(never) @inlinable public borrowing func squared() -> Fallible<Self> {
Expand Down Expand Up @@ -123,7 +123,7 @@ extension InfiniInt {
// MARK: Transformations x 1 by 1 as 2
//=----------------------------------------------------------------------------=

@inlinable public borrowing func multiplication(_ other: borrowing Self) -> Doublet<Self> {
@inline(never) @inlinable public borrowing func multiplication(_ other: borrowing Self) -> Doublet<Self> {
if Self.isSigned {
let low = Magnitude(raw: self &* other)
let high = Self(repeating: low.appendix)
Expand Down
64 changes: 53 additions & 11 deletions Tests/UltimathnumTests/BinaryInteger+Random.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import TestKit

final class BinaryIntegerTestsOnRandom: XCTestCase {

//=----------------------------------------------------------------------------=
//=------------------------------------------------------------------------=
// MARK: Tests
//=----------------------------------------------------------------------------=
//=------------------------------------------------------------------------=

/// - Note: The bounds may be infinite, but not their distance.
func testRandomInRange() {
Expand Down Expand Up @@ -103,17 +103,59 @@ final class BinaryIntegerTestsOnRandom: XCTestCase {
let index = Shift<T.Magnitude>(Count(index))
let limit = IX(raw: index.value) + (T.isSigned ? 1 : 2)

for _ in 0 ..< 4 {
let r0 = T.random(through: index)
let r1 = T.random(through: index, using: &randomness)

for random in [r0, r1] {
Test().yay(random.entropy() >= Count(00001))
Test().yay(random.entropy() <= Count(limit))
Test().nay(random.isInfinite)
}
while true {
let random = T.random(through: index)
let entropy = random.entropy()
Test().yay(entropy >= Count(00001))
Test().yay(entropy <= Count(limit))
Test().nay(random.isInfinite)
guard entropy != Count(limit) else { break }
}

while true {
let random = T.random(through: index, using: &randomness)
let entropy = random.entropy()
Test().yay(entropy >= Count(00001))
Test().yay(entropy <= Count(limit))
Test().nay(random.isInfinite)
guard entropy != Count(limit) else { break }
}
}
}

for type in binaryIntegers {
whereIs(type, randomness: fuzzer)
}
}

func testRandomThroughBitIndexHasKnownBounds() {
func whereIs<T>(_ type: T.Type, randomness: consuming FuzzerInt) where T: BinaryInteger {
func check(_ index: Shift<T.Magnitude>, _ expectation: ClosedRange<T>) {
let middle = T.isSigned ? T.zero : ((expectation.upperBound / 2) + 1)

var min = false
var mid = false
var max = false

while !(min && mid && max) {
let random = T.random(through: index, using: &randomness)
guard expectation.contains(random) else { break }
if random == expectation.lowerBound { min = true }
if random == ((((((((middle)))))))) { mid = true }
if random == expectation.upperBound { max = true }
}

Test().yay(min && mid && max)
}

check(Shift(Count(0)), T.isSigned ? -001 ... 000 : 000 ... 001)
check(Shift(Count(1)), T.isSigned ? -002 ... 001 : 000 ... 003)
check(Shift(Count(2)), T.isSigned ? -004 ... 003 : 000 ... 007)
check(Shift(Count(3)), T.isSigned ? -008 ... 007 : 000 ... 015)
check(Shift(Count(4)), T.isSigned ? -016 ... 015 : 000 ... 031)
check(Shift(Count(5)), T.isSigned ? -032 ... 031 : 000 ... 063)
check(Shift(Count(6)), T.isSigned ? -064 ... 063 : 000 ... 127)
check(Shift(Count(7)), T.isSigned ? -128 ... 127 : 000 ... 255)
}

for type in binaryIntegers {
Expand Down

0 comments on commit ab296e7

Please sign in to comment.