UNPKG

speedy-vision

Version:

GPU-accelerated Computer Vision for JavaScript

143 lines (125 loc) 4.18 kB
/* * speedy-vision.js * GPU-accelerated Computer Vision for JavaScript * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * sorting-networks.js * Sorting Networks */ import { AbstractMethodError } from './errors'; /** * @typedef {Array<[number,number]>} Sortnet */ /** * An abstract Sorting Network * @abstract */ class SortingNetwork { /** * Generate a sequence of comparators for a * sorting network supporting n data points * @abstract * @param {number} n number of data points * @returns {Sortnet} */ static generate(n) { throw new AbstractMethodError(); } /** * Sort the given data points using this network * @template T * @param {T[]} data data points * @param {function(T, T): number} [cmp] comparator function, as in Array.prototype.sort() * @returns {T[]} sorted data */ static sort(data, cmp = ((a, b) => (+a) - (+b))) { const network = this.generate(data.length); for(const [a, b] of network) { if(cmp(data[a], data[b]) > 0) [ data[a], data[b] ] = [ data[b], data[a] ]; } return data; } } /** * An implementation of Batcher's Odd-Even Mergesort */ export class OddEvenMergesort extends SortingNetwork { /* A reference for this algorithm can be found at: https://www.inf.hs-flensburg.de/lang/algorithmen/sortieren/networks/oemen.htm The algorithm will work if the size of the input array is a power of 2. In order to extend the algorithm so that it works with arrays of any size - say it's n - we use a very simple idea: extend the input array so that its size becomes a power of 2. Set the new entries to infinity. Sort the extended array and return its first n elements. Any comparator [i,j] where j >= n is comparing some value with infinity, meaning that no exchange will need to take place. Therefore, [i,j] can be dropped from the network. */ /** * Generate a sequence of comparators for a * sorting network supporting n data points * @param {number} n number of data points * @returns {Sortnet} */ static generate(n) { const nextPot = 1 << Math.ceil(Math.log2(Math.max(n, 1))); return this._mergesort(n, [], 0, nextPot); } /** * Odd-Even Mergesort * @param {number} count number of data points * @param {Sortnet} net sorting network * @param {number} lo starting index * @param {number} n sequence length, a power of 2 * @returns {Sortnet} net */ static _mergesort(count, net, lo, n) { if(n > 1) { const m = n / 2; this._mergesort(count, net, lo, m); this._mergesort(count, net, lo + m, m); this._merge(count, net, lo, n, 1); } return net; } /** * Odd-Even Merge * @param {number} count number of data points * @param {Sortnet} net sorting network * @param {number} lo starting index * @param {number} n a power of 2 * @param {number} jmp a power of 2 */ static _merge(count, net, lo, n, jmp) { const dbljmp = jmp * 2; if(dbljmp < n) { this._merge(count, net, lo, n, dbljmp); // merge even subsequence this._merge(count, net, lo + jmp, n, dbljmp); // merge odd subsequence for(let i = lo + jmp; i + jmp < lo + n && i + jmp < count; i += dbljmp) net.push([i, i + jmp]); } else if(lo + jmp < count) net.push([lo, lo + jmp]); } }