How to initialise a three dimensional ruby array - arrays

I want to initialise a three dimensional ruby array. For a two-dimensional array, I can do
a = Array.new(4){ Array.new(5, 0) }
so I have tried
a = Array.new(4) { Array.new(5, Array.new(6, 0)) }
but if I do a[1][2][3] = 5, it not only sets that element to 5, it sets the corresponding element to 5 in other sub arrays i.e.
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]],
[[0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0]],
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]

The issue is that if you pass the value as an argument, you will get an array where each value refers to that same object. You do exactly that with:
Array.new(5, Array.new(6, 0))
You can use Array#*, i.e array multiplication instead:
[[[0] * 6] * 5] * 4

Just use the same syntax (with a block instead of an argument : Array.new(n){...}) for all the dimensions.
a = Array.new(4) { Array.new(5) { Array.new(6, 0) } }
This way, your code will create 20 distincts Array.new(6, 0) sub-sub-arrays instead of replicating the same object 5 times.
require 'pp'
a = Array.new(4) { Array.new(5) { Array.new(6, 0) } }
a[1][2][3] = 5
pp a
# [[[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]],
# [[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 5, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]],
# [[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]],
# [[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]]]

The following worked properly.
a=Array.new(4){ Array.new(5) { Array.new(6,0) }}

You can use recursion to initialize the elements of a multidimensional array of any dimension.1
Code
def init(n, *rest)
rest.empty? ? Array.new(n, 0) : Array.new(n) { init(*rest) }
end
Examples
dims = [2, 3, 2]
a = init(*dims)
#=> [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
a[0][0][0] = 1
a #=> [[[1, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
dims = [2, 3, 2, 4, 2, 3]
a = init(*dims)
a.flatten.size
#=> 288 (= 2*3*2*4*2*3)
a[0][0][0][0][0][0] = 1
a.flatten.count(1)
#=> 1
Explanation
The steps are as follows.
Suppose, as in the example,
dims = [2, 3, 2]
Then
n, *rest = dims
#=> [2, 3, 2]
n #=> 2
rest
#=> [3, 2]
As rest.empty? #=> false, the method returns
Array.new(2) { init(*[3, 2]) } # (1)
#=> [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
To obtain this result, we execute the block
{ init(*[3, 2]) }
for each of the two elements of the array being constructed. This requires us to compute init([3, 2]) (same as { init(3, 2) }), which is done as follows.
n, *rest = [3, 2]
#=> [3, 2]
n #=> 3
rest
#=> [2]
Again, as rest.empty? #=> false, we return
Array.new(3) { init(*[2]) } # (2)
#=> [[0, 0], [0, 0], [0, 0]]
to expression (1) above. For each of the 3 elements of this array we execute the block
{ init(*[2]) }
This requires us to compute init([2]), which is done as follows.
n, *rest = [2]
#=> [2]
n #=> 2
rest
#=> []
This time, since rest.empty? #=> true, we compute and return
Array.new(2, 0)
#=> [0, 0]
to expression (2) above.
1 Yes, there's no such thing as a "multidimensional array" in Ruby, but I expect readers to know what I mean. The alternative is something like "...of an array containing nested arrays of equal size with any number of levels of nesting", but even that is incomplete as it fails to exclude, for example, [[1, [2,3]], [4,5]]. It would be helpful if Ruby had a name for such objects.

Related

Most efficient way to select elements in n dimension array in Ruby with indexes

I want to select elements with its indexes based on given condition for n dimension array
I have solution for two dimension array like below
ary = [
['A', 'B', 'C'],
['D', 'E', 'F'],
['G', 'H', 'I']
]
new_ary = ary.collect.with_index do |row, index_r|
row.collect.with_index { |col, index_c| [col, index_r, index_c] if index_c == 0 }.compact
end
new_ary.flatten(1)
=> [["A", 0, 0], ["D", 1, 0], ["G", 2, 0]]
I want this solution for n dimension
it would be great if method works like this
ary.select_with_indexes { |val, index_c ,index_c,...| index_c == 0 }
# x,y,... is indexes
# val is value of x,y,... index
# x == 0 is condition for select element, this condition is only for understanding. we will put any condition there
Three dimension array like below
ary = [[
['A1', 'B1', 'C1'],
['D1', 'E1', 'F1'],
['G1', 'H1', 'I1']
],[
['A2', 'B2', 'C2'],
['D2', 'E2', 'F2'],
['G2', 'H2', 'I2']
],[
['A3', 'B3', 'C3'],
['D3', 'E3', 'F3'],
['G3', 'H3', 'I3']
]]
new_ary = ary.collect.with_index do |row, index_r|
row.collect.with_index do |col, index_c|
col.collect.with_index do |val, index_d|
[val, index_r, index_c, index_d] if index_d == 0
end.compact
end
end
new_ary.flatten(1)
=> [[["A1", 0, 0, 0]], [["D1", 0, 1, 0]], [["G1", 0, 2, 0]], [["A2", 1, 0, 0]], [["D2", 1, 1, 0]], [["G2", 1, 2, 0]], [["A3", 2, 0, 0]], [["D3", 2, 1, 0]], [["G3", 2, 2, 0]]]
index_d == 0 this condition is only for understanding
we will put any condition there
Code
In the examples in the question the index of the innermost array is always zero. I have made that an argument, most_inner_index.
def doit(ary, most_inner_index)
first, *rest = nested_indices(ary)
first.product(*rest).map do |indices|
[ary.dig(*indices, most_inner_index), *indices, most_inner_index]
end
end
def nested_indices(ary)
sizes = []
while ary.first.is_a?(Array)
sizes << ary.size.times.to_a
ary = ary.first
end
sizes
end
Examples
ary2 = [
['A', 'B', 'C'],
['D', 'E', 'F'],
['G', 'H', 'I']
]
doit(ary2, 0)
#=> [["A", 0, 0], ["D", 1, 0], ["G", 2, 0]]
doit(ary2, 1)
#=> [["B", 0, 1], ["E", 1, 1], ["H", 2, 1]]
doit(ary2, 2)
#=> [["C", 0, 2], ["F", 1, 2], ["I", 2, 2]]
ary3 = [[
['A1', 'B1', 'C1'],
['D1', 'E1', 'F1'],
['G1', 'H1', 'I1']
],[
['A2', 'B2', 'C2'],
['D2', 'E2', 'F2'],
['G2', 'H2', 'I2']
],[
['A3', 'B3', 'C3'],
['D3', 'E3', 'F3'],
['G3', 'H3', 'I3']
]]
doit(ary3, 0)
#=> [["A1", 0, 0, 0], ["D1", 0, 1, 0], ["G1", 0, 2, 0],
# ["A2", 1, 0, 0], ["D2", 1, 1, 0], ["G2", 1, 2, 0],
# ["A3", 2, 0, 0], ["D3", 2, 1, 0], ["G3", 2, 2, 0]]
doit(ary3, 1)
#=> [["B1", 0, 0, 1], ["E1", 0, 1, 1], ["H1", 0, 2, 1],
# ["B2", 1, 0, 1], ["E2", 1, 1, 1], ["H2", 1, 2, 1],
# ["B3", 2, 0, 1], ["E3", 2, 1, 1], ["H3", 2, 2, 1]]
doit(ary3, 2)
#=> [["C1", 0, 0, 2], ["F1", 0, 1, 2], ["I1", 0, 2, 2],
# ["C2", 1, 0, 2], ["F2", 1, 1, 2], ["I2", 1, 2, 2],
# ["C3", 2, 0, 2], ["F3", 2, 1, 2], ["I3", 2, 2, 2]]
Notice that the return values are not quite in the form desired. That is because I could not figure out from the question how many nested arrays were desired.
ary4 = [
[
[
[['A1', 'B1'], ['C1', 'D1']],
[['E1', 'F1'], ['G1', 'H1']]
],
[
[['I1', 'J1'], ['K1', 'L1']],
[['M1', 'N1'], ['O1', 'P1']]
]
],
[
[
[['A2', 'B2'], ['C2', 'D2']],
[['E2', 'F2'], ['G2', 'H2']]
],
[
[['I2', 'J2'], ['K2', 'L2']],
[['M2', 'N2'], ['O2', 'P2']]
]
],
[
[
[['A3', 'B3'], ['C3', 'D3']],
[['E3', 'F3'], ['G3', 'H3']]
],
[
[['I3', 'J3'], ['K3', 'L3']],
[['M3', 'N3'], ['O3', 'P3']]
]
]
]
doit(ary4, 0)
#=> [["A1", 0, 0, 0, 0, 0], ["C1", 0, 0, 0, 1, 0], ["E1", 0, 0, 1, 0, 0],
# ["G1", 0, 0, 1, 1, 0], ["I1", 0, 1, 0, 0, 0], ["K1", 0, 1, 0, 1, 0],
# ["M1", 0, 1, 1, 0, 0], ["O1", 0, 1, 1, 1, 0], ["A2", 1, 0, 0, 0, 0],
# ["C2", 1, 0, 0, 1, 0], ["E2", 1, 0, 1, 0, 0], ["G2", 1, 0, 1, 1, 0],
# ["I2", 1, 1, 0, 0, 0], ["K2", 1, 1, 0, 1, 0], ["M2", 1, 1, 1, 0, 0],
# ["O2", 1, 1, 1, 1, 0], ["A3", 2, 0, 0, 0, 0], ["C3", 2, 0, 0, 1, 0],
# ["E3", 2, 0, 1, 0, 0], ["G3", 2, 0, 1, 1, 0], ["I3", 2, 1, 0, 0, 0],
# ["K3", 2, 1, 0, 1, 0], ["M3", 2, 1, 1, 0, 0], ["O3", 2, 1, 1, 1, 0]]
doit(ary4, 1)
#=> [["B1", 0, 0, 0, 0, 1], ["D1", 0, 0, 0, 1, 1], ["F1", 0, 0, 1, 0, 1],
# ["H1", 0, 0, 1, 1, 1], ["J1", 0, 1, 0, 0, 1], ["L1", 0, 1, 0, 1, 1],
# ["N1", 0, 1, 1, 0, 1], ["P1", 0, 1, 1, 1, 1], ["B2", 1, 0, 0, 0, 1],
# ["D2", 1, 0, 0, 1, 1], ["F2", 1, 0, 1, 0, 1], ["H2", 1, 0, 1, 1, 1],
# ["J2", 1, 1, 0, 0, 1], ["L2", 1, 1, 0, 1, 1], ["N2", 1, 1, 1, 0, 1],
# ["P2", 1, 1, 1, 1, 1], ["B3", 2, 0, 0, 0, 1], ["D3", 2, 0, 0, 1, 1],
# ["F3", 2, 0, 1, 0, 1], ["H3", 2, 0, 1, 1, 1], ["J3", 2, 1, 0, 0, 1],
# ["L3", 2, 1, 0, 1, 1], ["N3", 2, 1, 1, 0, 1], ["P3", 2, 1, 1, 1, 1]]
Explanation
The steps are as follows for ary3 and most_inner_index = 0.
a = nested_indices(ary3)
#=> [[0, 1, 2], [0, 1, 2]]
first, *rest = a
#=> [[0, 1, 2], [0, 1, 2]]
Ruby applies array decomposition to obtain the following.
first
#=> [0, 1, 2]
rest
#=> [[0, 1, 2]]
Continuing,
b = first.product(*rest)
#=> [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
c = b.map do |indices|
[ary.dig(*indices, most_inner_index), *indices, most_inner_index]
end
#=> [["A1", 0, 0, 0], ["D1", 0, 1, 0], ["G1", 0, 2, 0],
# ["A2", 1, 0, 0], ["D2", 1, 1, 0], ["G2", 1, 2, 0],
# ["A3", 2, 0, 0], ["D3", 2, 1, 0], ["G3", 2, 2, 0]]
See Array#product and Array#dig.

Tensorflow.js cropping image return zeros tensor

I have a custom model which takes in cropped faces from BlazeFace Model then outputs a prediction of 3 classes.
Before sending them to my custom model I resize the cropped faces to be of shape [1,224,224,3]
Output at every prediction:
Float32Array [
6.522771905936864e-11,
3.698188456857654e-12,
1,
]
Code for resizing the cropped faces and making predictions:
const getPrediction = async tensor => {
if (!tensor) {
console.log("Tensor not found!");
}
// Load both models
const bfModel = await blazeFaceModel;
const returnTensors = true;
const faces = await bfModel
.estimateFaces(tensor, returnTensors)
.catch(e => console.log(e));
// Reshape tensor from rank 3 to rank 4
const tensorReshaped = tensor.reshape([1, 224, 224, 3]);
const scale = {
height: styles.camera.height / tensorDims.height,
width: styles.camera.width / tensorDims.width
};
// Faces is an array of objects
if (!isEmpty(faces)) {
// Setting faces in state
setModelFaces({ faces });
}
//Looping over array of objects in faces
faces.map((face, i) => {
const { topLeft, bottomRight } = face;
const width = Math.floor(
bottomRight.dataSync()[0] - topLeft.dataSync()[0] * scale.width
);
const height = Math.floor(
bottomRight.dataSync()[1] - topLeft.dataSync()[1] * scale.height
);
const boxes = tf
.concat([topLeft.dataSync(), bottomRight.dataSync()])
.reshape([-1, 4]);
// Cropping out faces from original tensor
const crop = tf.image.cropAndResize(
tensorReshaped,
boxes,
[0],
[height, width]
);
// Resize cropped faces to [1,224,224,3]
const alignCorners = true;
const imageResize = tf.image.resizeBilinear(
crop,
[224, 224],
alignCorners
);
makePrediction(imageResize);
});
};
// Make predictions on the tensors
const makePrediction = async image => {
if (!image) {
console.log("No input!");
}
const model = await loadedModel;
const prediction = await model.predict(image, { batchSize: 1 });
if (!prediction || isEmpty(prediction)) {
console.log("Prediction not available");
}
console.log(prediction);
console.log(prediction.dataSync());
};
EDIT
I tried changing the batch size when making predictions to 1 and still the same issue
I tried reconverting the keras model to tfjs format and still the same issue
I tried disposing of the tensor after making a prediction but still there is an error
So i printed out the tensors of the resized faces and its a lot of 0's
Tensor before prediction
Tensor
[[[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
...
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]]]
undefined
Tensor during prediction
Tensor
[[[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
...
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]]]
undefined
boxes of tf.image.cropAndResize are normalized coordinates between 0 and 1. Therefore topLeft and bottomRight should be normalized by using [imageWidth, imageHeight]
normalizedTopLeft = topLeft.div(tensor.shape.slice(-3, -2))
// slice will get [h, w] of a tensor of shape [b, h, w, ch] or [h, w, ch]
// do likewise for bottomRight
// use normalizedTopLeft instead of topLeft for cropping

Constructing Diagonal and Off-Diagonal Matrix Elements

Mathematica Code
In Mathematica, I was able to write out the desired matrix with diagonal and off-diagonal values I was wondering what the best way to do this is in python using numpy?
A virtual clone of your code:
In [146]: arr = np.zeros((5,5),int)
In [147]: arr[np.arange(5),np.arange(5)]=2
In [148]: arr[np.arange(4),np.arange(1,5)]=-1
In [149]: arr[np.arange(1,5),np.arange(4)]=-1
In [150]: arr
Out[150]:
array([[ 2, -1, 0, 0, 0],
[-1, 2, -1, 0, 0],
[ 0, -1, 2, -1, 0],
[ 0, 0, -1, 2, -1],
[ 0, 0, 0, -1, 2]])
or with a diag function:
In [151]: np.diag(np.ones(5,int)*2,0)+np.diag(np.ones(4,int)*-1,-1)+np.diag(np.ones(4,int)*-1,1
...: )
Out[151]:
array([[ 2, -1, 0, 0, 0],
[-1, 2, -1, 0, 0],
[ 0, -1, 2, -1, 0],
[ 0, 0, -1, 2, -1],
[ 0, 0, 0, -1, 2]])

How to change a value of an array which is indexed several times?

Let's have A like below :
A = np.array([[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 0, 0, 0, 0]])
And now, I have to take all the lines which have a 1 on first column :
A[A[:, 0] > 0]
return: array([[1, 0, 0, 0, 0],
[1, 0, 1, 0, 0]])
And now, I want to modify the first column of the second line ? How can I do it ? Because this is not working :
A[A[:, 0] > 0][1, 1] = 1
A
array([[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 3, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 0, 0, 0, 0]])
My code is more complicated than this one, and so, the condition have to be done in two times like here : (1) > 0 and (2) [1, 1].

which tasks can simple perceptron perform?

I'm trying to teach simple single neuron perceptron to recognize repetitive sequences of 1.
here is data I use to teach it:
learning_signals = [
[[1, 1, 0, 0], 1],
[[1, 1, 0, 1], 1],
[[1, 1, 1, 0], 1],
[[0, 1, 1, 0], 1],
[[0, 1, 1, 1], 1],
[[0, 0, 1, 1], 1],
[[1, 0, 1, 1], 1],
[[0, 0, 0, 0], 0],
[[1, 0, 0, 0], 0],
[[0, 1, 0, 0], 0],
[[0, 0, 1, 0], 0],
[[0, 0, 0, 1], 0],
[[1, 0, 1, 0], 0],
[[1, 0, 0, 1], 0],
# [[0, 1, 0, 1], 0],
This is the array of learning templates each of them are array of data and correct result for that data.
As you see. last row commented - if I do uncomment it - perceptron will fail to learn. without it perceptron does not work right in case with "0101". So the question is:
Is this task can be solved with single neuron perceptron or should I use few layered perceptron?
How can I determine which tasks can be solved with such a simple perceptron? Are there any rule that I can apply to my task and say that it could be done with simple perceptron?
here is the code of perceprton written in coffeescript:
class window.Perceptron
weights: []
calc: (signal) ->
#neuron.calc signal
adjust: ->
foo: 0.1
calc: (signal) ->
sum = 0
for s, i in signal
sum += s*#weights[i]
if sum>0.5 then return 1 else return 0
sum
learn: (templates) ->
#weights = []
for i in [1..templates[0][0].length]
#weights.push Math.random()
li = 0
max_li = 50000
console.log #weights
while true
gerror = 0
li++
for template, i in templates
res = #calc template[0]
# console.log "result: #{res}"
error = template[1] - res
gerror += Math.abs error
for weight, i in #weights
#weights[i] += #foo*error*template[0][i]
if ((gerror == 0) || li > max_li) then break
if gerror == 0
console.log "Learned in #{li} iterations"
else
console.log "Learning failed after #{max_li} iterations"
console.log #weights

Resources