index negative number in array in lua - arrays

problem: I have an array called X. X[1:20]. I initialized to 0 to start with.
I want to pass a number to each element of array after adding 1 to it. So I read number and store in local variable z. sometimes "number" can be positive and negative.
However, array is only for positive (i.e. x [1....20] )
When "number" is negative lua gives error message that "attempt to perform arithmetic on field '?' (a nil value).
What should I do?
local x= {}
local number
local z
for i = 1, 20 do
x [i] = 0; -- array initialization
end
for y = 1, 5 do
z = number -- I am reading a "number" from hardware & it is a negative integer number
x[z] = x[z]+1 ;
end

It's because you are reading x[z], not just assigning it.
A simple fix would be to give it a default value.
Example:
x[z] = (x[z] or 0) + 1
This will make the code assume x[z] is equal to zero by default.

Your initialization code is only setting the positive values of the array X to 0. Simply modify the loop to initialize all the possible values of Z.
for i = -20, 20 do
x [i] = 0; -- array initialization
end
This assumes Z ranges from -20 to 20.
Negative index values work, but can sometimes lead to unexpected behavior when using the ipairs() function. The ipairs() function will only iterate through the values of the table starting at index 1 until the first uninitialized (nil) entry.
t = {}
for i = -2, 2 do t[i] = i end
print("all values")
for i = -2, 2 do
print(i, t[i])
end
print("positive integer values")
for k, v in ipairs(t) do
print(k, v)
end
Gives the following results:
all values
-2 -2
-1 -1
0 0
1 1
2 2
positive integer values
1 1
2 2

You can't index tables using negative numbers in Lua. You have got few possibilities:
Type cast the index to string and index with this string. It will make your table associative (you can index with any string):
z = tostring(number)
This is good if you do not have any boundaries for your indices
If you have limited interval of numbers (-20 to 20), you can do a transformation to the positive indices when accessing the values:
MIN_VALUE = -20
z = number - MIN_VALUE
This approach should give better performance, since the array is addressed directly.

You never set "number" to anything, therefore it gives you the error
attempt to perform arithmetic on field '?' (a nil value)
Notice the words "a nil value", because this is why this error occurred. So next time set "number" to something, or add an "or ___" when trying to do something like calculations, or setting variables.

Related

Julia / Cellular Automata: efficient way to get neighborhood

I'd like to implement a cellular automaton (CA) in Julia. Dimensions should be wrapped, this means: the left neighbor of the leftmost cell is the rightmost cell etc.
One crucial question is: how to get the neighbors of one cell to compute it's state in the next generation? As dimensions should be wrapped and Julia does not allow negative indices (as in Python) i had this idea:
Considered a 1D CA, one generation is a one-dimensional array:
0 0 1 0 0
What if we create a two dimensional Array, where the first row is shifted right and the third is shifted left, like this:
0 0 0 1 0
0 0 1 0 0
0 1 0 0 0
Now, the first column contain the states of the first cell and it's neighbors etc.
i think this can easily be generalized for two and more dimensions.
First question: do you think this is a good idea, or is this a wrong track?
EDIT: Answer to first question was no, second Question and code example discarded.
Second question: If the approach is basically ok, please have a look at the following sketch:
EDIT: Other approach, here is a stripped down version of a 1D CA, using mod1() for getting neighborhood-indices, as Bogumił Kamiński suggested.
for any cell:
- A array of all indices
- B array of all neighborhood states
- C states converted to one integer
- D lookup next state
function digits2int(digits, base=10)
int = 0
for digit in digits
int = int * base + digit
end
return int
end
gen = [0,0,0,0,0,1,0,0,0,0,0]
rule = [0,1,1,1,1,0,0,0]
function nextgen(gen, rule)
values = [mod1.(x .+ [-1,0,1], size(gen)) for x in 1:length(gen)] # A
values = [gen[value] for value in values] # B
values = [digits2int(value, 2) for value in values] # C
values = [rule[value+1] for value in values] # D
return values
end
for _ in 1:100
global gen
println(gen)
gen = nextgen(gen, rule)
end
Next step should be to extend it to two dimensions, will try it now...
The way I typically do it is to use mod1 function for wrapped indexing.
In this approach, no matter what dimensionality of your array a is then when you want to move from position x by delta dx it is enough to write mod1(x+dx, size(a, 1)) if x is the first dimension of an array.
Here is a simple example of a random walk on a 2D torus counting the number of times a given cell was visited (here I additionally use broadcasting to handle all dimensions in one expression):
function randomwalk()
a = zeros(Int, 8, 8)
pos = (1,1)
for _ in 1:10^6
# Von Neumann neighborhood
dpos = rand(((1,0), (-1,0), (0,1), (0,-1)))
pos = mod1.(pos .+ dpos, size(a))
a[pos...] += 1
end
a
end
Usually, if the CA has cells that are only dependent on the cells next to them, it's simpler just to "wrap" the vector by adding the last element to the front and the first element to the back, doing the simulation, and then "unwrap" by taking the first and last elements away again to get the result length the same as the starting array length. For the 1-D case:
const lines = 10
const start = ".........#........."
const rules = [90, 30, 14]
rule2poss(rule) = [rule & (1 << (i - 1)) != 0 for i in 1:8]
cells2bools(cells) = [cells[i] == '#' for i in 1:length(cells)]
bools2cells(bset) = prod([bset[i] ? "#" : "." for i in 1:length(bset)])
function transform(bset, ruleposs)
newbset = map(x->ruleposs[x],
[bset[i + 1] * 4 + bset[i] * 2 + bset[i - 1] + 1
for i in 2:length(bset)-1])
vcat(newbset[end], newbset, newbset[1])
end
const startset = cells2bools(start)
for rul in rules
println("\nUsing Rule $rul:")
bset = vcat(startset[end], startset, startset[1]) # wrap ends
rp = rule2poss(rul)
for _ in 1:lines
println(bools2cells(bset[2:end-1])) # unwrap ends
bset = transform(bset, rp)
end
end
As long as only the adjacent cells are used in the simulation for any given cell, this is correct.
If you extend this to a 2D matrix, you would also "wrap" the first and last rows as well as the first and last columns, and so forth.

If condition in Octave is not saving the required values within an array

I have a csv file from which I want to get just the values different from 0 and save them within an array x. I want to store rest of the matrix elements in an array s. This is the code I'm running in Octave:
clear all;close all;clc;
datafile = csvread('data20us.csv');
datafile = datafile(3:length(datafile));
for i=1:length(datafile)
if (datafile(i) ~= 0)
% x must stock values different from 0
x(i) = datafile(i);
else
% s must stock the rest of the values
s(i) = datafile(i);
end
end
The problem I have is that the vector x gets filled with both 0 and non 0 values (there 20 values different from 0 in the file). Is there any mistake in the condition I'm putting in the if statement?
The reason why you see zeros and non-zeros is the way you are populating the array in the loop. If you read your code, if the value at position i in your CSV file (I'm assuming this is a row or column vector) is not equal to 0, position i of the vector x gets changed. Else, position i of the vector s gets changed. Because you are not pre-allocating the vector x, what happens is that the vector x should you specify a position that is larger than the length of the array gets populated by zeros up until the desired position which you finally store the value.
Observe:
>> clear x;
>> x(4) = 3
x =
0 0 0 3
>> x(7) = 10
x =
0 0 0 3 0 0 10
As you can see, by not pre-allocating x and you specify a position other than the first to place a value there, all positions in between the previous last element and your desired position get populated with zeros. Therefore, when you get to a point in your loop where you have a value that's not equal to 0, you are seeing this zeros expansion happening.
If what I'm reading about your post is correct, you want to filter out the values in the CSV file that are not equal to 0. This can be done with simple logical indexing:
x = datafile(datafile ~= 0);
This will give you the vector x with all zero values removed. Finally, you can create the s vector which is just a vector of zeros that is as long as the total number of zeroes in the vector.
s = zeros(1, nnz(datafile == 0));
If you are somehow dead set on using a loop, consider concatenating the values instead:
clear all;close all;clc;
datafile = csvread('data20us.csv');
datafile = datafile(3:length(datafile));
% New - Make x empty
x = [];
% New - Make s empty
s = [];
for i=1:length(datafile)
if (datafile(i) ~= 0)
% x must stock values different from 0
% New - concatenate
x = [x datafile(i)];
else
% s must stock the rest of the values
% New - concatenate
s = [s datafile(i)];
end
end

Filter Multiple Conditions Array

I am trying to filter every negative number as well as every other number on an array with MATLAB. How's this possible? I thought I could have done this but it is not working:
Z = A(A<0 | 2:2:end)
The issue is that 2:2:end simply returns the following array
[2, 4, 6, .... % All the way up to numel(A)
The conditional yields a logical array the size of A that is true where an element is negative and false otherwise.
You can't combine these two because they are two different types and two different sizes.
If you want all numbers that are either a negative number or occur at an even location you could create a logical array that is true at all of the even locations (and false otherwise) and then perform logical operations using that instead. To do this, we create an array from [1....numel(A)] and perform the modulo operation (mod) with 2. Even numbers will have a remainder of 0 and odd numbers will have a remained of 1. Therefore, by comparing the result of mod(...,2) to 0 (== 0) we get a logical array that is true in all of the even locations and false otherwise.
even_locations = mod(1:numel(A), 2) == 0;
Z = A(A < 0 | even_locations);
If you simply want the even locations that are also negative
tmp = A(2:2:end);
Z = tmp(tmp < 0);
Or you can use the even_locations array above:
Z = A(A < 0 & even_locations);

Max of an Array (SAS)

I have an array of auc values, cv_auc0-cv_auc39, numbered 0-39. The maximum auc value is .7778, and it appears in several places in the array (33, 35, 38, 39). When I create the variable
auc_max = max(of cv_auc0-cv_auc&39);
It seems to identify place 39 as the maximum, even though this maximum appears elsewhere in the array.
These numbers 0-39 reflect the number of covariates in a model, and I want to keep this number as low as possible while maintaining max auc, thus I would like for the auc_max variable to identify place 33 instead of 39. How to do this?
I extract this covariate number, p, in the following code:
array a (*) cv_auc0-cv_auc&maxp;
do k = &maxp to 0 by -1;
if (a(k+1) = auc_max) then p = k;
end;
cross_val_auc = a(p+1);
keep p cross_val_auc;
And the p it returns is 39 instead of 33.
Why not just use the WHICHN() function? You might want to subtract one since your variable name suffixes start from zero instead of one.
auc_max = max(of cv_auc0-cv_auc&maxp);
p = whichn(auc_max,of cv_auc0-cv_auc&maxp)-1;
I don't see anything in here that could be incorrect. Best guess is that the max value is slightly different between the places. If the value in place 39 is, say, 1e-6 > the value in place 33, then you will return place 39.
Here is how I would do it. I would iterate up from the bottom and use the leave; statement to stop the loop.
data test;
array a[10] (1 2 3 4 4 3 2 4 1 4);
m = max(of a1-a10);
do p=1 to 10 ;
if a[p] = m then leave;
end;
put m= p=;
run;
returns:
m=4 p=4

Removing all zero-values except for those flanking non-zero values

Given a vector of:
a = [0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0]
Can anybody show or suggest a way to remove all zero-values except for those which flank non-zero values?
The desired result for the above would be:
b = [0;2;3;0;2;10;11;0;0;4;5;8;0]
Where these values have been removed:
[0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0]
I'm not sure where to start with this problem without having to resort to using a set of IF statements such as:
for k=1:length(a)
if a(k) == 0 && a(k+1) == 0
*delete value*
end
if a(k) == 0 && a(k+1) >0
*keep/store value*
end
if a(k) > 0
*keep/store value*
end
if a(k) == 0 && a(k-1) >0
*keep/store value*
end
end
And so forth.
I have another idea (granted, not very different from the other two), using logical indexing:
a(~(~a & ~[diff(a);0] & ~[0;diff(a)] ));
Explanation:
~ - boolean not, returns a boolean value representing the "opposite" of the input.
~a - returns the zero elements of a (it is not required in the example you gave, but is important if you have repeating nonzero values that you would like to keep).
~[diff(a);0] & ~[0;diff(a)] - return the values whose derivative on either size is zero.
a(~(...)) - return the values of a that aren't "zeros with the same values on both sides", which is b.
Another way to write the same thing (using De Morgan's laws and exploiting the "truthiness" of nonzero values):
a( a | [diff(a);0] | [0;diff(a)] );
You can think of it as finding "which values to keep" rather than "which values to remove", where the simplest way I can think of to define which values to keep is "all nonzero elements and zero elements that have a nonzero on either side".
You can use convolution:
b = a(conv(abs(sign(a)), ones(3,1), 'same')>0);
This works as follows:
Convert a to a vector of zeros or ones (abs(sign(a))), with zero if the entry of a is zero and one otherwise.
Convolve with a mask of three ones (conv(..., ones(3,1), 'same')). So a nonzero value in a produces a nonzero result at its position and at its neighbouring positions.
This is compared with zero to create a logical vector with which a is indexed (a(...>0)).
This can be easily generalized to keep more distant neighbours. Specifically, use the mask ones(2*N+1,1) to keep zero values that are up to N entries away of nonzero values.
If you create two additional vectors, one shifting to the left, one to the right from your vector a (EDIT : using circshift as suggested in the comments below) :
a = [0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0];
a_right = circshift(a,-1);
a_left = circshift(a,1);
Create a matrix M :
M = [a,a_right,a_left];
And sum each line :
s = sum(M,2);
Then find the components that differs from 0 :
i = find(s~=0);
This will give you the right indexes to select from your initial vector :
b=a(i)
I get :
b=[0;2;3;0;2;10;11;0;0;4;5;8;0]

Resources