Skip to content

Commit

Permalink
[NBKCoreKit] Euclidean algorithm model.
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Oct 30, 2023
1 parent d3b894d commit b4a8586
Show file tree
Hide file tree
Showing 3 changed files with 460 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,64 +34,43 @@ extension NBK.ProperBinaryInteger {
extension NBK.ProperBinaryInteger where Integer: NBKSignedInteger {

//=------------------------------------------------------------------------=
// MARK: Utilities
// MARK: Utilities x Euclidean Algorithm
//=------------------------------------------------------------------------=

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
///
/// It extends the Euclidean algorithm and returns some additional values.
///
/// ### Result
///
/// ```swift
/// precondition(0 ... T.min.magnitude ~= result)
/// ```
///
/// - Note: The GCD of `0` and `0` is `0`.
/// [algorithm]: https://en.wikipedia.org/wiki/euclidean_algorithm
///
/// - Note: The GCD of `0` and `X` is `X`.
///
/// - Note: The GCD of `Int.min` and `Int.min` is `Int.min.magnitude`.
///
/// ### Bézout's identity
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm100(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Void, Void> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// ```swift
/// precondition(T(bitPattern: result) == lhs &* lhsCoefficient &+ rhs &* rhsCoefficient)
/// ```
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
///
/// ### Quotients of dividing by GCD
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm110(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Integer, Void> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// ```swift
/// guard !result.isZero, result <= T.max else { return }
/// precondition(lhsQuotient == lhs / T(result))
/// precondition(rhsQuotient == rhs / T(result))
/// ```
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
///
/// ### Iteration
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm101(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Void, Integer> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// ```swift
/// let lhsCoefficientSign = lhs.isLessThanZero != iteration.isOdd
/// let rhsCoefficientSign = rhs.isLessThanZero == iteration.isOdd
/// ```
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
///
@inlinable public static func greatestCommonDivisorByExtendedEuclideanAlgorithm(of lhs: Integer, and rhs: Integer)
-> (result: Integer.Magnitude, lhsCoefficient: Integer, rhsCoefficient: Integer, lhsQuotient: Integer, rhsQuotient: Integer, iteration: Integer.Magnitude) {
//=--------------------------------------=
let lhsIsLessThanZero: Bool = lhs.isLessThanZero
let rhsIsLessThanZero: Bool = rhs.isLessThanZero
//=--------------------------------------=
let unsigned = Magnitude.greatestCommonDivisorByExtendedEuclideanAlgorithm(of: lhs.magnitude, and: rhs.magnitude)
let odd = unsigned.iteration.isOdd as Bool
//=--------------------------------------=
return (
result: unsigned.result as Integer.Magnitude,
lhsCoefficient: Integer(sign: lhsIsLessThanZero != odd ? .minus : .plus, magnitude: unsigned.lhsCoefficient)!,
rhsCoefficient: Integer(sign: rhsIsLessThanZero == odd ? .minus : .plus, magnitude: unsigned.rhsCoefficient)!,
lhsQuotient: Integer(sign: lhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.lhsQuotient )!,
rhsQuotient: Integer(sign: rhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.rhsQuotient )!,
iteration: unsigned.iteration as Integer.Magnitude)
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm111(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Integer, Integer> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}
}

Expand All @@ -102,7 +81,7 @@ extension NBK.ProperBinaryInteger where Integer: NBKSignedInteger {
extension NBK.ProperBinaryInteger where Integer: NBKUnsignedInteger {

//=------------------------------------------------------------------------=
// MARK: Utilities
// MARK: Utilities x Binary Algorithm
//=------------------------------------------------------------------------=

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
Expand Down Expand Up @@ -137,6 +116,53 @@ extension NBK.ProperBinaryInteger where Integer: NBKUnsignedInteger {
return lhs as Integer.Magnitude
}

//=------------------------------------------------------------------------=
// MARK: Utilities x Euclidean Algorithm
//=------------------------------------------------------------------------=

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// [algorithm]: https://en.wikipedia.org/wiki/euclidean_algorithm
///
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm100(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Void, Void> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
///
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm110(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Integer, Void> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
///
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm101(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Void, Integer> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
///
@inlinable public static func greatestCommonDivisorByEuclideanAlgorithm111(
of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm<Integer, Integer, Integer> {
NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs)
}
}

//*============================================================================*
// MARK: * NBK x Proper Binary Integer x Greatest Common Divisor x E.E.A
//*============================================================================*

extension NBK {

/// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm].
///
/// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm
Expand Down Expand Up @@ -178,22 +204,196 @@ extension NBK.ProperBinaryInteger where Integer: NBKUnsignedInteger {
/// let rhsCoefficientSign = rhs.isLessThanZero == iteration.isOdd
/// ```
///
@inlinable public static func greatestCommonDivisorByExtendedEuclideanAlgorithm(of lhs: Integer, and rhs: Integer)
-> (result: Integer, lhsCoefficient: Integer, rhsCoefficient: Integer, lhsQuotient: Integer, rhsQuotient: Integer, iteration: Integer) {
@frozen public struct GreatestCommonDivisorByEuclideanAlgorithm<X, Y, Z> where X: NBKBinaryInteger {

/// The main integer's magnitude type.
public typealias I = X.Magnitude

//=--------------------------------------------------------------------=
// MARK: State
//=--------------------------------------------------------------------=

@usableFromInline var i: ((I))
@usableFromInline var x: (I,I)
@usableFromInline var y: (Y,Y)
@usableFromInline var z: (Z,Z)

//=--------------------------------------------------------------------=
// MARK: Accessors
//=--------------------------------------------------------------------=

@inlinable public var iteration: I {
self.i
}

@inlinable public var result: I {
self.x.0
}

@inlinable public var lhsCoefficient: Y {
self.y.0
}

@inlinable public var rhsQuotient: Y {
self.y.1
}

@inlinable public var rhsCoefficient: Z {
self.z.0
}

@inlinable public var lhsQuotient: Z {
self.z.1
}
}
}
//=----------------------------------------------------------------------------=
// MARK: + Integer, Void, Void
//=----------------------------------------------------------------------------=

extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == Void, Z == Void {

//=------------------------------------------------------------------------=
// MARK: Initializers
//=------------------------------------------------------------------------=

@inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger {
//=--------------------------------------=
let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm<I, Void, Void>(of: lhs.magnitude, and: rhs.magnitude)
//=--------------------------------------=
self.i = unsigned.i
self.x = unsigned.x
}

@inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger {
self.i = (00000000)
self.x = (lhs, rhs)

reduce: while !(self.x.1.isZero) {
self.i += 0001 as X.Digit
self.x.0 %= self.x.1
Swift.swap(&self.x.0, &self.x.1)
}
}
}

//=----------------------------------------------------------------------------=
// MARK: + Integer, Integer, Void
//=----------------------------------------------------------------------------=

extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == X, Z == Void {

//=------------------------------------------------------------------------=
// MARK: Initializers
//=------------------------------------------------------------------------=

@inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger {
//=--------------------------------------=
let lhsIsLessThanZero: Bool = lhs.isLessThanZero
let rhsIsLessThanZero: Bool = rhs.isLessThanZero
//=--------------------------------------=
let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm<I, I, Void>(of: lhs.magnitude, and: rhs.magnitude)
let odd = unsigned.iteration.isOdd as Bool
//=--------------------------------------=
self.i = unsigned.i
self.x = unsigned.x
//=--------------------------------------=
self.y.0 = Y(sign: lhsIsLessThanZero != odd ? .minus : .plus, magnitude: unsigned.y.0)!
self.y.1 = Y(sign: rhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.y.1)!
}

@inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger {
self.i = (00000000)
self.x = (lhs, rhs)
self.y = (001, 000)

reduce: while !self.x.1.isZero {
let division = self.x.0.quotientAndRemainder(dividingBy: self.x.1)
self.i += (000000000000001) as X.Digit
self.x = (self.x.1, division.remainder)
self.y = (self.y.1, division.quotient * self.y.1 + self.y.0)
}
}
}

//=----------------------------------------------------------------------------=
// MARK: + Integer, Void, Integer
//=----------------------------------------------------------------------------=

extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == Void, Z == X {

//=------------------------------------------------------------------------=
// MARK: Initializers
//=------------------------------------------------------------------------=

@inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger {
//=--------------------------------------=
let lhsIsLessThanZero: Bool = lhs.isLessThanZero
let rhsIsLessThanZero: Bool = rhs.isLessThanZero
//=--------------------------------------=
var (a, b) = (lhs, rhs) as (Integer,Integer)
var (c, d) = (001, 000) as (Integer,Integer)
var (e, f) = (000, 001) as (Integer,Integer)
var iteration = 0000000 as (((((Integer)))))
let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm<I, Void, I>(of: lhs.magnitude, and: rhs.magnitude)
let odd = unsigned.iteration.isOdd as Bool
//=--------------------------------------=
self.i = unsigned.i
self.x = unsigned.x
//=--------------------------------------=
while !b.isZero {
let division = a.quotientAndRemainder(dividingBy: b)
(a, b) = (b, division.remainder)
(c, d) = (d, division.quotient * d + c)
(e, f) = (f, division.quotient * f + e)
iteration += 000000001 as Integer.Digit
self.z.0 = Z(sign: rhsIsLessThanZero == odd ? .minus : .plus, magnitude: unsigned.z.0)!
self.z.1 = Z(sign: lhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.z.1)!
}

@inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger {
self.i = (00000000)
self.x = (lhs, rhs)
self.z = (000, 001)

reduce: while !self.x.1.isZero {
let division = self.x.0.quotientAndRemainder(dividingBy: self.x.1)
self.i += (000000000000001) as X.Digit
self.x = (self.x.1, division.remainder)
self.z = (self.z.1, division.quotient * self.z.1 + self.z.0)
}
}
}

//=----------------------------------------------------------------------------=
// MARK: + Integer, Integer, Integer
//=----------------------------------------------------------------------------=

extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == X, Z == X {

//=------------------------------------------------------------------------=
// MARK: Initializers
//=------------------------------------------------------------------------=

@inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger {
//=--------------------------------------=
return (result: a, lhsCoefficient: c, rhsCoefficient: e, lhsQuotient: f, rhsQuotient: d, iteration: iteration)
let lhsIsLessThanZero: Bool = lhs.isLessThanZero
let rhsIsLessThanZero: Bool = rhs.isLessThanZero
//=--------------------------------------=
let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm<I, I, I>(of: lhs.magnitude, and: rhs.magnitude)
let odd = unsigned.iteration.isOdd as Bool
//=--------------------------------------=
self.i = unsigned.i
self.x = unsigned.x
//=--------------------------------------=
self.y.0 = Y(sign: lhsIsLessThanZero != odd ? .minus : .plus, magnitude: unsigned.y.0)!
self.y.1 = Y(sign: rhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.y.1)!
self.z.0 = Z(sign: rhsIsLessThanZero == odd ? .minus : .plus, magnitude: unsigned.z.0)!
self.z.1 = Z(sign: lhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.z.1)!
}

@inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger {
self.i = (00000000)
self.x = (lhs, rhs)
self.y = (001, 000)
self.z = (000, 001)

reduce: while !self.x.1.isZero {
let division = self.x.0.quotientAndRemainder(dividingBy: self.x.1)
self.i += (000000000000001) as X.Digit
self.x = (self.x.1, division.remainder)
self.y = (self.y.1, division.quotient * self.y.1 + self.y.0)
self.z = (self.z.1, division.quotient * self.z.1 + self.z.0)
}
}
}
Loading

0 comments on commit b4a8586

Please sign in to comment.