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)
Related
I have a 2D matrix composed of ones and zeros.
mat = [0 0 0 0 1 1 1 0 0
1 1 1 1 1 0 0 1 0
0 0 1 0 1 1 0 0 1];
I need to find all consecutive repetitions of ones in each row and replace all ones with zeros only when the sequence size is smaller than 5 (5 consecutive ones):
mat = [0 0 0 0 0 0 0 0 0
1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0];
Any suggestion on how to approach this problem would be very welcome.
You can use diff to find the start and end points of the runs of 1, and some logic based on that to zero out the runs which are too short. Please see the below code with associated comments
% Input matrix of 0s and 1s
mat = [0 0 0 0 1 1 1 0 0
1 1 1 1 1 0 0 1 0
0 0 1 0 1 1 0 0 1];
% Minimum run length of 1s to keep
N = 5;
% Get the start and end points of the runs of 1. Add in values from the
% original matrix to ensure that start and end points are always paired
d = [mat(:,1),diff(mat,1,2),-mat(:,end)];
% Find those start and end points. Use the transpose during the find to
% flip rows/cols and search row-wise relative to input matrix.
[cs,r] = find(d.'>0.5); % Start points
[ce,~] = find(d.'<-0.5); % End points
c = [cs, ce]; % Column number array for start/end
idx = diff(c,1,2) < N; % From column number, check run length vs N
% Loop over the runs which didn't satisfy the threshold and zero them
for ii = find(idx.')
mat(r(ii),c(ii,1):c(ii,2)-1) = 0;
end
If you want to throw legibility out of the window, this can be condensed for a slightly faster and denser version, based on the exact same logic:
[c,r] = find([mat(:,1),diff(mat,1,2),-mat(:,end)].'); % find run start/end points
for ii = 1:2:numel(c) % Loop over runs
if c(ii+1)-c(ii) < N % Check if run exceeds threshold length
mat(r(ii),c(ii):c(ii+1)-1) = 0; % Zero the run if not
end
end
The vectorized solution by #Wolfie is nice and concise, but a bit hard to understand and far from the wording of the problem. Here is a direct translation of the problem using loops. It has the advantage of being easier to understand and is slightly faster with less memory allocations, which means it will work for huge inputs.
[m,n] = size(mat);
for i = 1:m
j = 1;
while j <= n
seqSum = 1;
if mat(i,j) == 1
for k = j+1:n
if mat(i,k) == 1
seqSum = seqSum + 1;
else
break
end
end
if seqSum < 5
mat(i,j:j+seqSum-1) = 0;
end
end
j = j + seqSum;
end
end
I have been studying Matlab for hobby.
This is my second question in stack-overflow.
These days I have interest in Sudoku by Matlab.
I got code from internet and I am studying this code for 3 weeks.
I want to add function which indicate how many times 'sub-function(candidates)' executed. -> how many times function works for solution.
I used to use cnt = 0 and cnt=cnt+1 for count(under if statement and while statement)
but i realize this code's structure is loop(??)
*i tried it but cnt were reset when i try, i think i know the reason of reset
but i can't write it code
Thank you for your help
function X = s2(X)
% SUDOKU Solve Sudoku using recursive backtracking.
% sudoku(X), expects a 9-by-9 array X.
% Fill in all ?singletons?.
% C is a cell array of candidate vectors for each cell.
% s is the first cell, if any, with one candidate.
% e is the first cell, if any, with no candidates.
[C,s,e] = candidates(X);
while ~isempty(s) && isempty(e)
X(s) = C{s};
[C,s,e] = candidates(X);
end
% Return for impossible puzzles.
if ~isempty(e)
return
end
% Recursive backtracking.
if any(X(:) == 0)
Y = X;
z = find(X(:) == 0,1); % The first unfilled cell.
for r = [C{z}] % Iterate over candidates.
X = Y;
X(z) = r; % Insert a tentative value.
X = s2(X); % Recursive call.
if all(X(:) > 0) % Found a solution.
return
end
end
end
% ???????????????
function [C,s,e] = candidates(X)
C = cell(9,9);
tri = #(k) 3*ceil(k/3-1) + (1:3);
for j = 1:9
for i = 1:9
if X(i,j)==0
z = 1:9;
z(nonzeros(X(i,:))) = 0;
z(nonzeros(X(:,j))) = 0;
z(nonzeros(X(tri(i),tri(j)))) = 0;
C{i,j} = nonzeros(z)';
end
end
end
L = cellfun(#length,C); % Number of candidates.
s = find(X==0 & L==1,1);
e = find(X==0 & L==0,1);
end % candidates
end % s2
i used variable X
X=[4 0 0 0 2 0 0 0 0;
0 1 0 3 0 0 5 0 0;
0 0 9 0 0 8 0 6 0;
7 0 0 6 0 0 1 0 0;
0 2 0 0 0 0 0 0 9;
0 0 3 0 0 4 0 0 0;
6 0 0 7 0 0 0 2 0;
0 8 0 0 1 0 0 0 4;
0 0 0 0 0 9 3 0 0];
You could also use a persistent variable, which should retain its value across multiple calls of the function.
For example:
function [ result ] = myfactorial( num )
% using persistent variable based on
% https://www.mathworks.com/help/matlab/ref/persistent.html
persistent numcalls;
if isempty(numcalls)
numcalls = 0;
end
numcalls = numcalls+1;
disp(strcat('numcalls is now: ', int2str(numcalls)));
% factorial function based on
% https://www.quora.com/How-can-I-create-a-factorial-function-in-MATLAB
if num > 1
result = myfactorial(num-1)*num;
else
result = 1;
end
end
Now call the function.
clear all;
result = myfactorial(5);
The output is:
numcalls is now:1
numcalls is now:2
numcalls is now:3
numcalls is now:4
numcalls is now:5
How to obtain the coordinates of the first and the last appearances (under column-major ordering) of each label present in a matrix?
Example of a label matrix (where labels are 1 to 4):
L = [
1 1 1 1 0 0 0 0
0 0 0 0 2 2 0 0
0 0 0 0 0 0 2 0
0 0 0 0 0 0 0 0
0 0 0 0 0 3 0 0
0 0 0 0 0 0 3 3
0 0 0 4 0 0 0 0
4 4 4 0 0 0 0 0
];
For the above example L, I would like to obtain a matrix of coordinates like:
M = [
1 1 1
1 4 1
2 5 2
3 7 2
5 6 3
6 8 3
8 1 4
7 4 4 ];
Where the 1st column of M contains horizontal coordinates, the 2nd contains vertical coordinates, and the 3rd column contains the label. There should be 2 rows for each label.
With for-loop you can do it like that:
M=zeros(2*max(L(:)),3);
for k=1:max(L(:))
[r,c]=find(L==k);
s=sortrows([r c],2);
M(k*2-1:k*2,:)=[s(1,:) k; s(end,:) k];
end
M =
1 1 1
1 4 1
2 5 2
3 7 2
5 6 3
6 8 3
8 1 4
7 4 4
Maybe somehow with regionprops options you can do it without the loop...
I just had to try it with accumarray:
R = size(L, 1);
[rowIndex, colIndex, values] = find(L); % Find nonzero values
index = (colIndex-1).*R+rowIndex; % Create a linear index
labels = unique(values); % Find unique values
nLabels = numel(labels);
minmax = zeros(2, nLabels);
minmax(1, :) = accumarray(values, index, [nLabels 1], #min); % Collect minima
minmax(2, :) = accumarray(values, index, [nLabels 1], #max); % Collect maxima
temp = ceil(minmax(:)/R);
M = [minmax(:)-R.*(temp-1) temp repelem(labels, 2, 1)]; % Convert index to subscripts
M =
1 1 1
1 4 1
2 5 2
3 7 2
5 6 3
6 8 3
8 1 4
7 4 4
Here's what I got for timing with Dev-iL's script and Adiel's newest code (Note that the number of labels can't go above 127 due to how Adiel's code uses the uint8 values as indices):
| Adiel | Dev-iL | gnovice
-----------------------+---------+---------+---------
20 labels, 1000x1000 | 0.0753 | 0.0991 | 0.0889
20 labels, 10000x10000 | 12.0010 | 10.2207 | 8.7034
120 labels, 1000x1000 | 0.1924 | 0.3439 | 0.1387
So, for moderate numbers of labels and (relatively) smaller sizes, Adiel's looping solution looks like it does best, with my solution lying between his and Dev-iL's. For larger sizes or greater numbers of labels, my solution starts to take the lead.
If you're looking for a vectorized solution, you can do this:
nTags = max(L(:));
whois = bsxfun(#eq,L,reshape(1:nTags,1,1,[]));
% whois = L == reshape(1:nTags,1,1,[]); % >=R2016b syntax.
[X,Y,Z] = ind2sub(size(whois), find(whois));
tmp = find(diff([0; Z; nTags+1])); tmp = reshape([tmp(1:end-1) tmp(2:end)-1].',[],1);
M = [X(tmp), Y(tmp), repelem(1:nTags,2).'];
Or with extreme variable reuse:
nTags = max(L(:));
Z = bsxfun(#eq,L,reshape(1:nTags,1,1,[]));
[X,Y,Z] = ind2sub(size(Z), find(Z));
Z = find(diff([0; Z; nTags+1]));
Z = reshape([Z(1:end-1) Z(2:end)-1].',[],1);
M = [X(Z), Y(Z), repelem(1:nTags,2).'];
Here's my benchmarking code:
function varargout = b42973322(isGPU,nLabels,lMat)
if nargin < 3
lMat = 1000;
end
if nargin < 2
nLabels = 20; % if nLabels > intmax('uint8'), Change the type of L to some other uint.
end
if nargin < 1
isGPU = false;
end
%% Create L:
if isGPU
L = sort(gpuArray.randi(nLabels,lMat,lMat,'uint8'),2);
else
L = sort(randi(nLabels,lMat,lMat,'uint8'),2);
end
%% Equality test:
M{3} = DeviL2(L);
M{2} = DeviL1(L);
M{1} = Adiel(L);
assert(isequal(M{1},M{2},M{3}));
%% Timing:
% t(3) = timeit(#()DeviL2(L)); % This is always slower, so it's irrelevant.
t(2) = timeit(#()DeviL1(L));
t(1) = timeit(#()Adiel(L));
%% Output / Print
if nargout == 0
disp(t);
else
varargout{1} = t;
end
end
function M = Adiel(L)
M=[];
for k=1:max(L(:))
[r,c]=find(L==k);
s=sortrows([r c],2);
M=[M;s(1,:) k; s(end,:) k];
end
end
function M = DeviL1(L)
nTags = max(L(:));
whois = L == reshape(1:nTags,1,1,[]); % >=R2016b syntax.
[X,Y,Z] = ind2sub(size(whois), find(whois));
tmp = find(diff([0; Z; nTags+1])); tmp = reshape([tmp(1:end-1) tmp(2:end)-1].',[],1);
M = [X(tmp), Y(tmp), repelem(1:nTags,2).'];
end
function M = DeviL2(L)
nTags = max(L(:));
Z = L == reshape(1:nTags,1,1,[]);
[X,Y,Z] = ind2sub(size(Z), find(Z));
Z = find(diff([0; Z; nTags+1]));
Z = reshape([Z(1:end-1) Z(2:end)-1].',[],1);
M = [X(Z), Y(Z), repelem(1:nTags,2).'];
end
You can retrive the uniqe values (your labels) of the matrix with unique.
Having them retrived you can use find to get their indices.
Put together your matrix with it.
I have a large column vector y containing integer values from 1 to 10. I wanted to convert it to a matrix where each row is full of 0s except for a 1 at the index given by the value at the respective row of y.
This example should make it clearer:
y = [3; 4; 1; 10; 9; 9; 4; 2; ...]
% gets converted to:
Y = [
0 0 1 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 0 0;
0 0 0 0 0 0 0 0 0 1;
0 0 0 0 0 0 0 0 1 0;
0 0 0 0 0 0 0 0 1 0;
0 0 0 1 0 0 0 0 0 0;
0 1 0 0 0 0 0 0 0 0;
...
]
I have written the following code for this (it works):
m = length(y);
Y = zeros(m, 10);
for i = 1:m
Y(i, y(i)) = 1;
end
I know there are ways I could remove the for loop in this code (vectorizing). This post contains a few, including something like:
Y = full(sparse(1:length(y), y, ones(length(y),1)));
But I had to convert y to doubles to be able to use this, and the result is actually about 3x slower than my "for" approach, using 10.000.000 as the length of y.
Is it likely that doing this kind of vectorization will lead to better performance for a very large y? I've read many times that vectorizing calculations leads to better performance (not only in MATLAB), but this kind of solution seems to result in more calculations.
Is there a way to actually improve performance over the for approach in this example? Maybe the problem here is simply that acting on doubles instead of ints isn't the best thing for comparison, but I couldn't find a way to use sparse otherwise.
Here is a test to comapre:
function [t,v] = testIndicatorMatrix()
y = randi([1 10], [1e6 1], 'double');
funcs = {
#() func1(y);
#() func2(y);
#() func3(y);
#() func4(y);
};
t = cellfun(#timeit, funcs, 'Uniform',true);
v = cellfun(#feval, funcs, 'Uniform',false);
assert(isequal(v{:}))
end
function Y = func1(y)
m = numel(y);
Y = zeros(m, 10);
for i = 1:m
Y(i, y(i)) = 1;
end
end
function Y = func2(y)
m = numel(y);
Y = full(sparse(1:m, y, 1, m, 10, m));
end
function Y = func3(y)
m = numel(y);
Y = zeros(m,10);
Y(sub2ind([m,10], (1:m).', y)) = 1;
end
function Y = func4(y)
m = numel(y);
Y = zeros(m,10);
Y((y-1).*m + (1:m).') = 1;
end
I get:
>> testIndicatorMatrix
ans =
0.0388
0.1712
0.0490
0.0430
Such a simple for-loop can be dynamically JIT-compiled at runtime, and would run really fast (even slightly faster than vectorized code)!
It seems you are looking for that full numeric matrix Y as the output. So, you can try this approach -
m = numel(y);
Y1(m,10) = 0; %// Faster way to pre-allocate zeros than using function call `zeros`
%// Source - http://undocumentedmatlab.com/blog/preallocation-performance
linear_idx = (y-1)*m+(1:m)'; %//'# since y is mentioned as a column vector,
%// so directly y can be used instead of y(:)
Y1(linear_idx)=1; %// Y1 would be the desired output
Benchmarking
Using Amro's benchmark post and increasing the datasize a bit -
y = randi([1 10], [1.5e6 1], 'double');
And finally doing the faster pre-allocation scheme mentioned earlier of using Y(m,10)=0; instead of Y = zeros(m,10);, I got these results on my system -
>> testIndicatorMatrix
ans =
0.1798
0.4651
0.1693
0.1457
That is the vectorized approach mentioned here (the last one in the benchmark suite) is giving you more than 15% performance improvement over your for-loop code (the first one in the benchmark suite). So, if you are using large datasizes and intend to get full versions of sparse matrices, this approach would make sense (in my personal opinion).
Does something like this not work for you?
tic;
N = 1e6;
y = randperm( N );
Y = spalloc( N, N, N );
inds = sub2ind( size(Y), y(:), (1:N)' );
Y = sparse( 1:N, y, 1, N, N, N );
toc
The above outputs
Elapsed time is 0.144683 seconds.
I have the following code that includes 3 iterated for loops in order to create an upper diagonal matrix, I plan on performing on large data set many times and want to make as computationally efficient as possible.
data = magic(3);
n = size(data,1);
W = zeros(n,n);
for i = 1:n
for j = i:n
if i==j
W(i,j)=0;
else
for k = 1:n
temp(1,k) = (data(i,k)-data(j,k))^2;
sumTemp = sumTemp + temp(1,k);
end
W(i,j)=sqrt(sumTemp);
end
temp = 0;
sumTemp = 0;
end
end
Answer should look like:
[0 6.4807 9.7980
0 0 6.4807
0 0 0]
I am working it hard right now, but figure I would throw it out there in case anyone has any suggestions that would save me hours of fiddling around.
This is hat I have at the moment:
data = magic(3);
n = size(data,1);
W = zeros(n,n);
for i = 1:n
for j = i+1:n
W(i,j)= norm(data(i,:)-data(j,:))
%W(i,j)= sqrt(sum((data(i,:)-data(j,:)).^2));
end
end
What I did:
vecorized the inner loop
removed www, which is unused
changed 2nd loop, start at i+1 because nothing is done for i=j
Replaced sqrt((a-b).^2) with norm(a-b)
And now the "full" vectorization:
data = magic(3);
n = size(data,1);
W = zeros(n,n);
tri=triu(ones(n,n),1)>0;
[i,j]=find(tri);
W(tri)=arrayfun(#(i,j)norm(data(i,:)-data(j,:)),i,j)
Here is a straightforward solution with bsxfun:
Wfull = sqrt(squeeze(sum(bsxfun(#minus,data,permute(data,[3 2 1])).^2,2)))
W = triu(Wfull)
Use this where data is N-by-D, where N is the number of points and D is dimensions. For example,
>> data = magic(3);
>> triu(sqrt(squeeze(sum(bsxfun(#minus,data,permute(data,[3 2 1])).^2,2))))
ans =
0 6.4807 9.7980
0 0 6.4807
0 0 0
>> data = magic(5); data(:,end-1:end)=[]
data =
17 24 1
23 5 7
4 6 13
10 12 19
11 18 25
>> triu(sqrt(squeeze(sum(bsxfun(#minus,data,permute(data,[3 2 1])).^2,2))))
ans =
0 20.8087 25.2389 22.7376 25.4558
0 0 19.9499 19.0263 25.2389
0 0 0 10.3923 18.3576
0 0 0 0 8.5440
0 0 0 0 0
>>