I am trying to display some value of n consecutive numbers of a vector (in this example, vector x).
x = [1
1
1
1
1
1
0
0
0
0
1
1
0
0
0
0
0
0
1
0
1
0
1
0
1
0
1
1
0
0
1
1
1
1
1
1
0
0
1
1
1
1
0
0
1
1
1
1
1
1
0
0
0
0
0
1
0
0
1
0
0
0
0
1
0
0
1
0
1
0
0
0
1
0
0
0
0
1
0
1
0
0
1
0
0
0
0
1
1
0
0
0
1
0
0
0
0
0
0
1
0
1
0
0
0
0
1
0
1
0
0
0
1
0
0
0
0
0
0
1
0
0
0
1
0
0
1
1
1
1
1
1
0
0
1
1
0
0
1
0
1
0
0
0
0
0
0
1
0
1
0
0];
For example, I may want the first 3 values of 4 consecutive numbers which would be (3 values of 4 bits each):
1111
1100
0011
I may want the first 4 values of 2 consecutive numbers which would be (4 values of 2 bits each):
11
11
11
00
x is a double array. What would be an easy way to achieve this?
The simplest way is to reshape x to a matrix with your desired number of bits per value as the number of rows (MATLAB is column-major). For example, to get 4-digit values:
t = reshape(x,4,[]);
This will only work if the length of x evenly divides into 4. You could first crop x to the right number of elements to avoid errors where the length is not evenly divisible:
t = reshape(x(1:4*3),4,[]);
Now the transposed matrix t, converted to a string, looks like your desired output:
c = char(t.' + '0');
The output is a 3x4 char array:
'1111'
'1100'
'0011'
You can convert these binary representations back to numbers with bin2dec:
b = bin2dec(c);
The output is a 3-element double vector:
15
12
3
Related
I have
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
I want to find all the regions that have more than 5 zeros in a row. I want to find the index where it starts and where it stops.
In this case I want this: c=[12 18]. I can do it using for loops but I wonder if there is any better way, at least to find if there are some regions where this 'mask' ( mask=[0 0 0 0 0] ) appears.
A convolution based approach:
n = 5;
x = [0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0];
end_idx = find(diff(conv(~x, ones(1,n))==n)==-1)
start_idx = find(diff(conv(~x, ones(1,n))==n)==1) - n + 2
returning
end_idx =
6 14 25
start_idx =
1 9 20
Note that this part is common to both lines: diff(conv(~x, ones(1,n))==n) so it would be more efficient to pull it out:
kernel = ones(1,n);
convolved = diff(conv(~x, kernel)==n);
end_idx = find(convolved==-1)
start_idx = find(convolved==1) - n + 2
You can use regexp this way:
convert the array into a string
remove the blanks
use regexp to find the sequence of 0
A possible implementation could be:
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
% Convert the array to string and remove the blanks
str=strrep(num2str(x),' ','')
% Find the occurrences
[start_idx,end_idx]=regexp(str,'0{6,}')
This gives:
start_idx = 12
end_idx = 17
where x(start_idx) is the first element of the sequence and x(end_idx) is the last one
Applied to a more long sequence, start_idx and end_idx results being arrays:
x=[0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0]
start_idx =
1 9 20
end_idx =
6 14 25
I'm not quite sure how to describe what I mean, so let me try to explain by example (bear with me).
When you simply increment an integer you get a binary sequence like so (let's assume 8 bits for this question):
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 0
0 0 0 0 0 0 1 1
0 0 0 0 0 1 0 0
0 0 0 0 0 1 0 1
0 0 0 0 0 1 1 0
0 0 0 0 0 1 1 1
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 1
0 0 0 0 1 0 1 0
0 0 0 0 1 0 1 1
0 0 0 0 1 1 0 0
0 0 0 0 1 1 0 1
0 0 0 0 1 1 1 0
0 0 0 0 1 1 1 1
0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 1
0 0 0 1 0 0 1 0
0 0 0 1 0 0 1 1
0 0 0 1 0 1 0 0
0 0 0 1 0 1 0 1
0 0 0 1 0 1 1 0
0 0 0 1 0 1 1 1
0 0 0 1 1 0 0 0
0 0 0 1 1 0 0 1
0 0 0 1 1 0 1 0
0 0 0 1 1 0 1 1
0 0 0 1 1 1 0 0
0 0 0 1 1 1 0 1
0 0 0 1 1 1 1 0
0 0 0 1 1 1 1 1
[ ... etc ... ]
One way to visualize this is that each column represents a "clock". Each clock/column is half the frequency of its right neighbor.
So the right-most clock has one 0 followed by one 1, etc. The next clock has two 0s followed by two 1s, etc and so on...
I'm interested in a sequence of binary strings in which each clock is an integer division of its neighbor.
So the right-most clock is still one 0, one 1, the next clock is still two 0s, two 1s, but the third clock is three 0s and three 1s, etc.
Instead of /1 /2 /4 /8 /16 ... it's now /1 /2 /3 /4 /5 ....
The sequence now looks like this:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 0
0 0 0 0 0 1 1 1
0 0 0 0 1 1 0 0
0 0 0 1 1 1 0 1
0 0 1 1 1 0 1 0
0 1 1 1 1 0 1 1
1 1 1 1 0 0 0 0
1 1 1 1 0 1 0 1
1 1 1 0 0 1 1 0
1 1 1 0 0 1 1 1
1 1 0 0 1 0 0 0
1 1 0 0 1 0 0 1
1 0 0 0 1 0 1 0
1 0 0 1 1 1 1 1
0 0 0 1 0 1 0 0
0 0 0 1 0 1 0 1
0 0 1 1 0 0 1 0
0 0 1 1 0 0 1 1
[ ... etc ... ]
Question: Is there an operation/algorithm which can give me the value at i given the value at i-1?
In other words, let's say I'm at the 4th step (0 0 0 0 0 1 1 1). Is there some operation I can perform on this number to get the value at the 5th step (0 0 0 0 1 1 0 0), and similarly for any other step?
In the divide-by-2 case you simply increment the number (i++) but in the divide-by-N case I can't seem to figure out a similar way to go from one to the next. Am I missing something obvious?
I've tried translating the sequencing into decimal but that pattern is 0, 1, 2, 7, 12, 29, 58, etc which doesn't stand out to me as anything obvious.
The brute-force way that I'm doing it now is that I have an array of counters (one for each column/clock) and I independently reset each count when the respective column's "period" is reached (so 2 for the first column, 3 for the next, etc). But that feels ugly.
I'd love to do this directly on the number without requiring an array of counters. Is this even possible? Is this a known sequence? I'm not even sure what to Google to be honest. I'd appreciate any kind of leads on this. I'm happy to go down the rabbit hole with some guidance.
UPDATE
As per #borrible's observation, there are more than one values for i-1 for a given i so it turns out the solution to my original question is ambiguous. So I will expand my question to allow i as an input (in addition to the i-1th value.
Without knowing i you are only going be able to generate the successor to a given sequence if that sequence uniquely implies i (modulo the number of bit sequences). If this is not the case the successor to a given sequence is ambiguous.
Lets consider the first few sequences for 3 bits:
0 0 0
0 0 1
0 1 0
1 1 1
1 0 0
1 0 1
0 1 0
0 1 1
Note that 0 1 0 is succeeded by both 1 1 1 and 0 1 1; i.e. it is ambiguous. Given 0 1 0 but not i you cannot deduce the next sequence. You can see a similar ambiguity in 4 bit sequences for 0 1 1 1 etc...
In other words, without knowing i, your problem is not generally solvable.
This sequence can be considered as a set of state machines, each with 2,4,6,...,16 states. The least common multiple of 2,4,6,...,16, i.e. the length of the sequence, is 1680. Eight bits only lets us represent 256 values, so even if we were allowed to select the state encoding (which we aren't!), we wouldn't be able to uniquely identify all possible states.
If we know the index i (or, as the sequence length is 1680, it is sufficient to know the index modulo 1680), digit j is given by (i mod (2 * j)) / j.
I am working with iterative methods, and thus with large sparse matrices.
For instance, I want to set up a matrix like this:
1 1 0 0 1 0 0 0 0 0
1 1 1 0 0 1 0 0 0 0
0 1 1 1 0 0 1 0 0 0
0 0 1 1 1 0 0 1 0 0
1 0 0 1 1 1 0 0 1 0
0 1 0 0 1 1 1 0 0 1
So that only certain diagonals are non-zero. In my programming, I will be working with much larger matrix sizes, but Idea is the same: Only a few diagonals are non-zero, all other entries are zeros.
I know, how to do it in for loop, but it seems to be not effective, if the matrix size is large. Also I work with symmetric matrices.
I would appreciate, if you provide me a code for my sample matrix along with description.
You want spdiags:
m = 6; %// number of rows
n = 10; %// number of columns
diags = [-4 -1 0 1 4]; %// diagonals to be filled
A = spdiags(ones(min(m,n), numel(diags)), diags, m, n);
This gives:
>> full(A)
ans =
1 1 0 0 1 0 0 0 0 0
1 1 1 0 0 1 0 0 0 0
0 1 1 1 0 0 1 0 0 0
0 0 1 1 1 0 0 1 0 0
1 0 0 1 1 1 0 0 1 0
0 1 0 0 1 1 1 0 0 1
I'm looking for a vectorized solution for this problem :
Let A a vector (great size : > 10000) of 0 and 1.
Ex :
A = [0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1 0 1 etc]
I want to replace the 0 between the 1's (of odd ranks) by 2
i.e. to produce :
B = [0 0 0 1 2 2 2 2 2 1 0 0 0 1 2 2 1 0 0 1 2 1 etc]
Thanks for your help
It can be done quite easily with cumsum and mod:
A = [0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1 0 1]
Short answer
A( mod(cumsum(A),2) & ~A ) = 2
A =
0 0 0 1 2 2 2 2 2 1 0 0 0 1 2 2 1 0 0 1 2 1
You requested to fill the islands of odd rank, but by changing mod(... to ~mod(... you can easily fill also the islands of even rank.
Explanation/Old answer:
mask1 = logical(A);
mask2 = logical(mod(cumsum(A),2))
out = zeros(size(A));
out(mask2) = 2
out(mask1) = 1
try using cumsum
cs = cumsum( A );
B = 2*( mod(cs,2)== 1 );
B(A==1) = 1;
I have an array:
1 1 1 0 0
1 2 2 0 0
1 2 3 0 0
0 0 0 0 0
0 0 0 0 0
I want to make it
1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1
It is like rotating 1/4 piece of pie 270 degrees to fill out the remaining parts of the pie to make a full circle. Essentially mirroring the entire corner in all directions. I don't want to use any in built matlab features if possible - just some vector tricks if possible. Thanks.
EDIT:
This is embedded within an matrix of zeros of arbitrary size. I want it to work in both the above example and say this example:
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0 0 0 0 0
0 0 1 2 2 0 0 0 0 0 0 0 0 0
0 0 1 2 3 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
Ideally, I want to have a vector say [1,2,3.. N] which can be rotated circularly about the highest value in the array (N) centered about some point xc,yc in the grid. Or if this isn't possible, take an base array [1 1 1, 1 2 2, 1 2 3] and rotate it such that 3 is in the centre and you fill a circle as in the 2nd matrix above.
EDIT:
I found rot90(M,k) rotates matrix M k times but this produces:
Mrot = M + rot90(M,1) + rot90(M,2) + rot90(M,3)
Mrot =
1 1 2 1 1
1 2 4 2 1
2 4 12 4 2
1 2 4 2 1
1 1 2 1 1
This stacks it in the x,y directions which isn't correct.
Assuming the corner you want to replicate is symmetric about the diagonal (as in your example), then you can do this in one indexing step. Given a matrix M containing your sample 5-by-5 matrix, here's how to do it:
>> index = [1 2 3 2 1];
>> M = M(index, index)
M =
1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1