Skip to content

added msa to swiftgraph for pull request #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions Sources/SwiftGraph/Arbok/Data Structures/ActiveForest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import Foundation

internal final class ActiveForest<T> where T: AdditiveArithmetic & Comparable {
internal let co: CompressedTree<T>
internal var activeEdge: [FibonacciHeapNode<T>?] // for each node the active outgoing edge
internal var activeSets: [LinkedList<FibonacciHeapNode<T>>] // for each node on path the active set heap represented by the root list

init(co: CompressedTree<T>) {
self.co = co
self.activeEdge = .init(repeating: nil, count: co.size())
self.activeSets = []

// activeSets.reserveCapacity(co.size())

for _ in 0..<co.size() {
activeSets.append(LinkedList<FibonacciHeapNode>())
}
}

// MARK: - ACTIVE FORESTS METHODS

/// - Complexity: O(activeSets.count)
internal func mergeHeaps(_ lhs: Int, _ rhs: Int) {

let rhsList = self.activeSets[rhs]

self.activeSets[lhs].append(rhsList)
rhsList.removeAll()
}


/// - Complexity: O(α(n) · `self.activeEdge[edge].count` + Cost(`removeFromCurrentList(self.activeEdge[edge])` ,
/// where α(n) is the inverse Ackermann function. Approximately linear
internal func deleteActiveEdge(_ edge: Int) {
guard let vertex = self.activeEdge[edge] else { fatalError() }

vertex.children.forEach { child in
self.moveHome(child)
}

vertex.children.removeAll()

self.removeFromCurrentList(vertex)

self.activeEdge[edge] = nil

// delete v
}


internal func getMin(_ index: Int) -> Int {
var orderRep = [FibonacciHeapNode<T>?].init()

activeSets[index].forEach { v in
var vertex = v

vertex.isLoser = false

// vertex.children.count changes during the while loop
let _ = vertex.children.count() // Refresh vertex.children.underestimatedCount

while orderRep.count > vertex.children.underestimatedCount && orderRep[vertex.children.underestimatedCount] != nil {

guard var other = orderRep[vertex.children.underestimatedCount] else { fatalError() }

orderRep[vertex.children.underestimatedCount] = nil

if self.currentWeight(of: other) < self.currentWeight(of: vertex) {
swap(&vertex, &other)
}

#if DEBUG
assert(other.parent == nil)
#endif


other.list_it = vertex.children.append(other)
other.parent = vertex

#if DEBUG
assert(vertex !== other)
assert(other.list_it?.getOwner() === vertex.children)
#endif
}

orderRep.append(contentsOf: [FibonacciHeapNode?].init(
repeating: nil,
count: max(0, vertex.children.underestimatedCount+1 - orderRep.count)
))

orderRep[vertex.children.underestimatedCount] = vertex
}

activeSets[index].removeAll()

orderRep.forEach { vertex in
if let vertex = vertex {
vertex.list_it = activeSets[index].append(vertex)
}
}

#if DEBUG
assert(!activeSets[index].isEmpty)
#endif

let vMin = activeSets[index].min { lhs, rhs in
return self.currentWeight(of: lhs) < self.currentWeight(of: rhs)
}

#if DEBUG
assert(vMin != nil)
assert(co.find(vMin!.to) == index, "\(vMin!.to) expected in home heap \(index), found in \(co.find(vMin!.to)) instead")
assert(activeEdge[co.find(vMin!.from)] != nil)
assert(vMin! === activeEdge[co.find(vMin!.from)], "edge must be active!") // FIXME: It happened that activeEdge[co.find(vMin!.from)] == nil
#endif

return vMin!.id
}


internal func makeActive(from: Int, to: Int, weight: T, id: Int) {
let fromRep = co.find(from)

if activeEdge[fromRep] == nil {
activeEdge[fromRep] = FibonacciHeapNode(from: from, to: to, weight: weight, id: id)
moveHome(activeEdge[fromRep]!)
return
}

guard let vertex = activeEdge[fromRep] else { fatalError() }

#if DEBUG
assert(
weight + self.co.findValue(to) < self.currentWeight(of: vertex) ||
co.find(to) != co.find(vertex.to)
)
#endif

self.removeFromCurrentList(vertex)
vertex.to = to
vertex.weight = weight
vertex.id = id
vertex.from = from

self.moveHome(vertex)
}


// MARK: - FIBONACCI HEAP METHODS

/// - Complexity: O(α(n)), where α(n) is the inverse Ackermann function
internal func homeHeap(_ vertex: FibonacciHeapNode<T>) -> LinkedList<FibonacciHeapNode<T>> {
return activeSets[co.find(vertex.to)]
}

/// - Complexity: O(α(n)), where α(n) is the inverse Ackermann function
internal func moveHome(_ vertex: FibonacciHeapNode<T>) {
let home = self.homeHeap(vertex)


#if DEBUG
assert(!home.find(where: { node in
return node === vertex
}))
#endif

vertex.list_it = home.append(vertex)
vertex.parent = nil
}


/// - Complexity: O(α(n))·Cost(`loseChild(vertex.parent)`), where α(n) is the inverse Ackermann function
internal func loseChild(_ vertex: FibonacciHeapNode<T>) {
guard let parent = vertex.parent else { return }

if vertex.isLoser {
self.loseChild(parent)

#if DEBUG
assert(vertex.list_it?.getOwner() === vertex.parent?.children)
#endif

vertex.list_it?.removeFromOwnerList()
self.moveHome(vertex)
}

vertex.isLoser.toggle()
}


/// - Complexity: O( α(n) + n + m ) where `n = vertex.parent?.children.count` and `m = self.homeHeap(vertex).count`, and
/// α(n) is the inverse Ackermann function
internal func removeFromCurrentList(_ vertex: FibonacciHeapNode<T>) {
let list = vertex.parent != nil ? vertex.parent?.children : self.homeHeap(vertex)

#if DEBUG
// Assert that `list` contains the parameter `vertex`
assert(list != nil)
assert(vertex.list_it != nil)
assert(vertex.list_it?.getNode() != nil)

assert(list?.find { node in
return node === vertex
} ?? false)
#endif

list?.removeAll { edge in
return edge.id == vertex.id
}

if let parent = vertex.parent {
self.loseChild(parent)
vertex.parent = nil
}
}

/// - Complexity: O(α(n)), where α(n) is the inverse Ackermann function
internal func currentWeight(of vertex: FibonacciHeapNode<T>) -> T {
let retval = vertex.weight + self.co.findValue(vertex.to)

return retval
}
}
108 changes: 108 additions & 0 deletions Sources/SwiftGraph/Arbok/Data Structures/CompressedTree.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import Foundation

internal final class CompressedTree<T> where T: AdditiveArithmetic {
internal var parent: [Int]
internal var value: [T]

init(initialSize: Int) {
self.parent = [Int].init(repeating: -1, count: initialSize)
self.value = [T].init(repeating: T.zero, count: initialSize)
}


/// Finds the representative (alias, root) of the set that contains the element `element`.
///
/// - Parameter element: The index of the element to find the representative for.
/// - Returns: The index of the element that represents the set that contains `element`.
///
/// - Complexity: O(α(n)), where α(n) is the inverse Ackermann function
func find(_ element: Int) -> Int {
assert(element < parent.count)

if parent[element] < 0 {
return element
} else {
let root = find(parent[element])

if parent[element] != root {
value[element] += value[parent[element]]
}

parent[element] = root

return root
}
}

/// Increments the value of `element` by `T`.
///
/// - Parameter element: The index of the element to increment
/// - Parameter increment: The delta to increment the value of element of.
func addValue(_ element: Int, increment: T) {
value[find(element)] += increment
}


/// Determines the sum of the values associated with all the elements in the path from `root` of the set that contains `element` and `element` itself.
///
/// - Parameter element: The index of the element to find the path compression value for.
/// - Returns: Sum of the values from `find(element)` to `element`.
///
/// - Complexity: O(α(n)), where α(n) is the inverse Ackermann function
func findValue(_ element: Int) -> T {
let root = self.find(element)

return value[element] + (element != root ? value[root] : T.zero)
}


/// Performs the union by rank with path compression of the sets that contain `lhs` and `rhs` respectively, if they're not already in the same set.
///
/// - Parameter lhs: The index of an element in the first set to join.
/// - Parameter rhs: The index of an element in the second set to join.
///
/// - Returns `false` if `lhs` and `rhs` already belonged to the same set and the union didn't produce any effect, `true` otherwise.
/// - Complexity: O(α(n)), where α(n) is the inverse Ackermann function
@discardableResult func join(_ lhs: Int, _ rhs: Int) -> Bool {
var lhsRoot = self.find(lhs)
var rhsRoot = self.find(rhs)

if lhsRoot == rhsRoot {
return false
} else {
if parent[lhsRoot] > parent[rhsRoot] {
swap(&lhsRoot, &rhsRoot)
}

parent[lhsRoot] += parent[rhsRoot]
parent[rhsRoot] = lhsRoot
value[rhsRoot] -= value[lhsRoot]

return true
}
}


/// Tests wheter or not `lhs` and `rhs` belong to the same set.
///
/// - Parameter lhs: The index of the first element.
/// - Parameter rhs: The index of the second element.
///
/// - Returns `true` if `lhs` and `rhs` are part of the same set, `false` otherwise.
func same(_ lhs: Int, _ rhs: Int) -> Bool {
return find(lhs) == find(rhs)
}


/// Computes the size of the subset that contains `element`.
///
/// - Parameter element: The index of an element contained in the set to find the size for.
func size(_ element: Int) -> Int {
return -parent[find(element)]
}

/// Computes the size of this Disjoint Set Union, that is, the number of subsets.
func size() -> Int {
return self.parent.count
}
}
36 changes: 36 additions & 0 deletions Sources/SwiftGraph/Arbok/Data Structures/FibonacciHeapNode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Foundation

internal final class Weak<T> where T: AnyObject {
internal weak var wrappedValue: T?

init(wrappedValue: T? = nil) {
self.wrappedValue = wrappedValue
}
}

internal final class FibonacciHeapNode<T> where T: AdditiveArithmetic {
internal var from: Int
internal var to: Int
internal var weight: T
internal var id: Int

internal var parent: FibonacciHeapNode? = nil
internal var children: LinkedList = LinkedList<FibonacciHeapNode>()
internal var isLoser: Bool = false
internal var list_it: LinkedList<FibonacciHeapNode>.LinkedListIndex?
internal var superlists: [Weak<LinkedList<FibonacciHeapNode>>] = []

init(from: Int, to: Int, weight: T, id: Int) {
self.from = from
self.to = to
self.weight = weight
self.id = id
}
}


extension FibonacciHeapNode: CustomStringConvertible {
var description: String {
return "[\(from) ---\(weight)---> \(to)]"
}
}
Loading