I tried to parallelize each chunk to speed up the process and this is my for loop
for (let m = 0; m < keyCountMap.length; m += 2) {
fetchWorker.postMessage([nodePages, keyCountMap]);
// console.log(m, keyCountMap[m], keyCountMap.length);
let myRoot = nodePages[keyCountMap[m]];
const view = await Copc.loadPointDataView(filename, copc, myRoot);
let getters = ["X", "Y", "Z", "Intensity"].map(view.getter);
let chunkCount = 2;
let totalCalled = 0;
for (let j = 0; j < keyCountMap[m + 1]; j += chunkCount) {
let remaining = keyCountMap[m + 1] - totalCalled;
let localChunkCount = Math.min(chunkCount, remaining);
totalCalled += localChunkCount;
const pointTemp = new Array(localChunkCount).fill(null);
const promises = pointTemp.map((element, index) =>
readPoints(index + j, getters)
);
const done = await Promise.all(promises);
}
}
and
const readPoints = (id, getters) => {
return new Promise((resolve, reject) => {
let returnPoint = getXyzi(id, getters);
positions.push(
returnPoint[0] - x_min - 0.5 * width,
returnPoint[1] - y_min - 0.5 * width,
returnPoint[2] - z_min - 0.5 * width
);
const vx = (returnPoint[3] / 65535) * 255;
color.setRGB(vx, vx, vx);
colors.push(color.r, color.g, color.b);
return resolve(true);
});
};
function getXyzi(index, getters) {
return getters.map((get) => get(index));
}
I think there is some error because I am not getting performance in execution time.
Can anyone please help me on figuring out what I am doing wrong?
My worker code:
Related
(https://codepen.io/johnslipper/details/eYgZMRL)
var context = new AudioContext();
let dampening = 1;
function pluck(frequency) {
var pluck = context.createScriptProcessor(4096, 0, 1);
var N = Math.round(context.sampleRate / frequency);
var y = new Float32Array(N);
for (let i = 0; i < N; i++) {if (window.CP.shouldStopExecution(0)) break;
y[i] = Math.random() * 2 - 1;
}
window.CP.exitedLoop(0);let n = 0;
pluck.onaudioprocess = function (e) {
var output = e.outputBuffer.getChannelData(0);
for (let i = 0; i < e.outputBuffer.length; i++) {if (window.CP.shouldStopExecution(1)) break;
y[n] = (y[n] + y[(n + 1) % N]) / 2;
output[i] = y[n];
y[n] *= dampening;
n++;
if (n >= N) n = 0;
}window.CP.exitedLoop(1);
};
var bandpass = context.createBiquadFilter();
bandpass.type = "bandpass";
bandpass.frequency.value = frequency;
bandpass.Q.value = 1;
pluck.connect(bandpass);
setTimeout(() => {
pluck.disconnect();
}, 2000);
setTimeout(() => {
bandpass.disconnect();
}, 2000);
return bandpass;
}
function strum(fret, stringCount = 6, stagger = 150) {
dampening = 1;
var dst = context.destination;
for (let index = 0; index < stringCount; index++) {if (window.CP.shouldStopExecution(2)) break;
if (Number.isFinite(fret[index])) {
setTimeout(() => {
pluck(getFrequency(index, fret[index])).connect(dst);
}, stagger * index);
}
}window.CP.exitedLoop(2);
}
function getFrequency(string, fret) {
var A = 120;
var offsets = [-5, 0, 5, 10, 14, 19];
return A * Math.pow(2, (fret + offsets[string]) / 12);
}
context.resume().then(strum([0,2,2,1,0,0]));
!!! The ScriptProcessorNode is deprecated. Use AudioWorkletNode instead.
(The ScriptProcessorNode is deprecated. Use AudioWorkletNode instead.)
It is a very successful webaudio guitar application. How can I change it?
I'm trying to filter out all lines as a result from HoughLine function in opencv. Currently just using getLines() function to get all lines then sorting them according to their rho value for each line. Then applying for loop to remove duplicates, problem is as follows:
In code if in (r1, θ1) and (r2, θ2) which I'm comparing in inner for loop for both either (r1,r2) positive or (r1,r2) negative (based on html canvas) then it's easy to filter them. But if either of them is positve or negative respectively then that line also gets included in finalLines array. Which can be explained through following figure:
function:
function getLines(minthresh = 8) {
let t = 300,
j = 0;
linesMat = new cv.Mat();
let copy = org_img.clone();
while (t > 0 && j < minthresh) {
try {
cv.HoughLines(tmp, linesMat, 1, Math.PI / 180, t);
j = linesMat.matSize[0]
console.log(`t=${t} j=${j}`, linesMat.matSize);
} catch (err) {
console.log(`error for t=${t}`);
j = 0;
} finally {
t = t - 10;
}
}
console.log('hough lines', linesMat.rows);
let bool = true;
let lines = linesMat.data32F;
let rows = linesMat.rows;
let foundLines = [];
finalLines = [];
for (let i = 0; i < rows; i++) {
let l = [lines[i * 2], lines[i * 2 + 1]];
foundLines.push(l);
}
foundLines.sort((a, b) => a[0] - b[0]);
console.log('filtering lines starts, sorted found lines:', foundLines);
for (let [index, line] of foundLines.entries()) {
let rho = line[0];
let theta = line[1];
let a = Math.cos(theta);
let b = Math.sin(theta);
let x0 = a * rho;
let y0 = b * rho;
let startPoint = {
x: x0 - 1000 * b,
y: y0 + 1000 * a
};
let endPoint = {
x: x0 + 1000 * b,
y: y0 - 1000 * a
};
let color = [random(), random(), random(), 255];
cv.line(copy, startPoint, endPoint, color);
bool = false;
for (let [jindex, linet] of foundLines.slice(index + 1).entries()) {
console.log(`for index=${index} jindex=${jindex+1} linet=${linet} line=${line}`);
bool = false;
if (linet[0] !== line[0]) {
k = [Math.abs(linet[0] - line[0]) < 50, Math.abs(linet[1] - line[1]) < 0.5];
console.log(`k=${k}`);
if (k[0] && k[1]) {
bool = true;
break;
}
}
}
if (bool) {
continue;
}
finalLines.push(line);
console.log(`push for i=${index}`);
console.log(`%c rho=${rho} deg=${theta * (180/Math.PI)}`, `background: rgba(${color[0]}, ${color[1]}, ${color[2]}, 1); color: black`);
}
cv.imshow('op', copy);
}
I've written a merge sort visualisation in p5.js which shows the steps of merge sort. This works fine as a sequential visualisation, but I'd quite like to show this as a true representation, where you can see each part of the array being sorted at the same time (with multiple sections being visualised sorting at the same time, to truly reflect the recursion). The code itself is relatively simple:
// Split the array recursively
let mid = Math.floor((right + left) / 2);
if (right - left < 1) {
return;
}
// My attempt to visualise this properly
await Promise.all([mergeSortSlice(array, left, mid), mergeSortSlice(array, mid + 1, right)]);
// THIS WORKS, but only for sequential sorting
// await mergeSortSlice(array, left, mid);
// await mergeSortSlice(array, mid + 1, right)
// Putting sleep(200) here also works, but doesn't show the steps of the sort as they are happening, just the result of each stage of the sort.
leftCounter = 0;
rightCounter = 0;
l = left;
r = mid + 1;
valuesStartIndex = l;
let leftArray = array.slice(left, r);
let rightArray = array.slice(r, right + 1);
while (rightCounter < rightArray.length && leftCounter < leftArray.length) {
if (leftArray[leftCounter] < rightArray[rightCounter]) {
array.splice(l + rightCounter, 1);
array.splice(valuesStartIndex, 0, leftArray[leftCounter]);
l++;
leftCounter++;
valuesStartIndex++;
await sleep(200);
} else {
array.splice(r, 1);
array.splice(valuesStartIndex, 0, rightArray[rightCounter]);
r++;
rightCounter++;
valuesStartIndex++;
await sleep(200);
}
}
The problem with using Promise.all is that the split parts of the array are getting mixed up, I believe due to the recursion? This is resulting in the array not getting sorted properly.
My timeout function:
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
The setup function and draw loop:
let values = [50, 10, 80, 56, 30, 25, 15]
function setup() {
createCanvas(600, 190);
frameRate(60);
mergeSort(values)
}
function draw() {
rectWidth = 10;
background(23);
stroke(0);
fill(255);
for (let i = 0; i < values.length; i++) {
rect(i * rectWidth, height - values[i], rectWidth, values[i]);
}
}
The combination of async functions and recursion makes it difficult for me to come up with a solution for this. Any help/advice would be much appreciated.
You were actually very close to having a working solution. Your issue is that you are creating a bunch of global variables inside your mergeSortSlice function:
// These were all missing the let keyword
// And were therefore either assigning or implicitly declaring
// globally scoped variables.
let leftCounter = 0;
let rightCounter = 0;
let l = left;
let r = mid + 1;
let valuesStartIndex = l;
let leftArray = array.slice(left, r);
let rightArray = array.slice(r, right + 1);
When two instances of a function invocation being run as part of a Promise each of which await on timeouts, their execution is going to be interleaved (which you want so you can graphically represent the theoretical parallelism). However, when those functions alter global variables this is a classic shared memory multi-threading bug.
Here's an adaptation of your code with the bug fixed, highlighting added, and a slightly different delay strategy:
function merge_sort(p) {
const Mode = {
Shuffling: 0,
Sorting: 1
};
const spacing = 5;
let array = [...Array(40)].map((_, i) => i);
let highlights = [];
let itemWidth;
let itemHeight;
let currentMode = Mode.Shuffling;
let iterator;
let frameRate = 8;
let redrawPromise;
let signalRedraw;
p.setup = function() {
p.createCanvas(p.windowWidth, p.windowHeight);
p.frameRate(frameRate * 5);
itemWidth = (p.width - (spacing * (array.length + 1))) / array.length;
itemHeight = p.height - spacing * 2;
iterator = shuffle();
initRedrawPromise();
};
function initRedrawPromise() {
redrawPromise =
new Promise(resolve => {
signalRedraw = resolve;
});
redrawPromise.then(() => initRedrawPromise());
}
p.draw = function() {
p.background('white');
// draw
for (let i = 0; i < array.length; i++) {
if (highlights[i]) {
p.fill(highlights[i]);
} else {
p.fill('blue');
}
let fractionalHeight = (array[i] + 1) / array.length;
let pixelHeight = fractionalHeight * itemHeight;
p.rect(
(i + 1) * spacing + i * itemWidth,
spacing + (itemHeight - pixelHeight),
itemWidth,
pixelHeight
);
}
signalRedraw();
if (currentMode === Mode.Shuffling) {
// update
let next = iterator.next();
if (next.value) {
// Done suffle, switch to sort
currentMode = Mode.Sorting;
p.frameRate(frameRate);
sort().then(() => {
// switch back to shuffling
currentMode = Mode.Shuffling;
p.frameRate(frameRate * 5);
iterator = shuffle();
});
}
}
};
p.keyPressed = function(e) {
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
frameRate++;
p.frameRate(frameRate);
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
frameRate = Math.max(0, frameRate - 1);
p.frameRate(frameRate);
}
}
// shuffle the array. yield false for each step where the array is not yet shuffled. yield true once the array is shuffled.
function* shuffle() {
// for each position in the array (except the last position),
// if the chosen item is not the current item, swap the two items.
for (let i = 0; i < array.length - 1; i++) {
highlight(i);
yield false;
let j = randomInt(i, array.length);
if (j !== i) {
highlight(i, j);
yield false;
swap(i, j);
highlight(j, i);
yield false;
} else {
highlight(i);
yield false;
}
}
yield true;
}
function sort() {
highlights = [];
return sortSlice(0, array.length - 1);
}
async function sortSlice(left, right) {
if (right - left < 1) {
return;
}
// Split the array recursively
let mid = Math.floor((right + left) / 2);
await Promise.all([sortSlice(left, mid), sortSlice(mid + 1, right)]);
for (let ix = left; ix <= right; ix++) {
highlights[ix] = undefined;
}
let leftCounter = 0;
let rightCounter = 0;
let l = left;
let r = mid + 1;
let valuesStartIndex = l;
let leftArray = array.slice(left, r);
let rightArray = array.slice(r, right + 1);
while (rightCounter < rightArray.length && leftCounter < leftArray.length) {
if (leftArray[leftCounter] < rightArray[rightCounter]) {
array.splice(l + rightCounter, 1);
array.splice(valuesStartIndex, 0, leftArray[leftCounter]);
highlights[valuesStartIndex] = 'green';
highlights[r] = 'red';
l++;
leftCounter++;
valuesStartIndex++;
} else {
array.splice(r, 1);
array.splice(valuesStartIndex, 0, rightArray[rightCounter]);
highlights[valuesStartIndex] = 'green';
r++;
rightCounter++;
valuesStartIndex++;
highlights[l + rightCounter] = 'red';
}
// at each merge step wait for a redraw that shows this step
await redrawPromise;
highlights[valuesStartIndex - 1] = 'gray';
for (let ix = valuesStartIndex; ix <= right; ix++) {
highlights[ix] = undefined;
}
}
}
function swap(i, j) {
const tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
function randomInt(lowerBound, upperBound) {
return lowerBound + Math.floor(Math.random() * (upperBound - lowerBound));
}
function highlight(i, j) {
highlights = [];
if (i !== undefined) {
highlights[i] = 'green';
}
if (j !== undefined) {
highlights[j] = 'red';
}
}
}
sketch = new p5(merge_sort);
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
I'm new to JavaScript, I'm trying to solve leetcode question 37. I need to a create a blank two dimensional array, I initially used the method in the comments; however, it doesn't work correctly, it will change all the value. Then, I used the for loop method to create array and currently it worked correctly. But I still cannot figured out why this will happen, could anyone explain the reason why this will happen, is this because of shallow copy?
var solveSudoku = function (board) {
// let rows = new Array(9).fill(new Array(10).fill(0)),
let rows = new Array(9);
for (let i = 0; i < 9; i++) {
rows[i] = new Array(10).fill(0);
}
let cols = new Array(9);
for (let i = 0; i < 9; i++) {
cols[i] = new Array(10).fill(0);
}
let boxes = new Array(9);
for (let i = 0; i < 9; i++) {
boxes[i] = new Array(10).fill(0);
}
// let cols = new Array(9).fill(new Array(10).fill(0)),
// boxes = new Array(9).fill(new Array(10).fill(0));
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
let c = board[i][j];
if (c !== '.') {
let n = parseInt(c),
bx = Math.floor(j / 3),
by = Math.floor(i / 3);
// 0代表为使用,1为使用过
rows[i][n] = 1;
console.log(i, n)
cols[j][n] = 1;
// box索引
boxes[by * 3 + bx][n] = 1;
}
}
}
fill(board, 0, 0)
function fill(board, x, y) {
// 完成填充条件
if (y === 9) return true;
// 下一个点的坐标
let nx = (x + 1) % 9,
// 判断进入是否下一行
ny = (nx === 0) ? y + 1 : y;
// 如果已经填充,则进入下一个点
if (board[y][x] !== '.') return fill(board, nx, ny);
// 没有被填充过
for (let i = 1; i <= 9; i++) {
let bx = Math.floor(x / 3),
by = Math.floor(y / 3),
box_key = by * 3 + bx;
if (!rows[y][i] && !cols[x][i] && !boxes[box_key][i]) {
rows[y][i] = 1;
cols[x][i] = 1;
boxes[box_key][i] = 1;
board[y][x] = i.toString();
console.log(board[y][x])
// 递归向下一个点求解
if (fill(board, nx, ny)) return true;
// 恢复初始状态
board[y][x] = '.';
boxes[box_key][i] = 0;
rows[y][i] = 0;
cols[x][i] = 0;
}
}
return false;
}
console.log(board);
};
The problem with fill(), at least with object, is that it passes the same object, by reference, to all element of the array. So if you mutate this object, then it will mutate every object of every arrays.
Note that in your case, you are creating a new Array object using it's constructor ( new Array() ) which makes them objects.
const matrix = new Array(5).fill(new Array(5).fill(0));
console.log(matrix);
In the previous snippet, you can see that the values of the other rows, from the second one to the end, are reference to the initial row.
To get around that, you can fill you array with empty values and then use the map() to create unique object for each position in the array.
const matrix = new Array(5).fill().map(function() { return new Array(5).fill(0); });
console.log(matrix);
As you can see in the previous snippet, all the rows are now their unique reference.
This is the reason all of your values were changed.
I've applied this solution to your code. I wasn't able to test it, because I wasn't sure of the initial parameters to pass.
I've also used anonymous function here ( function() { return; } ), but I would success using arrow function ( () => {} ) instead, if you are comfortable with them. It's cleaner.
var solveSudoku = function (board) {
let rows = new Array(9).fill().map(function() { return new Array(10).fill(0); }),
cols = new Array(9).fill().map(function() { return new Array(10).fill(0); }),
boxes = new Array(9).fill().map(function() { return new Array(10).fill(0); });
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
let c = board[i][j];
if (c !== '.') {
let n = parseInt(c),
bx = Math.floor(j / 3),
by = Math.floor(i / 3);
// 0代表为使用,1为使用过
rows[i][n] = 1;
console.log(i, n)
cols[j][n] = 1;
// box索引
boxes[by * 3 + bx][n] = 1;
}
}
}
fill(board, 0, 0)
function fill(board, x, y) {
// 完成填充条件
if (y === 9) return true;
// 下一个点的坐标
let nx = (x + 1) % 9,
// 判断进入是否下一行
ny = (nx === 0) ? y + 1 : y;
// 如果已经填充,则进入下一个点
if (board[y][x] !== '.') return fill(board, nx, ny);
// 没有被填充过
for (let i = 1; i <= 9; i++) {
let bx = Math.floor(x / 3),
by = Math.floor(y / 3),
box_key = by * 3 + bx;
if (!rows[y][i] && !cols[x][i] && !boxes[box_key][i]) {
rows[y][i] = 1;
cols[x][i] = 1;
boxes[box_key][i] = 1;
board[y][x] = i.toString();
console.log(board[y][x])
// 递归向下一个点求解
if (fill(board, nx, ny)) return true;
// 恢复初始状态
board[y][x] = '.';
boxes[box_key][i] = 0;
rows[y][i] = 0;
cols[x][i] = 0;
}
}
return false;
}
console.log(board);
};
I'm trying to come up with a solution where I need to roll a number of dice (all of the same size) and come to a specified number. Provided I have all the validation in place to make sure the numbers are valid and could theoretically arrive at the desired result, does anyone have a good algorithm for solving this? Note it should appear random, not just a straight divide.
Some examples
roll 3 d6 and get 14 -> so it could output 5,3,6 or 6,6,2
roll 4 d20 and get 66 -> so it could output 16,14,19,17
I need a generic function that can accept a dice of any size, any amount to be rolled and the desired result.
My initial attempt is below, though this doesn't produce the desired output (you can ignore the mod for now, this was to also allow modifiers). This example is also missing the validation that the desired output is achievable,but that's not part of the question.
let desired = 19
let mod = 0
let dm = desired - mod
let n = 5;// number of dice
let d = 6 // dice sides
let nums = []
for(i =0; i< n; i++) {
nums.push(Math.round(Math.random() * Math.round(d)) + 1)
}
let sum = nums.reduce((acc,val) => acc + val)
nums = nums.map(a => Math.round((a/sum) * dm))
let diff = dm - (nums.reduce((acc,val) => acc + val))
function recursive(diff) {
let ran = nums[Math.random() * Math.round(nums.length -1)]
if(nums[ran] + diff > d || nums[ran] + diff < 1) {
recursive(diff)
} else {
nums[ran] += diff
}
}
while(diff != 0) {
recursive(diff)
diff += diff < 0 ? 1 : -1;
}
alert(nums)
recursive:
function foo(desired, rolls, sides, current) {
if (rolls === 0) {
return current.reduce((s, c) => s + c) === desired ? current : null;
}
const random = [];
for (let i = 1; i <= sides; i++) {
const randomIndex = Math.floor(Math.random() * (random.length + 1))
random.splice(randomIndex, 0, i);
}
for (const n of random) {
const result = foo(desired, rolls - 1, sides, [...current, n]);
if (result) {
return result;
}
}
}
console.log(foo(14, 3, 6, []))
non-recursive:
function foo(desired, rolls, sides) {
const stack = [[]];
while (stack.length) {
const current = stack.pop();
const random = [];
for (let i = 1; i <= sides; i++) {
const randomIndex = Math.floor(Math.random() * (random.length + 1));
random.splice(randomIndex, 0, i);
}
for (const n of random) {
if (current.length === rolls - 1) {
if (current.reduce((s, c) => s + c + n) === desired) {
return [...current, n];
}
} else {
stack.push([...current, n]);
}
}
}
}
console.log(foo(14, 3, 6));
non-recursive with minimum memory consumption:
function foo(desired, rolls, sides) {
const currentIndexes = Array(rolls).fill(0);
const randoms = Array.from({ length: rolls }, () => {
const random = [];
for (let i = 1; i <= sides; i++) {
const randomIndex = Math.floor(Math.random() * (random.length + 1));
random.splice(randomIndex, 0, i);
}
return random;
})
while (true) {
if (currentIndexes.reduce((s, idx, i) => s + randoms[i][idx], 0) === desired) {
return currentIndexes.map((idx, i) => randoms[i][idx]);
}
for (let i = currentIndexes.length - 1; i >= 0; i--) {
if (currentIndexes[i] < sides - 1) {
currentIndexes[i] += 1;
break;
}
currentIndexes[i] = 0;
}
}
}
console.log(foo(14, 3, 6));
non-recursive solution with minimum memory consumption and increased performance by calculating the last roll based on previous rolls.
function foo(desired, rolls, sides) {
const currentIndexes = Array(rolls - 1).fill(0);
const randoms = Array.from({ length: rolls - 1 }, () => {
const random = [];
for (let i = 1; i <= sides; i++) {
const randomIndex = Math.floor(Math.random() * (random.length + 1));
random.splice(randomIndex, 0, i);
}
return random;
})
while (true) {
const diff = desired - currentIndexes.reduce((s, idx, i) => s + randoms[i][idx], 0);
if (diff > 0 && diff <= sides) {
return [...currentIndexes.map((idx, i) => randoms[i][idx]), diff];
}
for (let i = currentIndexes.length - 1; i >= 0; i--) {
if (currentIndexes[i] < sides - 1) {
currentIndexes[i] += 1;
break;
}
currentIndexes[i] = 0;
}
}
}
console.log(foo(66, 4, 20));
Soluton in ruby:
def foo(count, dim, desired, results = [])
return results if count == 0
raise ArgumentError if count > desired
raise ArgumentError if count * dim < desired
max_roll = (dim <= desired - count) ? dim : desired - count + 1
min_roll = [(desired - (count-1) * dim), 1].max
roll = (rand(min_roll..max_roll))
results << roll
foo(count - 1, dim, desired - roll, results)
results
end
puts foo(3, 6, 11).inspect
puts foo(2, 6, 11).inspect
puts foo(4, 4, 11).inspect
Results:
[3, 4, 4]
[5, 6]
[2, 3, 4, 2]
So basically it is recursive function. For each step:
roll a dice (within allowed range min_roll..max_roll)
call same function but reduce count by already consumed number by dice and extend results array by value of roll
Note one thing: with this behaviour you may have larger numbers in the beginning of result. To avoid this just shuffle result of function in the end of it