mathjs
Version:
Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with dif
334 lines (315 loc) • 9.63 kB
JavaScript
function factory (type, config, load, typed) {
const smaller = load(require('../../function/relational/smaller'))
const larger = load(require('../../function/relational/larger'))
const oneOverLogPhi = 1.0 / Math.log((1.0 + Math.sqrt(5.0)) / 2.0)
/**
* Fibonacci Heap implementation, used interally for Matrix math.
* @class FibonacciHeap
* @constructor FibonacciHeap
*/
function FibonacciHeap () {
if (!(this instanceof FibonacciHeap)) { throw new SyntaxError('Constructor must be called with the new operator') }
// initialize fields
this._minimum = null
this._size = 0
}
/**
* Attach type information
*/
FibonacciHeap.prototype.type = 'FibonacciHeap'
FibonacciHeap.prototype.isFibonacciHeap = true
/**
* Inserts a new data element into the heap. No heap consolidation is
* performed at this time, the new node is simply inserted into the root
* list of this heap. Running time: O(1) actual.
* @memberof FibonacciHeap
*/
FibonacciHeap.prototype.insert = function (key, value) {
// create node
const node = {
key: key,
value: value,
degree: 0
}
// check we have a node in the minimum
if (this._minimum) {
// minimum node
const minimum = this._minimum
// update left & right of node
node.left = minimum
node.right = minimum.right
minimum.right = node
node.right.left = node
// update minimum node in heap if needed
if (smaller(key, minimum.key)) {
// node has a smaller key, use it as minimum
this._minimum = node
}
} else {
// set left & right
node.left = node
node.right = node
// this is the first node
this._minimum = node
}
// increment number of nodes in heap
this._size++
// return node
return node
}
/**
* Returns the number of nodes in heap. Running time: O(1) actual.
* @memberof FibonacciHeap
*/
FibonacciHeap.prototype.size = function () {
return this._size
}
/**
* Removes all elements from this heap.
* @memberof FibonacciHeap
*/
FibonacciHeap.prototype.clear = function () {
this._minimum = null
this._size = 0
}
/**
* Returns true if the heap is empty, otherwise false.
* @memberof FibonacciHeap
*/
FibonacciHeap.prototype.isEmpty = function () {
return this._size === 0
}
/**
* Extracts the node with minimum key from heap. Amortized running
* time: O(log n).
* @memberof FibonacciHeap
*/
FibonacciHeap.prototype.extractMinimum = function () {
// node to remove
const node = this._minimum
// check we have a minimum
if (node === null) { return node }
// current minimum
let minimum = this._minimum
// get number of children
let numberOfChildren = node.degree
// pointer to the first child
let x = node.child
// for each child of node do...
while (numberOfChildren > 0) {
// store node in right side
const tempRight = x.right
// remove x from child list
x.left.right = x.right
x.right.left = x.left
// add x to root list of heap
x.left = minimum
x.right = minimum.right
minimum.right = x
x.right.left = x
// set Parent[x] to null
x.parent = null
x = tempRight
numberOfChildren--
}
// remove node from root list of heap
node.left.right = node.right
node.right.left = node.left
// update minimum
if (node === node.right) {
// empty
minimum = null
} else {
// update minimum
minimum = node.right
// we need to update the pointer to the root with minimum key
minimum = _findMinimumNode(minimum, this._size)
}
// decrement size of heap
this._size--
// update minimum
this._minimum = minimum
// return node
return node
}
/**
* Removes a node from the heap given the reference to the node. The trees
* in the heap will be consolidated, if necessary. This operation may fail
* to remove the correct element if there are nodes with key value -Infinity.
* Running time: O(log n) amortized.
* @memberof FibonacciHeap
*/
FibonacciHeap.prototype.remove = function (node) {
// decrease key value
this._minimum = _decreaseKey(this._minimum, node, -1)
// remove the smallest
this.extractMinimum()
}
/**
* Decreases the key value for a heap node, given the new value to take on.
* The structure of the heap may be changed and will not be consolidated.
* Running time: O(1) amortized.
* @memberof FibonacciHeap
*/
function _decreaseKey (minimum, node, key) {
// set node key
node.key = key
// get parent node
const parent = node.parent
if (parent && smaller(node.key, parent.key)) {
// remove node from parent
_cut(minimum, node, parent)
// remove all nodes from parent to the root parent
_cascadingCut(minimum, parent)
}
// update minimum node if needed
if (smaller(node.key, minimum.key)) { minimum = node }
// return minimum
return minimum
}
/**
* The reverse of the link operation: removes node from the child list of parent.
* This method assumes that min is non-null. Running time: O(1).
* @memberof FibonacciHeap
*/
function _cut (minimum, node, parent) {
// remove node from parent children and decrement Degree[parent]
node.left.right = node.right
node.right.left = node.left
parent.degree--
// reset y.child if necessary
if (parent.child === node) { parent.child = node.right }
// remove child if degree is 0
if (parent.degree === 0) { parent.child = null }
// add node to root list of heap
node.left = minimum
node.right = minimum.right
minimum.right = node
node.right.left = node
// set parent[node] to null
node.parent = null
// set mark[node] to false
node.mark = false
}
/**
* Performs a cascading cut operation. This cuts node from its parent and then
* does the same for its parent, and so on up the tree.
* Running time: O(log n); O(1) excluding the recursion.
* @memberof FibonacciHeap
*/
function _cascadingCut (minimum, node) {
// store parent node
const parent = node.parent
// if there's a parent...
if (!parent) { return }
// if node is unmarked, set it marked
if (!node.mark) {
node.mark = true
} else {
// it's marked, cut it from parent
_cut(minimum, node, parent)
// cut its parent as well
_cascadingCut(parent)
}
}
/**
* Make the first node a child of the second one. Running time: O(1) actual.
* @memberof FibonacciHeap
*/
const _linkNodes = function (node, parent) {
// remove node from root list of heap
node.left.right = node.right
node.right.left = node.left
// make node a Child of parent
node.parent = parent
if (!parent.child) {
parent.child = node
node.right = node
node.left = node
} else {
node.left = parent.child
node.right = parent.child.right
parent.child.right = node
node.right.left = node
}
// increase degree[parent]
parent.degree++
// set mark[node] false
node.mark = false
}
function _findMinimumNode (minimum, size) {
// to find trees of the same degree efficiently we use an array of length O(log n) in which we keep a pointer to one root of each degree
const arraySize = Math.floor(Math.log(size) * oneOverLogPhi) + 1
// create list with initial capacity
const array = new Array(arraySize)
// find the number of root nodes.
let numRoots = 0
let x = minimum
if (x) {
numRoots++
x = x.right
while (x !== minimum) {
numRoots++
x = x.right
}
}
// vars
let y
// For each node in root list do...
while (numRoots > 0) {
// access this node's degree..
let d = x.degree
// get next node
const next = x.right
// check if there is a node already in array with the same degree
while (true) {
// get node with the same degree is any
y = array[d]
if (!y) { break }
// make one node with the same degree a child of the other, do this based on the key value.
if (larger(x.key, y.key)) {
const temp = y
y = x
x = temp
}
// make y a child of x
_linkNodes(y, x)
// we have handled this degree, go to next one.
array[d] = null
d++
}
// save this node for later when we might encounter another of the same degree.
array[d] = x
// move forward through list.
x = next
numRoots--
}
// Set min to null (effectively losing the root list) and reconstruct the root list from the array entries in array[].
minimum = null
// loop nodes in array
for (let i = 0; i < arraySize; i++) {
// get current node
y = array[i]
if (!y) { continue }
// check if we have a linked list
if (minimum) {
// First remove node from root list.
y.left.right = y.right
y.right.left = y.left
// now add to root list, again.
y.left = minimum
y.right = minimum.right
minimum.right = y
y.right.left = y
// check if this is a new min.
if (smaller(y.key, minimum.key)) { minimum = y }
} else { minimum = y }
}
return minimum
}
return FibonacciHeap
}
exports.name = 'FibonacciHeap'
exports.path = 'type'
exports.factory = factory