UNPKG

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

357 lines (343 loc) 10 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createFibonacciHeapClass = void 0; var _factory = require("../../utils/factory.js"); const name = 'FibonacciHeap'; const dependencies = ['smaller', 'larger']; const createFibonacciHeapClass = exports.createFibonacciHeapClass = /* #__PURE__ */(0, _factory.factory)(name, dependencies, _ref => { let { smaller, larger } = _ref; 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, 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; }, { isClass: true });