Why won't setMatrix([...matrix, [[x][y]]]) work? - javascript

I want to add the coordinates x and y (from the loop) to the state (matrix) like you can see in my example but it won't work. Can someone help me?
const [matrix, setMatrix] = useState([[], []] as any)
for (let j = 0; j < imgHeight * scale; j += props.gridsize.height) {
for (let i = 0; i < imgWidth * scale; i += props.gridsize.width) {
console.log('x: ' + x + ' ===== ' + 'y: ' + y)
drawImgRectangles(ctx, [{ x: x, y: y, width: props.gridsize.width, height: props.gridsize.height }])
x += props.gridsize.height
}
x = 0
y += props.gridsize.height
}
setMatrix([...matrix, [[x][y]]])
console.log(matrix[[0][0]]) **

The problem is in expression [x][y] which evaluates to undefined.
[x] defines an array containing one element x
[x][y] tries to index the [x] array, taking y-th element. If y is anything other than 0, the result is undefined
console.log([3][0]); // 3
console.log([3][1]); // undefined
You probably meant one of:
const x = 1;
const y = 2;
var matrix1: number[][] = [];
matrix1 = [...matrix1, [x, y]];
var matrix2: number[][][] = [];
matrix2 = [...matrix2, [[x], [y]]];

Related

Increment specific value of element in a 2d array JS

How can I create the starting positon on a coordinate plot and update (increment) the x value? Initially, position was given values of 2 and 5, but for testing purposes, I'd just like to update the x value by 1, but am getting the same values returned?
function boardCreate(rows, columns) {
for (let x = 0; x < rows; x++) {
for (let y = 0; y < columns; y++) {
boardCell(x, y);
}
}
}
function boardCell(x, y) {
board[x] = board[x] || [];
board[x][y] = x + " " + y;
}
var board = [];
boardCreate(10, 10);
let position = board[2][5];
function incrementX(position) {
position[1] = position[1] + 1;
return position;
}
incrementX(position);
console.log(position);
If I understand correctly, you need to increment the board coordinates based on the x and y values of the current position - this can be achieved by:
extracting the x and y values at the specified position
const [x, y] = position.split(' ');
incrementing x by one:
const nextX = Number.parseInt(x) + 1;
reading the new position value from new x value and exisiting y
return board[nextX][y]
Hope this helps!
function boardCreate(rows, columns) {
for (let x = 0; x < rows; x++) {
for (let y = 0; y < columns; y++) {
boardCell(x, y);
}
}
}
function boardCell(x, y) {
board[x] = board[x] || [];
board[x][y] = x + " " + y;
}
var board = [];
boardCreate(10, 10);
let position = board[2][5];
function incrementX(position) {
/* Ensure valid position specified before attempting increment */
if (!position) {
return;
}
/* Read x,y coordinates from array value */
const [x, y] = position.split(' ');
/* Parse x to number and increment it */
const nextX = Number.parseInt(x) + 1;
if (nextX >= board.length) {
console.error(`next x: ${ nextX } out of bounds`);
return;
}
/* Look up board value at next x, and same y coordinate */
return board[nextX][y]
}
console.log(position);
/* Testing */
let p = incrementX(position);
for (let i = 0; i < 10; i++) {
p = incrementX(p);
console.log(p);
}

Tensorflow, conv2d and filters

I'm beginner in deep learning, and trying to understand how algorithms works, writing them using JavaScript. Now I'm working on JavaScript implementation of conv2d like Tensorflow does, and misunderstand how to handle different count of filters, I have succeeded for one output filter and multiple output, but I'm confused how to produce operations with multiple filters input e.g. 32 -> 64
Here is example of code using ndarray
:
const outCount = 32 // count of inputs filters
const inCount = 1 // count of output features
const filterSize = 3
const stride = 1
const inShape = [1, 10, 10, outCount]
const outShape = [
1,
Math.ceil((inShape[1] - filterSize + 1) / stride),
Math.ceil((inShape[2] - filterSize + 1) / stride),
outCount
];
const filters = ndarray([], [filterSize, filterSize, inCount, outCount])
const conv2d = (input) => {
const result = ndarray(outShape)
// for each output feature
for (let fo = 0; fo < outCount; fo += 1) {
for (let x = 0; x < outShape[1]; x += 1) {
for (let y = 0; y < outShape[2]; y += 1) {
const fragment = ndarray([], [filterSize, filterSize]);
const filter = ndarray([], [filterSize, filterSize]);
// agregate fragment of image and filter
for (let fx = 0; fx < filterSize; fx += 1) {
for (let fy = 0; fy < filterSize; fy += 1) {
const dx = (x * stride) + fx;
const dy = (y * stride) + fy;
fragment.data.push(input.get(0, dx, dy, 0));
filter.data.push(filters.get(fx, fy, 0, fo));
}
}
// calc dot product of filter and image fragment
result.set(0, x, y, fo, dot(filter, fragment));
}
}
}
return result
}
For test I'm using a Tenforflow as a source of true and it algorithm works correct but with 1 -> N. But my question how to add a support of multiple filters in input value like N -> M.
Could someone explain how to modify this algorithm to make it more compatible with Tensorflow tf.nn.conv2d
A lot of thanks.
You would need to add another for loop. You didn't specify all of your input shapes and dimensions so it's actually kind of hard to write it exactly but it would look like this.
// agregate fragment of image and filter
for (let fx = 0; fx < filterSize; fx += 1) {
for (let fy = 0; fy < filterSize; fy += 1) {
//addition
for (let ch = 0; ch < input.get_channels) {
const dx = (x * stride) + fx;
const dy = (y * stride) + fy;
fragment.data.push(input.get(0, dx, dy, ch));
filter.data.push(filters.get(fx, fy, ch, fo));
}
}
}

Structure to run x first vs y first on 2d array

I want to have a flag passed to a function that runs an algorithm by either col-scanning or row-scanning:
if run-on-x
for 1..x
for 1..y
do something with ary[x][y]
else
for 1..y
for 1..x
do something with ary[x][y]
But I don't want to duplicate all the loops and logic.
I've come up with this:
let numPx = width * height;
for (let px = 0; px < numPx; px++) {
let [x, y] = yAxis ? [px % width, 0 | px / width] : [0 | px / height, px % height];
But I think all the math is rather heavy, especially when I'm running it on fairly large arrays.
Is there a better way to do this?
Perhaps by simply passing them in as parameters like so?:
function colRowScan(1stAxis,2ndAxis)
for 1.. 1stAxis
for 1.. 2ndAxis
do something with ary[x][y]
Without seeing what the "do something" is I don't know if there is any unforeseen reasons why this couldn't work but given what you posted it should do the trick.
I am not entirely sure what you are trying to do here:
let numPx = width * height;
for (let px = 0; px < numPx; px++) {
let [x, y] = yAxis ? [px % width, 0 | px / width] : [0 | px / height, px % height];
function f(x, y, on_x) {
var a, b;
if (on_x) {
a = x;
b = y;
}
else {
a = y;
b = x;
}
for (var ia = 0; ia < a.length; ia++) {
for (var ib = 0; ib = b.length; ib++) {
// ...
}
}
}
Keep the two sets of inner and outer loops, but change the body of the inner loop to a single function call. Then there's not much code duplication.
In your solution,
let numPx = width * height;
for (let px = 0; px < numPx; px++) {
let [x, y] = yAxis ? [px % width, 0 | px / width] : [0 | px / height, px % height];
Number of comparison is numPx times while earlier it was only once, leave out the heavy math involved.
I think the simple and best solution is to use a separate function.
OR you can try this
var a, b, fAry;
if (run-on-x) {
a = x;
b = y;
fAry = ary;
} else {
a = y;
b = x;
fAry = transpose of(ary);
}
for (var i = 0; i < a; i++) {
for (var j = 0; j < b; j++) {
do something with fAry[i][j];
}
}
for 1..x
for 1..y {
var a = run-on-x ? ary[x][y] : ary[y][x];
do something with a
}
Create helper functions for row major and column major iteration, taking the array and a function to apply to the array members.
var rowMajor = function (a, op) {
var maxi = a.length;
var maxj = a[0].length;
for(var i = 0; i < maxi; ++i) {
var row = a[i];
for(var j = 0; j < maxj; ++j)
op(row[j],i,j);
}
};
var colMajor = function (a, op) {
var maxi = a.length;
if(maxi === 0) return;
var maxj = a[0].length;
for(var j = 0; j < maxj; ++j) {
for(var i = 0; i < maxi; ++i) {
op(a[i][j],i,j);
}
}
};
// example use (with jQuery)
var array = [[11,12,13],[21,22,23]];
var div = $('<div></div>');
var append = function(value) {
div.append($('<span></span>').text(value + ' '));
};
rowMajor(array,append);
div.append('<br/>');
colMajor(array, append);
$('body').append(div);

Uncaught TypeError: Cannot set property '1' of undefined

Now this is wierd, I basically calling the function "sortTiles()" twice, the first time, it loops through, and returns a beautiful array, just as it's supposed to do. But the second time I call it, it doesn't work, and throws the error as stated in the title to a specific line: tiles[y][x] = tile;.
The first time around, the returned array from "sortTiles()" is put into a global array called "solution". The second time the function is called, it will get the tiles X and Y coordinate from the solution array.
What I'm doing here is it basically scans a sliding puzzle, with the help of a html5 canvas and prnt_scrn+paste into the website. And as said, first time you do it, you take a screenshot of the solution, paste it in, and it marks out all the coordinates just fine. The second time, it throws an error :(
function getTile(x, y) {
var id = 0;
for (i = 0; i < 2; i++) {
for (i2 = 0; i2 < 2; i2++) {
var data = context.getImageData(x + i * 48 + 5 - (i * 10), y + i2 * 48 + 5 - (i2 * 10), 1, 1).data;
id += data[0] + data[1] + data[2];
}
}
return id;
}
function findTile(number) {
for (y = 0; y < 5; y++) {
for (x = 0; x < 5; x++) {
if (solution[y][x] == number) {
return [x, y];
}
}
}
}
function sortTiles() {
context.font = "20px Georgia";
var tiles = [];
tiles.length = 0;
for (y = 0; y < 5; y++) {
tiles[y] = [];
for (x = 0; x < 5; x++) {
var tile = getTile(108 + x * 56, 34 + y * 56);
tiles[y][x] = tile;
if (solution.length != 0) {
var coordinate = findTile(tile);
context.fillText(coordinate[0] + ", " + coordinate[1], 108 + x * 56 + 12, 34 + y * 56 + 36);
} else {
context.fillText(x + ", " + y, 108 + x * 56 + 12, 34 + y * 56 + 36);
}
}
}
return tiles;
}
Your x and y variables are global and are conflicting between sortTiles and findTile. Make them local using var.
function getTile(x, y) {
var id = 0;
for (var i = 0; i < 2; i++) {
for (i2 = 0; i2 < 2; i2++) {
var data = context.getImageData(x + i * 48 + 5 - (i * 10), y + i2 * 48 + 5 - (i2 * 10), 1, 1).data;
id += data[0] + data[1] + data[2];
}
}
return id;
}
function findTile(number) {
for (var y = 0; y < 5; y++) {
for (var x = 0; x < 5; x++) {
if (solution[y][x] == number) {
return [x, y];
}
}
}
}
function sortTiles() {
context.font = "20px Georgia";
var tiles = [];
tiles.length = 0;
for (var y = 0; y < 5; y++) {
tiles[y] = [];
for (var x = 0; x < 5; x++) {
var tile = getTile(108 + x * 56, 34 + y * 56);
tiles[y][x] = tile;
if (solution.length != 0) {
var coordinate = findTile(tile);
context.fillText(coordinate[0] + ", " + coordinate[1], 108 + x * 56 + 12, 34 + y * 56 + 36);
} else {
context.fillText(x + ", " + y, 108 + x * 56 + 12, 34 + y * 56 + 36);
}
}
}
return tiles;
}

Using javascript vars as array key names

I'm making a grid of 18 x 9 and want to calculate the sizes for all possible boxes that could be placed on the grid.
I'm placing them in objects, but the line
var template_sizes_site[x + 'x' + y] = {};
Is failing. it seems I can't use variables AND a string to name key?
I want basically to say array['2x9']['width'] = 42; etc
What am I missing?
var template_sizes = {};
var site_width = 70;
var site_height = 70;
var site_margin = 20;
for (var y = 1; y <= 9; y++)
{
for (var x = 1; x <= 18; x++)
{
var template_sizes_site[x + 'x' + y] = {};
template_sizes_site[x + 'x' + y]['width'] = ((site_width * x) + (x > 1 ? site_margin * (x - 1) : 0));
template_sizes_site[x + 'x' + y]['height'] = ((site_height * y) + (y > 1 ? site_margin * (y - 1) : 0));
}
}
Remove the var from your first line in the body of your nested for loop:
var template_sizes = {};
var site_width = 70;
var site_height = 70;
var site_margin = 20;
for (var y = 1; y <= 9; y++)
{
for (var x = 1; x <= 18; x++)
{
template_sizes_site[x + 'x' + y] = {};
template_sizes_site[x + 'x' + y]['width'] = ((site_width * x) + (x > 1 ? site_margin * (x - 1) : 0));
template_sizes_site[x + 'x' + y]['height'] = ((site_height * y) + (y > 1 ? site_margin * (y - 1) : 0));
}
}
var is only for variables, not for properties:
var template = {}; // OK
var template_sizes_site[x + 'x' + y] = {}; // not allowed, no need
Also you'll need to initialise template_sizes_site if that wasn't a typo.
You did not initialize your variable template_sizes_site (is this meant to be template_sizes ?). Also you could shorten your initialization code a little like shown below.
var template_sizes = {},
template_sizes_site = {},
site_width = 70,
site_height = 70,
site_margin = 20;
for (var y = 1; y <= 9; y++) {
for (var x = 1; x <= 18; x++) {
template_sizes_site[x + 'x' + y] = {
'width': ((site_width * x) + (x > 1 ? site_margin * (x - 1) : 0)),
'height': ((site_height * y) + (y > 1 ? site_margin * (y - 1) : 0))
};
}
}
You need to change var template_sizes_site[x + 'x' + y] = {}; into template_sizes_site[x + 'x' + y] = {}; because your way creates local variable in scope and after leaving it (when loop goes to next time) data is becomes lost.
Also template_sizes_site is not initialized if it is all your code.

Categories