parallelizing the for loop in javascript - javascript

I have a nested for loop with
for(let i=0; i<500; i++){
//some work
for(let j=0; j<100000; j++){
//some work
}
}
is there any way I can make this parallel or fast like a web worker, asynchronous?
I could not think of how I can make any of these work.
Each work inside the inner for loop is independent of than watch others.
I tried to parallelize the code using the Promise.all() but no fruitful
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));
}

In single thread, you will only get performance boost for "parallelising" IO calls or network calls. In your case it is probably Copc.loadPointDataView, so the most important part is to make the body of the outer for-loop into promises. The inner loops don't matter so much as they do not contains IO/network calls so there is no "waiting time" to safe. But I'd demonstrate how to use Promise.all on all layers anyway.
let promises = [];
for (let m = 0; m < keyCountMap.length; m += 2) {
promises.push((async () => {
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;
let innerPromises = [];
for (let j = 0; j < keyCountMap[m + 1]; j += chunkCount) {
innerPromises.push((async ()=>{
let remaining = keyCountMap[m + 1] - totalCalled;
let localChunkCount = Math.min(chunkCount, remaining);
totalCalled += localChunkCount;
const pointTemp = new Array(localChunkCount).fill(null);
const readPointPromises = pointTemp.map((element, index) => readPoints(index + j, getters) );
const done = await Promise.all(readPointPromises);
})());
}
await Promise.all(innerPromises);
})());
}
await Promise.all(promises);

Related

I would like to fill an array with numbers using javascript with a for loop

"But I always double the numbers. so [1,1,2,2,3,3 .......] how can you do that? I am looking forward to the answer. "
Continuous with a number, the for loop is good. But how do I do it with double numbers?
To get an array to N, use:
let N = 10;
Array.from(Array(N).keys())
To double each value in any array:
[...yourArray.map(n => [n, n])].flat()
So, your solution:
let n = 10;
const a = [...Array.from(Array(n).keys()).map(k => [k, k])].flat()
console.log(a)
To have it starting from 0, not 1, alter the mapping accordingly:
let n = 10;
const a = [
...Array.from(Array(n).keys())
.map(k => [k + 1, k + 1])
].flat()
console.log(a)
Arguably, the cleanest solution:
function doubleArrayTo(n) {
const a = [];
for (i = 1; i <= n; i++) {
a.push(i, i);
}
return a;
}
console.log(doubleArrayTo(10))
Out of curiosity, I tested their performance. Unsurprisingly, the for loop wins hands down over the spread syntax:
function doubleFor(n) {
const a = [];
for (i = 1; i <= n; i++) {
a.push(i, i);
}
return a;
}
function doubleSpread(n) {
return [
...Array.from(Array(n).keys())
.map(k => [k + 1, k + 1])
].flat()
}
function run_test(fn, value) {
const t0 = performance.now();
fn(value);
return performance.now() - t0;
}
[1e4, 1e5, 1e6, 1e7].map(value => {
console.log(
`(${value}): for => ${
run_test(doubleFor, value)
} | spread => ${
run_test(doubleSpread, value)
}`);
});
follow this code
var array = [];
for(int i = 0;i <= 10;i++) {
array.push(i);
array.push(i);//again
}
var array = [];
for (let i = 0; i <= 10; i++) {
array.push(i,i);
}
console.log(array);
Edit
You can use multi input for array.push(i,i,i,....)

how can I better run my code in javascript?

The exercise is as follows, given an array with multiple arrays inside, return the sum of the product subtraction with the LMC. I managed to create the code, but is passing 12000ms of response and wanted to optimize my code, I still have difficulty with it, can you help me? Follow the code below.
The expected result is 840.
let pairs = [[15,18], [4,5], [12,60]];
function sumDifferencesBetweenProductsAndLCMs (pairs)
{
let product = [];
let prodResult = 1;
let LMC = [];
let result = 0;
// take a product
for(let i = 0; i < pairs.length;i++)
{
for(let j = 0; j < pairs[i].length;j++)
{
prodResult *= pairs[i][j]
}
product.push(prodResult);
if(prodResult != 0)
{
prodResult = 1
}
}
// take a LMC
for(let i = 0; i < pairs.length;i++)
{
let m = pairs[i][0];
let n = pairs[i][1];
let a = pairs[i][0];
let b = pairs[i][1];
let mmc = 0;
let r = 0
do
{
r = m%n;
m=n;
n=r;
} while (r != 0);
mmc = (a * b)/m
LMC.push(mmc)
}
for(let i = 0; i < product.length; i++){
result += product[i]-LMC[i]
}
return result
}
console.log(sumDifferencesBetweenProductsAndLCMs(pairs));
You can do all calculation in single loop only which will reduce your run time complexity.
let pairs = [[15,18], [4,5], [12,60]];
function sumDifferencesBetweenProductsAndLCMs (pairs) {
let result = 0;
// take a product
for(let i = 0; i < pairs.length;i++) {
let prodResult = 1;
for(let j = 0; j < pairs[i].length;j++) {
prodResult *= pairs[i][j]
}
const lcmResult = lcm(pairs[i][0], pairs[i][1]);
result += prodResult - lcmResult;
}
return result
}
function lcm(a, b) {
return (a / gcd(a, b)) * b;
}
function gcd(a, b) {
if (a === 0) {
return b;
}
return gcd(b % a, a);
}
console.log(sumDifferencesBetweenProductsAndLCMs(pairs));
.as-console-wrapper {
top: 0;
}

JavaScript String Encryption

I would like to encrypt one line of text using the following encryption scheme.
This is the sample input. First, the spaces are removed from the text.
haveaniceday
Then, returns the length of a string (L = 12). Next, characters are written into a grid, whose rows and columns have the following constraints:
The length of a string will return the square root of L is between 3 and 4. Thus, rewritten with 3 rows and 4 columns:
have
anic
eday
Finally, the encoded message is obtained by displaying the characters in a column, inserting a space, and then displaying the next column and inserting a space, and so on.
For example, the encoded message for the above rectangle is:
hae and via ecy
In my code snippets, the grid ["have", "anic", "eday"] already created, but I have no idea how to achieve the next stage.
const s = "haveaniceday";
let result = encryption(s);
function encryption(s) {
let sqr = Math.sqrt(s.length),
col = Math.ceil(sqr),
row = Math.floor(sqr);
let chunks = chunkSubstr(s, col);
// => ["have", "anic", "eday"]
console.log(chunks);
for (var i = 0; i < chunks.length; i++) {
// do some magic here...
// expected output: "hae and via ecy"
}
}
function chunkSubstr(str, size) {
const numChunks = Math.ceil(str.length / size)
const chunks = new Array(numChunks)
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = str.substr(o, size)
}
return chunks
}
You may reduce your Array ["have" "anic" "eday"] in an other Array, the length of your strings. For each three members of the original Array, you'll map all its characters into the new Array.
const original = ["have", "anic", "eday"];
const output = original.reduce((out, word) => {
word.split("") // break into characters[]
.forEach((char, i) =>
out[i] += char // append this char to the corresponding string of `out`
);
return out;
}, new Array(original[0].length).fill('')) // ['', '', '', '']
console.log(output.join(' '));
You may get each character in chunks by looping the count of col.
const s = "haveaniceday";
let result = encryption(s);
function encryption(s) {
let sqr = Math.sqrt(s.length),
col = Math.ceil(sqr),
row = Math.floor(sqr);
let chunks = chunkSubstr(s, col);
// => ["have", "anic", "eday"]
console.log(chunks);
let output = '';
for (var i=0; i<col; i++) {
chunks.forEach((e) => {
if (e[i]) {
output += e[i];
}
});
output += ' ';
}
console.log(output);
}
function chunkSubstr(str, size) {
const numChunks = Math.ceil(str.length / size)
const chunks = new Array(numChunks)
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = str.substr(o, size)
}
return chunks
}
const s = "haveaniceday";
let result = encryption(s);
function encryption(s) {
let sqr = Math.sqrt(s.length),
col = Math.ceil(sqr),
row = Math.floor(sqr);
let chunks = chunkSubstr(s, col);
// => ["have", "anic", "eday"]
console.log(chunks);
var result = [];
for (var i = 0; i < chunks.length; i++) {
// do some magic here...
// expected output: "hae and via ecy"
var split = Array.from(chunks[i]);
for (var s = 0; s < split.length; s++) {
var previousValue = '';
if(result[s])
{ previousValue = result[s];}
result[s]=previousValue + split[s];
}
}
console.log(result);
}
function chunkSubstr(str, size) {
const numChunks = Math.ceil(str.length / size)
const chunks = new Array(numChunks)
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = str.substr(o, size)
}
return chunks
}
easy => array.joint(' ') in the end, and a double loop
const s = "haveaniceday";
let result = encryption(s);
console.log ('result =', result );
function encryption(s) {
let
sqr = Math.sqrt(s.length),
col = Math.ceil(sqr),
row = Math.floor(sqr)
;
let chunks = chunkSubstr(s, col);
// => ["have", "anic", "eday"]
let Respons = [];
for (let i=0, iMax=chunks[0].length; i<iMax; i++ ) {
Respons[i] = '';
for (let txt of chunks ) {
Respons[i] += txt.charAt(i);
}
}
return Respons.join(' ');
}
function chunkSubstr(str, size) {
const
numChunks = Math.ceil(str.length / size),
chunks = new Array(numChunks)
;
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = str.substr(o, size)
}
return chunks
}

Strange behavior of the neutral network written in plain JS

Impressed by the possibilities of neural networks, I've decided that before using any library I want to understand how they work. So I wrote a simple training app, which used 3 layer network with 2 neurons each. There was a canvas 400x400. Given the coordinates of x,y of the mouse over the canvas <0;399> it was supposed to give as the result coordinate/400 <0;1> (So for 100,300 it is supposed to give 0.25,0.75).
The training looked reasonable.
But when I switch to the prediction mode the network gives the same result all the time for each training batch. It gives the same results no matter what the input is.
Then after more training the output changes, but it’s still the same for each input.
It's written in TypeScript.
Instead of pasting the whole web training page I just made the training script so you can see more clearly what's going on.
index.ts
let sigmoid: ActivationFunction = {
func: (x: number) => (1 / (1 + Math.exp(-x))),
derivative: (z: number) => {
return sigmoid.func(z) * (1 - sigmoid.func(z));
}
};
import Matrix from './matrix';
class NeutralNetwork {
layers: Array<number>;
weights: Matrix[];
biases: Matrix[];
activation_function: ActivationFunction;
learning_rate: number;
constructor(...layers: Array<number>) {
this.layers = layers;
this.activation_function = sigmoid;
//Initialize neural network with random weigths and biases [-1;1]
this.weights = [];
for(let i=0; i<this.layers.length - 1; i++){
this.weights.push(new Matrix(this.layers[i+1], this.layers[i]));
this.weights[i].randomize();
}
this.biases = [];
for(let i=1; i<this.layers.length; i++){
this.biases.push(new Matrix(this.layers[i], 1));
this.biases[i-1].randomize();
}
this.setActivationFunction();
this.setLearningRate();
}
feedForward(originalInput: Array<number>): Array<number> {
if(originalInput.length != this.layers[0]) throw new Error("corrupt input data");
let input : Matrix = Matrix.createFromArray(originalInput);
for(let i = 0; i < this.layers.length - 1; i++){
let output = Matrix.multiply(this.weights[i], input);
output.add(this.biases[i]);
output.map(this.activation_function.func);
input = output;
}
return input.toArray();
}
train(originalInput: Array<number>, originalTarget: Array<number>) {
if(originalInput.length != this.layers[0]) throw new Error("corrupt training data");
if(originalTarget.length != this.layers[this.layers.length - 1]) throw new Error("corrupt training data");
let outputs : Matrix[] = [];
let input : Matrix = Matrix.createFromArray(originalInput);
for(let i = 0; i < this.layers.length - 1; i++){
let output = Matrix.multiply(this.weights[i], input);
output.add(this.biases[i]);
output.map(this.activation_function.func);
input = output;
outputs.push(output);
}
let target = Matrix.createFromArray(originalTarget);
let errors = Matrix.subtract(target, outputs[this.layers.length - 2]);
for(let i = this.layers.length - 2; i>=0; i--){
let gradients = Matrix.map(outputs[i], this.activation_function.derivative);
gradients.multiply(errors);
gradients.multiply(this.learning_rate);
let outputsOfLayerBeforeTransposed = Matrix.transpose(i > 0 ? outputs[i-1] : Matrix.createFromArray(originalInput));
let deltas = Matrix.multiply(gradients, outputsOfLayerBeforeTransposed);
this.weights[i].add(deltas);
this.biases[i].add(gradients);
let weightsTransposed = Matrix.transpose(this.weights[i]);
errors = Matrix.multiply(weightsTransposed, errors);
}
return outputs[outputs.length - 1].toArray();
}
setActivationFunction(activationFunction = sigmoid) {
this.activation_function = activationFunction;
}
setLearningRate(learning_rate = 0.1) {
this.learning_rate = learning_rate;
}
}
interface ActivationFunction {
func(x: number): number;
derivative(x: number): number;
}
export = NeutralNetwork;
training.ts
let NN = require('./index');
let n = new NN(2,2,2);
let data = generateTrainingData();
data.forEach(d => n.train(d.i, d.o));
//check how well is it trained
let index = 0
let t = setInterval(()=>{
let pred = n.feedForward(data[index].i);
console.log(`PREDICTED - ${pred} EXPECTED = ${data[index].o} COST - ${Math.pow(pred[0]-data[index].o[0],2)+Math.pow(pred[1]-data[index].o[1],2)}`)
if(index++ == 1000) clearInterval(t);
}, 500);
function generateTrainingData(){
let data = [];
for(let i=0;i<1000;i++){
let x = Math.floor(Math.random() * 400);
let y = Math.floor(Math.random() * 400);
data.push({
i : [x,y],
o : [x/400, y/400]
})
}
return data;
}
matrix.ts
export default class Matrix {
rows;
columns;
data: Array<Array<number>>;
constructor(rows, columns) {
this.rows = rows;
this.columns = columns;
this.data = new Array(this.rows).fill().map(() => Array(this.columns).fill(0));
}
static map(matrix, f) : Matrix{
let m = new Matrix(matrix.rows, matrix.columns);
m.map((v,i,j) => f(matrix.data[i][j], i, j));
return m;
}
map(f) {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.columns; j++) {
this.data[i][j] = f(this.data[i][j], i, j);
}
}
}
randomize() {
this.map(() => Math.random() * 2 - 1);
}
add(n) {
if (n instanceof Matrix) {
if (this.rows !== n.rows || this.columns !== n.columns) {
throw new Error('Size of both matrices must match!');
}
return this.map((v, i, j) => v + n.data[i][j]);
} else {
return this.map(v => v + n);
}
}
static subtract(a, b) : Matrix{
if (a.rows !== b.rows || a.columns !== b.columns) {
throw new Error('Size of both matrices must match!');
}
let m = new Matrix(a.rows, a.columns);
m.map((_, i, j) => a.data[i][j] - b.data[i][j]);
return m;
}
static multiply(a, b) {
if (a.columns !== b.rows) {
throw new Error('a.columns !== b.rows');
}
let m = new Matrix(a.rows, b.columns)
m.map((_, i, j) => {
let sum = 0;
for (let k = 0; k < a.cols; k++) {
sum += a.data[i][k] * b.data[k][j];
}
return sum;
});
return m;
}
multiply(n) {
if (n instanceof Matrix) {
if (this.rows !== n.rows || this.columns !== n.columns) {
throw new Error('Size of both matrices must match!');
}
return this.map((v, i, j) => v * n.data[i][j]);
} else {
return this.map(v => v * n);
}
}
toArray() {
let arr = [];
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.columns; j++) {
arr.push(this.data[i][j]);
}
}
return arr;
}
static transpose(matrix) : Matrix {
let m = new Matrix(matrix.columns, matrix.rows)
m.map((_, i, j) => matrix.data[j][i]);
return m;
}
static createFromArray(arr): Matrix {
let m = new Matrix(arr.length, 1);
m.map((v, i) => arr[i]);
return m;
}
}
I'm not really sure what the cause of that. I've been trying to debug this for days now, but I think my lack of experience doesn't let me see the issue here. Thank you so much for all of your help.
There is a mistake in Matrix.multiply class method. It should be a.columns rather than a.cols. Because of this, gradients and deltas are not updating properly.

javascript getting rid array reference

This is a react minesweeper and it involves setState when the user wants to choose a new grid size. When the user clicks the grid should be recreated, but there are some reference problems thanks to the prev state.
When I first console.log(array); it is not empty thanks to the prev state. When I console.log(array[m][n]['value']) it says all the values are 0, but when I console.log(array); right after it the array contains 'b' values which are set from the addBombsmethod which is invoked after the createMap.
What should I do?
createMap (sizeX, sizeY, bombNumber) {
let array = [];
while (array.length > 0) {
array.pop();
}
array.length = 0;
console.log(array); // not totally empty, but it says length 0.
for (var m = 0; m < sizeY; m++) {
array[m] = new Array();
for (var n = 0; n < sizeX; n++) {
array[m][n] = { value: 0, state: 'closed' };
console.log(array[m][n]['value']); // Prints 0 for all of them.
}
}
console.log(array); // There are 'b' values in the array.
return array.slice();
}
createTable(props) {
const sizeX = props.sizeX;
const sizeY = props.sizeY;
const bombNumber = props.bombNumber;
const map = this.createMap(sizeX, sizeY, bombNumber);
const newMap = map.slice();
const newestMap = this.addBombs(newMap, sizeX, sizeY, bombNumber);
const newestestMap = newestMap.slice();
const mMap = this.calculateFieldValues(newestestMap);
const nMap = mMap.slice();
return nMap;
}
addBombs (map, sizeX, sizeY, bombNumber) {
let bombFields = [];
while (bombFields.length < bombNumber) {
const randomNumber = Math.floor(Math.random() * (sizeY * sizeX - 1))
if (!bombFields.includes(randomNumber)) {
bombFields.push(randomNumber);
}
}
bombFields.forEach((number) => {
const i = Math.floor(number / sizeX);
let j = (number % sizeX);
if (j === -1) {
j = sizeX - 1;
}
map[i][j]['value'] = 'b';
});
return map;
}

Categories