UNPKG

3.51 kBJavaScriptView Raw
1import { factory } from '../../utils/factory'
2
3const name = 'Spa'
4const dependencies = ['addScalar', 'equalScalar', 'FibonacciHeap']
5
6export const createSpaClass = /* #__PURE__ */ factory(name, dependencies, ({ addScalar, equalScalar, FibonacciHeap }) => {
7 /**
8 * An ordered Sparse Accumulator is a representation for a sparse vector that includes a dense array
9 * of the vector elements and an ordered list of non-zero elements.
10 */
11 function Spa () {
12 if (!(this instanceof Spa)) { throw new SyntaxError('Constructor must be called with the new operator') }
13
14 // allocate vector, TODO use typed arrays
15 this._values = []
16 this._heap = new FibonacciHeap()
17 }
18
19 /**
20 * Attach type information
21 */
22 Spa.prototype.type = 'Spa'
23 Spa.prototype.isSpa = true
24
25 /**
26 * Set the value for index i.
27 *
28 * @param {number} i The index
29 * @param {number | BigNumber | Complex} The value at index i
30 */
31 Spa.prototype.set = function (i, v) {
32 // check we have a value @ i
33 if (!this._values[i]) {
34 // insert in heap
35 const node = this._heap.insert(i, v)
36 // set the value @ i
37 this._values[i] = node
38 } else {
39 // update the value @ i
40 this._values[i].value = v
41 }
42 }
43
44 Spa.prototype.get = function (i) {
45 const node = this._values[i]
46 if (node) { return node.value }
47 return 0
48 }
49
50 Spa.prototype.accumulate = function (i, v) {
51 // node @ i
52 let node = this._values[i]
53 if (!node) {
54 // insert in heap
55 node = this._heap.insert(i, v)
56 // initialize value
57 this._values[i] = node
58 } else {
59 // accumulate value
60 node.value = addScalar(node.value, v)
61 }
62 }
63
64 Spa.prototype.forEach = function (from, to, callback) {
65 // references
66 const heap = this._heap
67 const values = this._values
68 // nodes
69 const nodes = []
70 // node with minimum key, save it
71 let node = heap.extractMinimum()
72 if (node) { nodes.push(node) }
73 // extract nodes from heap (ordered)
74 while (node && node.key <= to) {
75 // check it is in range
76 if (node.key >= from) {
77 // check value is not zero
78 if (!equalScalar(node.value, 0)) {
79 // invoke callback
80 callback(node.key, node.value, this)
81 }
82 }
83 // extract next node, save it
84 node = heap.extractMinimum()
85 if (node) { nodes.push(node) }
86 }
87 // reinsert all nodes in heap
88 for (let i = 0; i < nodes.length; i++) {
89 // current node
90 const n = nodes[i]
91 // insert node in heap
92 node = heap.insert(n.key, n.value)
93 // update values
94 values[node.key] = node
95 }
96 }
97
98 Spa.prototype.swap = function (i, j) {
99 // node @ i and j
100 let nodei = this._values[i]
101 let nodej = this._values[j]
102 // check we need to insert indeces
103 if (!nodei && nodej) {
104 // insert in heap
105 nodei = this._heap.insert(i, nodej.value)
106 // remove from heap
107 this._heap.remove(nodej)
108 // set values
109 this._values[i] = nodei
110 this._values[j] = undefined
111 } else if (nodei && !nodej) {
112 // insert in heap
113 nodej = this._heap.insert(j, nodei.value)
114 // remove from heap
115 this._heap.remove(nodei)
116 // set values
117 this._values[j] = nodej
118 this._values[i] = undefined
119 } else if (nodei && nodej) {
120 // swap values
121 const v = nodei.value
122 nodei.value = nodej.value
123 nodej.value = v
124 }
125 }
126
127 return Spa
128}, { isClass: true })