Grouping strings by matching substring - matlab

After running a SPICE simulation I get an .a2d file which I am parsing with Matlab. After parsing the file I get a cell array with the names of the variables
Ex: vars = {'s0';'s1';'s2';'a0';'a1'}
and a data matrix with the signals transitions, where each row represents the data of each signal and columns represent time. All the data is binary, i.e., it's only 0 or 1.
What I want to do is to create an algorithm that detects "words" based on the names stored in vars. For example, s0, s1, and s2 form a 3-bit word 's'; a0 and a1 a 2-bit word 'a'.
Finally, what I need is to break the data matrix into one array for each word (converting from binary to decimal).
I am doing that by hand, but I want to know if there is any way to do it by a script.

Here's a possible solution, putting the final values into the fields of a struct. I've used a regexp to extract the variable names and shifts as you didn't say how long they might be.
% fake data
vars = {'sums4', 'sums2', 'sums1', 'a0', 'a5'};
data(1,:) = logical([0 0 1 0 0 0 1]);
data(2,:) = logical([0 1 1 1 1 0 0]);
data(3,:) = logical([1 0 1 1 0 0 1]);
data(4,:) = logical([0 0 1 0 1 1 1]);
data(5,:) = logical([0 1 1 1 0 0 0]);
output = struct();
for i = 1:length(vars)
matches = regexp(vars{i}, '(\D+)(\d+)', 'tokens');
var = matches{1}{1};
shiftsize = str2num(matches{1}{2});
% initialise if not already present
if (~isfield(output, var))
output.(var) = zeros(1, size(data, 2));
end
% add apropriate shifted value to current values
output.(var) = output.(var) + (bitshift(1, shiftsize) * data(i, :));
end
output ends up with fields named after the string parts of vars
output =
sums: [2 4 22 6 4 0 18]
a: [0 32 33 32 1 1 1]

Related

How can I randomize two binary vectors that are similar while making sure all possible combinations are respected?

Been trying to solve this simple problem for a while but just couldn't find the solution for the life of me...
I'm programming an experiment in PsychToolbox but I'll spare you the details, basically I have two vectors A and B of equal size with the same number of ones and zeroes:
A = [0 0 1 1]
B = [0 0 1 1]
Both vectors A and B must be randomized independently but in such a way that one combination of items between the two vectors is never repeated. That is, I must end up with this
A = [1 1 0 0]
B = [1 0 0 1]
or this:
A = [0 0 1 1]
B = [0 1 0 1]
but I should never end up with this:
A = [1 1 0 0]
B = [1 1 0 0]
or this
A = [0 1 0 1]
B = [0 1 0 1]
One way to determine this is to check the sum of items between the two vectors A+B, which should always contain only one 2 or only one 0:
A = [1 1 0 0]
B = [1 0 0 1]
A+B = 2 1 0 1
Been trying to make this a condition within a 'while' loop (e.g. so long as the number of zeroes in the vector obtained by A+B is superior to 1, keep randomizing A and B), but either it still produces repeated combination or it just never stops looping. I know this is a trivial problem but I just can't get my head around it somehow. Anyone care to help?
This is a simplified version of the script I got:
A = [1 1 0 0];
B = A;
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
while nnz(~(A+B)) > 1
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
end
Still, I end up with repeated combinations.
% If you are only looking for an answer to this scenario the easiest way is
% as follows:
A = [0 0 1 1];
B = [0 0 1 1];
nn = length(A);
keepset = [0 0 1 1;0 1 0 1];
keepset = keepset(:,randperm(nn))
% If you want a more general solution for arbitrary A & B (for example)
A = [0 0 0 1 1 1 2 2 2];
B = [0 0 0 1 1 1 2 2 2];
nn = length(A);
Ai = A(randperm(nn));
Bi = B(randperm(nn));
% initialize keepset with the first combination of A & B
keepset = [Ai(1);Bi(1)];
loopcnt = 0;
while (size(keepset,2) < nn)
% randomize the elements in A and B independently
Ai = A(randperm(nn));
Bi = B(randperm(nn));
% test each combination of Ai and Bi to see if it is already in the
% keepset
for ii = 1:nn
tstcombo = [Ai(ii);Bi(ii)];
matchtest = bsxfun(#eq,tstcombo,keepset);
matchind = find((matchtest(1,:) & matchtest(2,:)));
if isempty(matchind)
keepset = [keepset tstcombo];
end
end
loopcnt = loopcnt + 1;
if loopcnt > 1000
disp('Execution halted after 1000 attempts')
break
elseif (size(keepset,2) >= nn)
disp(sprintf('Completed in %0.f iterations',loopcnt))
end
end
keepset
It's much more efficient to permute the combinations randomly than shuffling the arrays independently and handling the inevitable matching A/B elements.
There are lots of ways to generate all possible pairs, see
How to generate all pairs from two vectors in MATLAB using vectorised code?
For this example I'll use
allCombs = combvec([0,1],[0,1]);
% = [ 0 1 0 1
% 0 0 1 1 ]
Now you just want to select some amount of unique (non-repeating) columns from this array in a random order. In all of your examples you select all 4 columns. The randperm function is perfect for this, from the docs:
p = randperm(n,k) returns a row vector containing k unique integers selected randomly from 1 to n inclusive.
n = size(allCombs,2); % number of combinations (or columns) to choose from
k = 4; % number of columns to choose for output
AB = allCombs( :, randperm(n,k) ); % random selection of pairs
If you need this split into two variables then you have
A = AB(1,:);
B = AB(2,:);
Here's a possible solution:
A = [0 0 1 1];
B = [0 0 1 1];
% Randomize A and B independently
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
% Keep randomizing A and B until the condition is met
while sum(A+B) ~= 1 && sum(A+B) ~= length(A)
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
end
This solution checks if the sum of the elements in A+B is either 1 or the length of A, which indicates that only one element in A+B is either a 0 or a 2, respectively. If either of these conditions is not met, the vectors A and B are randomized again.

Finding all possible “lists” of possible pairs in Matlab

I have been thinking about a problem for the last few days but as I am a beginner in MATLAB, I have no clue how to solve it. Here is the background. Suppose that you have a symmetric N×N matrix where each element is either 0 or 1, and N = (1,2,...,n).
For example:
A =
0 1 1 0
1 0 0 1
1 0 0 0
0 1 0 0
If A(i,j) == 1, then it is possible to form the pair (i,j) and if A(i,j)==0 then it is NOT possible to form the pair (i,j). For example, (1,2) is a possible pair, as A(1,2)==A(2,1)==1 but (3,4) is NOT a possible pair as A(3,4)==A(4,3)==0.
Here is the problem. Suppose that a member of the set N only can for a pair with at most one other distinct member of the set N (i.e., if 1 forms a pair with 2, then 1 cannot form a pair with 3). How can I find all possible “lists” of possible pairs? In the above example, one “list” would only consist of the pair (1,2). If this pair is formed, then it is not possible to form any other pairs. Another “list” would be: ((1,3),(2,4)). I have searched the forum and found that the latter “list” is the maximal matching that can be found, e.g., by using a bipartite graph approach. However, I am not necessarily only interested to find the maximal matching; I am interested in finding ALL possible “lists” of possible pairs.
Another example:
A =
0 1 1 1
1 0 0 1
1 0 0 0
1 1 0 0
In this example, there are three possible lists:
(1,2)
((1,3),(2,4))
(1,4)
I hope that you can understand my question, and I apologize if am unclear. I appreciate all help I can get. Many thanks!
This might be a fast approach.
Code
%// Given data, A
A =[ 0 1 1 1;
1 0 0 1;
1 0 0 0;
1 1 0 0];
%%// The lists will be stored in 'out' as a cell array and can be accessed as out{1}, out{2}, etc.
out = cell(size(A,1)-1,1);
%%// Code that detects the lists using "selective" diagonals
for k = 1:size(A,1)-1
[x,y] = find(triu(A,k).*(~triu(ones(size(A)),k+1)));
out(k) = {[x y]};
end
out(cellfun('isempty',out))=[]; %%// Remove empty lists
%%// Verification - Print out the lists
for k = 1:numel(out)
disp(out{k})
end
Output
1 2
1 3
2 4
1 4
EDIT 1
Basically I will calculate all the the pairwise indices of the matrix to satisfy the criteria set in the question and then simply map them over the given matrix. The part of finding the "valid" indices is obviously the tedious part in it and in this code with some aggressive approach is expensive too when dealing with input matrices of sizes more than 10.
Code
%// Given data, A
A = [0 1 1 1; 1 0 1 1; 1 1 0 1; 1 1 1 0]
%%// Get all pairwise combinations starting with 1
all_combs = sortrows(perms(1:size(A,1)));
all_combs = all_combs(all_combs(:,1)==1,:);
%%// Get the "valid" indices
all_combs_diff = diff(all_combs,1,2);
valid_ind_mat = all_combs(all(all_combs_diff(:,1:2:end)>0,2),:);
valid_ind_mat = valid_ind_mat(all(diff(valid_ind_mat(:,1:2:end),1,2)>0,2),:);
%%// Map the ones of A onto the valid indices to get the lists in a matrix and then cell array
out_cell = mat2cell(valid_ind_mat,repmat(1,[1 size(valid_ind_mat,1)]),repmat(2,[1 size(valid_ind_mat,2)/2]));
A_masked = A(sub2ind(size(A),valid_ind_mat(:,1:2:end),valid_ind_mat(:,2:2:end)));
out_cell(~A_masked)={[]};
%%// Remove empty lists
out_cell(all(cellfun('isempty',out_cell),2),:)=[];
%%// Verification - Print out the lists
disp('Lists =');
for k1 = 1:size(out_cell,1)
disp(strcat(' List',num2str(k1),':'));
for k2 = 1:size(out_cell,2)
if ~isempty(out_cell{k1,k2})
disp(out_cell{k1,k2})
end
end
end
Output
A =
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0
Lists =
List1:
1 2
3 4
List2:
1 3
2 4
List3:
1 4
2 3
I'm sure there's a faster way to do it, but here's the obvious solution:
%// Set top half to 0, and find indices of all remaining 1's
A(triu(A)==1) = 0;
[ii,jj] = find(A);
%// Put these in a matrix for further processing
P = [ii jj];
%// Sort indices into 'lists' of the kind you defined
X = repmat({}, size(P,1),1);
for ii = 1:size(P,1)-1
X{ii}{1} = P(ii,:);
for jj = ii+1:size(P,1)
if ~any(ismember(P(ii,:), P(jj,:)))
X{ii}{end+1} = P(jj,:); end
end
end

Want to Create A Combination of Non-Decreasing Elements with Condition

I want to create a combination of non-decreasing elements. The combination will be like,
If i=10 and w=5, then the elements of the combination can be any value from 1 to w and the sum will be equal to i.
Possible combinations are like,
1+1+1+1+1+5
1+1+1+1+1+1+4
1+1+1+1+1+1+1+3
1+1+1+1+1+1+1+1+1+1
......
But 1+1+1+7 is not a desired combination because 7 is greater than w
How to get the combinations using MatLab? I need to get the combinations for higher values of i and w like may be i=20 and w=8.
Thank You
You can do it with a recursive function. The following code contains a wrapper function and the recursive function which does the actual work:
function result = partitions(s,M)
%// s: desired sum; M: maximum value
result = partitions_rec(s,1,M,s);
end
function mat = partitions_rec(s,m,M,n)
%// s: desired sum, m: minimum value; M: maximum value; n: number of entries
M = min(M,s);
if s==0
mat = zeros(1,n);
else
mat = [];
for ii = m:M;
aux = partitions_rec(s-ii,ii,M,n-1);
if size(aux,1)
mat = [ mat; ii*ones(size(aux,1),1) aux ];
end
end
end
end
Example:
>> result = partitions(5,3)
ans =
1 1 1 1 1
1 1 1 2 0
1 1 3 0 0
1 2 2 0 0
2 3 0 0 0
A 0 indicates no number. If you want to remove the zeros, you need to put the result in the form of a cell array, where each cell is a vector with nonzero values:
result_cell = arrayfun(#(ii) result(ii, logical(result(ii,:))), 1:size(result,1), 'uniformoutput', 0);
In the example, this would give
>> result_cell{:}
ans =
1 1 1 1 1
ans =
1 1 1 2
ans =
1 1 3
ans =
1 2 2
ans =
2 3

Create matrix using hashtable MATLAB

I am using hashtable (containers.map ) in MATLAB, and now I want to create a matrix with that information. So when I run my hashtable and then insert my text files for each type I get on my command window something like that:
edit
F = listdlg('PromptString','Different types', 'SelectionMode',...
'single', 'ListString',E, 'Name','Select a type','ListSize',[230 130]);
[files,path] = uigetfile ('*.txt','Select your text files',...
'MultiSelect','on');
where E is just the user's input which in this case is pink, purple and yellow.
%save for each type the user enters the corresponding text files he
%wants to train
%A Map object is a data structure that allows you to retrieve values
%using a corresponding key. Keys can be real numbers or text strings
%and provide more flexibility for data access than array indices,
%which must be positive integers. Values can be scalar or nonscalar arrays.
handles.map (E(F,:)) = files;
handles.map
a = handles.map.values
b = handles.map.keys
handles.map.size
b =
{1x3 cell} {1x6 cell} {1x4 cell}
a =
'pink ' 'purple' 'yellow'
So I want now to the the total number of b to be the number of rows on my matrix m ; so a total number of rows 14 and each bit from a to be a column; so a total of 3 columns. But I want to create a binary matrix where each column will identify different type. Finally I will have created a matrix like that:
m =[1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 1 0
0 1 0
0 1 0
0 0 1
0 0 1
0 0 1
0 0 1];
Where the first 3 rows of the matrix says that there are 3text files of type pink, the next 6 rows : 6 text files of type purple and the last 4: 4 text files of type yellow.
I hope that now is more clear. :)
Any help would be appreciated! :) x
So something like this?
val = cellfun(#length, b)';
m = 0;
for v = 1:size(val)
m(end:end+val(v)-1,v) = 1;
end

MATLAB matrix not formatting correctly

I have some code below, and I cant seem to get the matrices formatted correctly. I have been trying to get the matrices to look more professional (close together) with \t and fprintf, but cant seem to do so. I am also having some trouble putting titles for each columns of the matrix. Any help would be much appreciated!
clear all
clc
format('bank')
% input file values %
A = [4 6 5 1 0 0 0 0 0; 7 8 4 0 1 0 0 0 0; 6 5 9 0 0 1 0 0 0; 1 0 0 0 0 0 -1 0 0; 0 1 0 0 0 0 0 -1 0; 0 0 1 0 0 0 0 0 -1];
b = [480; 600; 480; 24; 20; 25];
c = [3000 4000 4000 0 0 0 0 0 0];
% Starting xb %
xb = [1 2 3 4 5 6]
% Starting xn %
xn = [7 8 9]
cb = c(xb)
cn = c(xn)
% Get B from A %
B = A(:,xb)
% Get N from A %
N = A(:,xn)
% Calculate z %
z = ((cb*(inv(B))*A)-c)
% Calculate B^(-1) %
Binv = inv(B)
% Calculate RHS of row 0 %
RHS0 = cb*Binv*b
% Calculates A %
A = Binv*A
%STARTING Tableau%
ST = [z RHS0;A b]
for j=1:A
fprintf(1,'\tz%d',j)
end
q = 0
while q == 0
m = input('what is the index value of the ENTERING variable? ')
n = input('what is the index value of the LEAVING variable? ')
xn(xn==m)= n
xb(xb==n) = m
cb = c(xb)
cn = c(xn)
B = A(:,xb)
N = A(:,xn)
Tableuz = (c-(cb*(B^(-1))*A))
RHS0 = (cb*(B^(-1))*b)
TableuA = ((B^(-1))*A)
Tableub = ((B^(-1))*b)
CT = [Tableuz RHS0; TableuA Tableub];
disp(CT)
q = input('Is the tableau optimal? Y-1, N-0')
end
I didn't dig into what you are doing really deeply, but a few pointers:
* Put semicolons at the end of lines you don't want printing to the screen--it makes it easier to see what is happening elsewhere.
* Your for j=1:A loop only prints j. I think what you want is more like this:
for row = 1:size(A,1)
for column = 1:size(A,2)
fprintf('%10.2f', A(row,column));
end
fprintf('\n');
end
If you haven't used the Matlab debugger yet, give it a try; it makes a lot of these problems easier to spot. All you have to do to start it is to add a breakpoint to the file by clicking on the dash(-) next to the line numbers and starting the script. Quick web searches can turn up the solution very quickly too--someone else has usually already had any problem you're going to run into.
Good luck.
Try using num2str with a format argument of your desired precision. It's meant for converting matrices to strings. (note: this is different than mat2str which serializes matrices so they can be deserialized with eval)