Plotting numbers in a Cell array - matlab

I want to just plot the data, which is all real numbers, that is stored in a Cell Array. My cell array is 1-100 1-dimensional, but I am confused on how to actually apply the plot() function with the hold on function.
Here is my code:
% Initalize arrays for storing data
C = cell(1,100); % Store output vector from floww()
D = cell(1,6); % User inputted initial point
I1 = cell(1,100);
I2 = cell(1,100);
I3 = cell(1,100);
%Declare alpha and beta variables detailed in Theorem 1 of paper
a1 = 0; a2 = 2; a3 = 4; a4 = 6;
b1 = 2; b2 = 3; b3 = 7; b4 = 10;
% Declare the \lambda_i, i=1,..., 6, variables
L = cell(1,6);
L1 = abs((b2 - b3)/(a2 - a3));
L2 = abs((b1 - b3)/(a1 - a3));
L3 = abs((b1 - b2)/(a1 - a2));
L4 = abs((b1 - b4)/(a1 - a4));
L5 = abs((b2 - b4)/(a2 - a4));
L6 = abs((b3 - b4)/(a3 - a4));
L{1,1} = L1;
L{1,2} = L2;
L{1,3} = L3;
L{1,4} = L4;
L{1,5} = L5;
L{1,6} = L6;
% Create function handle for floww()
F = #floww;
for j = 1:6
D{1,j} = input('Input in1 through in6: ');
end
% Iterate through floww()
k = [0:5:100];
for i = 1: 100
C{1,i} = F(D{1,1}, D{1,2}, D{1,3}, D{1,4}, D{1,5}, D{1,6},L); % Output from floww() is a 6-by-1 vector
for j = 1:6
D{1,j} = C{1,i}(j,1); % Reassign input values to put back into floww()
end
% First integrals as described in the paper
I1{1,i} = 2*(C{1,i}(1,1)).^2 + 2*(C{1,i}(2,1)).^2 + 2*(C{1,i}(3,1)).^2 + 2*(C{1,i}(4,1)).^2 + 2*(C{1,i}(5,1)).^2 + 2*(C{1,i}(6,1)).^2;
I2{1,i} = (-C{1,i}(3,1))*(-C{1,i}(6,1)) - (C{1,i}(2,1))*(-C{1,i}(5,1)) + (-C{1,i}(1,1))*(-C{1,i}(4,1));
I3{1,i} = 2*L1*(C{1,i}(1,1)).^2 + 2*L2*(C{1,i}(2,1)).^2 + 2*L3*(C{1,i}(3,1)).^2 + 2*L4*(C{1,i}(4,1)).^2 + 2*L5*(C{1,i}(5,1)).^2 + 2*L6*(C{1,i}(6,1)).^2;
plot(k, I1{1,i});
hold on;
end
% This function will solve the linear system
% Bx^(n+1) = x detailed in the research notes
function [out1] = floww(in1, in2, in3, in4, in5, in6, L)
% A_ij = (lambda_i - lambda_j)
% Declare relevant A_ij values
A32 = L{1,3} - L{1,2};
A65 = L{1,6} - L{1,5};
A13 = L{1,1} - L{1,3};
A46 = L{1,4} - L{1,6};
A21 = L{1,2} - L{1,1};
A54 = L{1,5} - L{1,4};
A35 = L{1,3} - L{1,5};
A62 = L{1,6} - L{1,2};
A43 = L{1,4} - L{1,3};
A16 = L{1,1} - L{1,6};
A24 = L{1,2} - L{1,4};
A51 = L{1,5} - L{1,1};
% Declare del(T)
delT = 1;
% Declare the 6-by-6 coefficient matrix B
B = [1, -A32*(delT/2)*in3, -A32*(delT/2)*in2, 0, -A65*(delT/2)*in6, -A65*(delT/2)*in5;
-A13*(delT/2)*in3, 1, -A13*(delT/2)*in1, -A46*(delT/2)*in6, 0, A46*(delT/2)*in4;
-A21*(delT/2)*in2, -A21*(delT/2)*in1, 1, -A54*(delT/2)*in5, -A54*(delT/2)*in4, 0;
0, -A62*(delT/2)*in6, -A35*(delT/2)*in5, 1, -A35*(delT/2)*in3, -A62*(delT/2)*in2;
-A16*(delT/2)*in6, 0, -A43*(delT/2)*in4, -A43*(delT/2)*in3, 1, -A16*(delT/2)*in1;
-A51*(delT/2)*in5, -A24*(delT/2)*in4, 0, -A24*(delT/2)*in2, -A51*(delT/2)*in1, 1];
% Declare input vector
N = [in1; in2; in3; in4; in5; in6];
% Solve the system Bx = N for x where x
% denotes the X_i^(n+1) vector in research notes
x = B\N;
% Assign output variables
out1 = x;
%disp(x);
%disp(out1(2,1));
end
The plotting takes place in the for-loop with plot(k, I1{1,i});. The figure that is outputted is not what I expect nor want:
Can someone please explain to me what I am doing wrong and/or how to get what I want?

You need to stop using cell arrays for numeric data, and indexed variable names when an array would be way simpler.
I've edited your code, below, to plot the I1 array.
To make it work, I changed almost all cell arrays to numeric arrays and simplified a bunch of the indexing. Note initialisation is now with zeros instead of cell, therefore indexing with parentheses () not curly braces {}.
I didn't change the structure too much, because your comments indicated you were following some literature with this layout
For the plotting, you were trying to plot single points during the loop - to do that you have no line (the points are distinct), so need to specify a marker like plot(x,y,'o'). However, what I've done is just plot after the loop - since you're storing the resulting I1 array anyway.
% Initalize arrays for storing data
C = cell(1,100); % Store output vector from floww()
D = zeros(1,6); % User inputted initial point
I1 = zeros(1,100);
I2 = zeros(1,100);
I3 = zeros(1,100);
%Declare alpha and beta variables detailed in Theorem 1 of paper
a1 = 0; a2 = 2; a3 = 4; a4 = 6;
b1 = 2; b2 = 3; b3 = 7; b4 = 10;
% Declare the \lambda_i, i=1,..., 6, variables
L = zeros(1,6);
L(1) = abs((b2 - b3)/(a2 - a3));
L(2) = abs((b1 - b3)/(a1 - a3));
L(3) = abs((b1 - b2)/(a1 - a2));
L(4) = abs((b1 - b4)/(a1 - a4));
L(5) = abs((b2 - b4)/(a2 - a4));
L(6) = abs((b3 - b4)/(a3 - a4));
for j = 1:6
D(j) = input('Input in1 through in6: ');
end
% Iterate through floww()
for i = 1:100
C{i} = floww(D(1), D(2), D(3), D(4), D(5), D(6), L); % Output from floww() is a 6-by-1 vector
for j = 1:6
D(j) = C{i}(j,1); % Reassign input values to put back into floww()
end
% First integrals as described in the paper
I1(i) = 2*(C{i}(1,1)).^2 + 2*(C{i}(2,1)).^2 + 2*(C{i}(3,1)).^2 + 2*(C{i}(4,1)).^2 + 2*(C{i}(5,1)).^2 + 2*(C{i}(6,1)).^2;
I2(i) = (-C{i}(3,1))*(-C{i}(6,1)) - (C{i}(2,1))*(-C{i}(5,1)) + (-C{i}(1,1))*(-C{i}(4,1));
I3(i) = 2*L(1)*(C{i}(1,1)).^2 + 2*L(2)*(C{i}(2,1)).^2 + 2*L(3)*(C{i}(3,1)).^2 + 2*L(4)*(C{i}(4,1)).^2 + 2*L(5)*(C{i}(5,1)).^2 + 2*L(6)*(C{i}(6,1)).^2;
end
plot(1:100, I1);
% This function will solve the linear system
% Bx^(n+1) = x detailed in the research notes
function [out1] = floww(in1, in2, in3, in4, in5, in6, L)
% A_ij = (lambda_i - lambda_j)
% Declare relevant A_ij values
A32 = L(3) - L(2);
A65 = L(6) - L(5);
A13 = L(1) - L(3);
A46 = L(4) - L(6);
A21 = L(2) - L(1);
A54 = L(5) - L(4);
A35 = L(3) - L(5);
A62 = L(6) - L(2);
A43 = L(4) - L(3);
A16 = L(1) - L(6);
A24 = L(2) - L(4);
A51 = L(5) - L(1);
% Declare del(T)
delT = 1;
% Declare the 6-by-6 coefficient matrix B
B = [1, -A32*(delT/2)*in3, -A32*(delT/2)*in2, 0, -A65*(delT/2)*in6, -A65*(delT/2)*in5;
-A13*(delT/2)*in3, 1, -A13*(delT/2)*in1, -A46*(delT/2)*in6, 0, A46*(delT/2)*in4;
-A21*(delT/2)*in2, -A21*(delT/2)*in1, 1, -A54*(delT/2)*in5, -A54*(delT/2)*in4, 0;
0, -A62*(delT/2)*in6, -A35*(delT/2)*in5, 1, -A35*(delT/2)*in3, -A62*(delT/2)*in2;
-A16*(delT/2)*in6, 0, -A43*(delT/2)*in4, -A43*(delT/2)*in3, 1, -A16*(delT/2)*in1;
-A51*(delT/2)*in5, -A24*(delT/2)*in4, 0, -A24*(delT/2)*in2, -A51*(delT/2)*in1, 1];
% Declare input vector
N = [in1; in2; in3; in4; in5; in6];
% Solve the system Bx = N for x where x
% denotes the X_i^(n+1) vector in research notes
x = B\N;
% Assign output variables
out1 = x;
end
Output with in1..6 = 1 .. 6:
Note: you could simplify this code a lot if you embraced arrays over clunky variable names. The below achieves the exact same result for the body of your script, but is much more flexible and maintainable:
See how much simpler your integral expressions become!
% Initalize arrays for storing data
C = cell(1,100); % Store output vector from floww()
D = zeros(1,6); % User inputted initial point
I1 = zeros(1,100);
I2 = zeros(1,100);
I3 = zeros(1,100);
%Declare alpha and beta variables detailed in Theorem 1 of paper
a = [0, 2, 4, 6];
b = [2, 3, 7, 10];
% Declare the \lambda_i, i=1,..., 6, variables
L = abs( ( b([2 1 1 1 2 3]) - b([3 3 2 4 4 4]) ) ./ ...
( a([2 1 1 1 2 3]) - a([3 3 2 4 4 4]) ) );
for j = 1:6
D(j) = input('Input in1 through in6: ');
end
% Iterate through floww()
k = 1:100;
for i = k
C{i} = floww(D(1), D(2), D(3), D(4), D(5), D(6), L); % Output from floww() is a 6-by-1 vector
D = C{i}; % Reassign input values to put back into floww()
% First integrals as described in the paper
I1(i) = 2*sum(D.^2);
I2(i) = sum( D(1:3).*D(4:6) );
I3(i) = 2*sum((L.').*D.^2).^2;
end
plot( k, I1 );
Edit:
You can simplify the floww function by using a couple of things
A can be declared really easily as a single matrix.
Notice delT/2 is a factor in almost every element, factor it out!
The only non-zero elements where delT/2 isn't a factor are the diagonal of ones... add this in using eye instead.
Input the in1..6 variables as a vector. You already have the vector when you call floww - makes no sense breaking it up.
With the input as a vector, we can use utility functions like hankel to do some neat indexing. This one is a stretch for a beginner, but I include it as a demo.
Code:
% In code body, call floww with an array input
C{i} = floww(D, L);
% ...
function [out1] = floww(D, L)
% A_ij = (lambda_i - lambda_j)
% Declare A_ij values in a matrix
A = L.' - L;
% Declare del(T)
delT = 1;
% Declare the 6-by-6 coefficient matrix B
% Factored out (delt/2) and the D coefficients
B = eye(6,6) - (delT/2) * D( hankel( [4 3 2 1 6 5], [5 4 3 2 1 6] ) ) .*...
[ 0, A(3,2), A(3,2), 0, A(6,5), A(6,5);
A(1,3), 0, A(1,3), A(4,6), 0, -A(4,6);
A(2,1), A(2,1), 0, A(5,4), A(5,4), 0;
0, A(6,2), A(3,5), 0, A(3,5), A(6,2);
A(1,6), 0, A(4,3), A(4,3), 0, A(1,6);
A(5,1), A(2,4), 0, A(2,4), A(5,1), 0];
% Solve the system Bx = N for x where x
% denotes the X_i^(n+1) vector in research notes
out1 = B\D(:);
end
You see when we simplify things like this, code is easier to read. For instance, it looks to me (without knowing the literature at all) like you've got a sign error in your B(2,6) element, it's the opposite sign to all other elements...

Related

Unable to perform assignment because the size of the left side is 1-by-7-by-7 and the size of the right side is 6-by-6 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am looking for a way to find same eigenvectors for 2 given matrices, this way I would make a joint diagonalisation. For this, I found out and tried to use qndiag (from https://github.com/pierreablin/qndiag.git ) from the following function :
function [D, B, infos] = qndiag(C, varargin)
% Joint diagonalization of matrices using the quasi-Newton method
%
% The algorithm is detailed in:
%
% P. Ablin, J.F. Cardoso and A. Gramfort. Beyond Pham’s algorithm
% for joint diagonalization. Proc. ESANN 2019.
% https://www.elen.ucl.ac.be/Proceedings/esann/esannpdf/es2019-119.pdf
% https://hal.archives-ouvertes.fr/hal-01936887v1
% https://arxiv.org/abs/1811.11433
%
% The function takes as input a set of matrices of size `(p, p)`, stored as
% a `(n, p, p)` array, `C`. It outputs a `(p, p)` array, `B`, such that the
% matrices `B * C(i,:,:) * B'` are as diagonal as possible.
%
% There are several optional parameters which can be provided in the
% varargin variable.
%
% Optional parameters:
% --------------------
% 'B0' Initial point for the algorithm.
% If absent, a whitener is used.
% 'weights' Weights for each matrix in the loss:
% L = sum(weights * KL(C, C')).
% No weighting (weights = 1) by default.
% 'maxiter' (int) Maximum number of iterations to perform.
% Default : 1000
%
% 'tol' (float) A positive scalar giving the tolerance at
% which the algorithm is considered to have converged.
% The algorithm stops when |gradient| < tol.
% Default : 1e-6
%
% lambda_min (float) A positive regularization scalar. Each
% eigenvalue of the Hessian approximation below
% lambda_min is set to lambda_min.
%
% max_ls_tries (int), Maximum number of line-search tries to
% perform.
%
% return_B_list (bool) Chooses whether or not to return the list
% of iterates.
%
% verbose (bool) Prints informations about the state of the
% algorithm if True.
%
% Returns
% -------
% D : Set of matrices jointly diagonalized
% B : Estimated joint diagonalizer matrix.
% infos : structure containing monitoring informations, containing the times,
% gradient norms and objective values.
%
% Example:
% --------
%
% [D, B] = qndiag(C, 'maxiter', 100, 'tol', 1e-5)
%
% Authors: Pierre Ablin <pierre.ablin#inria.fr>
% Alexandre Gramfort <alexandre.gramfort#inria.fr>
%
% License: MIT
% First tests
if nargin == 0,
error('No signal provided');
end
if length(size(C)) ~= 3,
error('Input C should be 3 dimensional');
end
if ~isa (C, 'double'),
fprintf ('Converting input data to double...');
X = double(X);
end
% Default parameters
C_mean = squeeze(mean(C, 1));
[p, d] = eigs(C_mean);
p = fliplr(p);
d = flip(diag(d));
B = p' ./ repmat(sqrt(d), 1, size(p, 1));
max_iter = 1000;
tol = 1e-6;
lambda_min = 1e-4;
max_ls_tries = 10;
return_B_list = false;
verbose = false;
weights = [];
% Read varargin
if mod(length(varargin), 2) == 1,
error('There should be an even number of optional parameters');
end
for i = 1:2:length(varargin)
param = lower(varargin{i});
value = varargin{i + 1};
switch param
case 'B0'
B0 = value;
case 'max_iter'
max_iter = value;
case 'tol'
tol = value;
case 'weights'
weights = value / mean(value(:));
case 'lambda_min'
lambda_min = value;
case 'max_ls_tries'
max_ls_tries = value;
case 'return_B_list'
return_B_list = value;
case 'verbose'
verbose = value;
otherwise
error(['Parameter ''' param ''' unknown'])
end
end
[n_samples, n_features, ~] = size(C);
D = transform_set(B, C, false);
current_loss = NaN;
% Monitoring
if return_B_list
B_list = []
end
t_list = [];
gradient_list = [];
loss_list = [];
if verbose
print('Running quasi-Newton for joint diagonalization');
print('iter | obj | gradient');
end
for t=1:max_iter
if return_B_list
B_list(k) = B;
end
diagonals = zeros(n_samples, n_features);
for k=1:n_samples
diagonals(k, :) = diag(squeeze(D(k, :, :)));
end
% Gradient
if isempty(weights)
G = squeeze(mean(bsxfun(#rdivide, D, ...
reshape(diagonals, n_samples, n_features, 1)), ...
1)) - eye(n_features);
else
G = squeeze(mean(...
bsxfun(#times, ...
reshape(weights, n_samples, 1, 1), ...
bsxfun(#rdivide, D, ...
reshape(diagonals, n_samples, n_features, 1))), ...
1)) - eye(n_features);
end
g_norm = norm(G);
if g_norm < tol
break
end
% Hessian coefficients
if isempty(weights)
h = mean(bsxfun(#rdivide, ...
reshape(diagonals, n_samples, 1, n_features), ...
reshape(diagonals, n_samples, n_features, 1)), 1);
else
h = mean(bsxfun(#times, ...
reshape(weights, n_samples, 1, 1), ...
bsxfun(#rdivide, ...
reshape(diagonals, n_samples, 1, n_features), ...
reshape(diagonals, n_samples, n_features, 1))), ...
1);
end
h = squeeze(h);
% Quasi-Newton's direction
dt = h .* h' - 1.;
dt(dt < lambda_min) = lambda_min; % Regularize
direction = -(G .* h' - G') ./ dt;
% Line search
[success, new_D, new_B, new_loss, direction] = ...
linesearch(D, B, direction, current_loss, max_ls_tries, weights);
D = new_D;
B = new_B;
current_loss = new_loss;
% Monitoring
gradient_list(t) = g_norm;
loss_list(t) = current_loss;
if verbose
print(sprintf('%d - %.2e - %.2e', t, current_loss, g_norm))
end
end
infos = struct();
infos.t_list = t_list;
infos.gradient_list = gradient_list;
infos.loss_list = loss_list;
if return_B_list
infos.B_list = B_list
end
end
function [op] = transform_set(M, D, diag_only)
[n, p, ~] = size(D);
if ~diag_only
op = zeros(n, p, p);
for k=1:length(D)
op(k, :, :) = M * squeeze(D(k, :, :)) * M';
end
else
op = zeros(n, p);
for k=1:length(D)
op(k, :) = sum(M .* (squeeze(D(k, :, :)) * M'), 1);
end
end
end
function [v] = slogdet(A)
v = log(abs(det(A)));
end
function [out] = loss(B, D, is_diag, weights)
[n, p, ~] = size(D);
if ~is_diag
diagonals = zeros(n, p);
for k=1:n
diagonals(k, :) = diag(squeeze(D(k, :, :)));
end
else
diagonals = D;
end
logdet = -slogdet(B);
if ~isempty(weights)
diagonals = bsxfun(#times, diagonals, reshape(weights, n, 1));
end
out = logdet + 0.5 * sum(log(diagonals(:))) / n;
end
function [success, new_D, new_B, new_loss, delta] = linesearch(D, B, direction, current_loss, n_ls_tries, weights)
[n, p, ~] = size(D);
step = 1.;
if current_loss == NaN
current_loss = loss(B, D, false);
end
success = false;
for n=1:n_ls_tries
M = eye(p) + step * direction;
new_D = transform_set(M, D, true);
new_B = M * B;
new_loss = loss(new_B, new_D, true, weights);
if new_loss < current_loss
success = true;
break
end
step = step / 2;
end
new_D = transform_set(M, D, false);
delta = step * direction;
end
I use it with the following script that you can test with downloading the 2 input matrices at the bottom of this post :
clc; clear
m=7 % dimension
n=2 % number of matrices
% Load spectro and WL+GCph+XC
FISH_GCsp = load('Fisher_GCsp_flat.txt');
FISH_XC = load('Fisher_XC_GCph_WL_flat.txt');
% Marginalizing over uncommon parameters between the two matrices
COV_GCsp_first = inv(FISH_GCsp);
COV_XC_first = inv(FISH_XC);
COV_GCsp = COV_GCsp_first(1:m,1:m);
COV_XC = COV_XC_first(1:m,1:m);
% Invert to get Fisher matrix
FISH_sp = inv(COV_GCsp);
FISH_xc = inv(COV_XC);
% Drawing a random set of commuting matrices
C=zeros(n,m,m);
B0=zeros(n,m,m);
C(1,:,:) = FISH_sp
C(2,:,:) = FISH_xc
%[D, B] = qndiag(C, 'max_iter', 1e6, 'tol', 1e-6);
[D, B] = qndiag(C);
% Print diagonal matrices
B*C(1,:,:)*B'
B*C(2,:,:)*B'
But unfortunately, I get the following error :
Unable to perform assignment because the size of the left side is 1-by-7-by-7 and the size of the
right side is 6-by-6.
Error in qndiag>transform_set (line 224)
op(k, :, :) = M * squeeze(D(k, :, :)) * M';
Error in qndiag (line 128)
D = transform_set(B, C, false);
Error in compute_joint_diagonalization (line 32)
[D, B] = qndiag(C);
I don't understand the utility of function squeeze the most important : why the function eigs returns only 6 values and not 7 like in my data (the input matrices has 7x7 size).
What might be wrong with this issue of array dimension and how can I fix it ?
I put the 2 input files available here :
Matrix Fisher_GCsp_flat.txt
Matrix Fisher_XC_GCph_WL_flat.txt
You can test the above code that calls qndiag for these 2 matrices.
Update 1
To allow people interested to test quickly the code, I put a link of the archive:
Archive_Matlab_StackOver.tar
You just have to untar and execute under Matlab the script compute_joint_diagonalization.m and you will see normally the above error (regarding the use of eigs and squeeze functions).
It should help you understand the origin of this issue.
Update 2
If I replace [p, d] = eigs(C_mean) by [p, d] = eigs(C_mean,7) , I get another error :
Index in position 1 exceeds array bounds (must not exceed 2).
Error in qndiag>transform_set (line 224)
op(k, :, :) = M * squeeze(D(k, :, :)) * M';
Error in qndiag (line 128)
D = transform_set(B, C, false);
Error in compute_joint_diagonalization (line 27)
[D, B] = qndiag(C);
However, the dimensions of the 2 matrices used are 7x7 and should be correctly processed with eigs(C_mean,7).
Update 3
The size of op, D, M and k are equal to (including after the error message) :
size(D) =
2 7 7
length(D) =
7
size(M) =
7 7
size(op) =
2 7 7
Index in position 1 exceeds array bounds (must not exceed 2).
Error in qndiag>transform_set (line 231)
op(k, :, :) = M * squeeze(D(k, :, :)) * M';
Error in qndiag (line 128)
D = transform_set(B, C, false);
Error in compute_joint_diagonalization (line 27)
[D, B] = qndiag(C);
Notice that k varies from 1 to length(D)=7.
Is there an issue which could appear with these dimensions ?
From the documentation for eigs:
d = eigs(A) returns a vector of the six largest magnitude eigenvalues of matrix A.
If you want all seven, you need to call d = eigs(A,7) or d = eig(A). For a small matrix (e.g. < 1000 x 1000) it's usually easier to just get all the eigenvalues with eig, rather than get a subset with eigs.
Edit: Responding to your "Update 3"
for k=1:length(D) should be replaced by for k=1:n. This needs to be changed on two lines. Judging from your error message they are lines 231 and 236.
L = length(X) returns the length of the largest array dimension in X, which in your case is 7, i.e. too high for the first dimension.

Cumulative count of unique element in Matlab array

Working with Matlab 2019b.
x = [10 10 10 20 20 30]';
How do I get a cumulative count of unique elements in x, which should look like:
y = [1 2 3 1 2 1]';
EDIT:
My real array is actually much longer than the example given above. Below are the methods I tested:
x = randi([1 100], 100000, 1);
x = sort(x);
% method 1: check neighboring values in one loop
tic
y = ones(size(x));
for ii = 2:length(x)
if x(ii) == x(ii-1)
y(ii) = y(ii-1) + 1;
end
end
toc
% method 2 (Wolfie): count occurrence of unique values explicitly
tic
u = unique(x);
y = zeros(size(x));
for ii = 1:numel(u)
idx = (x == u(ii));
y(idx) = 1:nnz(idx);
end
toc
% method 3 (Luis Mendo): triangular matrix
tic
y = sum(triu(x==x'))';
toc
Results:
Method 1: Elapsed time is 0.016847 seconds.
Method 2: Elapsed time is 0.037124 seconds.
Method 3: Elapsed time is 10.350002 seconds.
EDIT:
Assuming that x is sorted:
x = [10 10 10 20 20 30].';
x = sort(x);
d = [1 ;diff(x)];
f = find(d);
d(f) = f;
ic = cummax(d);
y = (2 : numel(x) + 1).' - ic;
When x is unsorted use this:
[s, is] = sort(x);
d = [1 ;diff(s)];
f = find(d);
d(f) = f;
ic = cummax(d);
y(is) = (2 : numel(s) + 1).' - ic;
Original Answer that only works on GNU Octave:
Assuming that x is sorted:
x = [10 10 10 20 20 30].';
x = sort(x);
[~, ic] = cummax(x);
y = (2 : numel(x) + 1).' - ic;
When x is unsorted use this:
[s, is] = sort(x);
[~, ic] = cummax(s);
y(is) = (2 : numel(s) + 1).' - ic;
You could loop over the unique elements, and set their indices to 1:n each time...
u = unique(x);
y = zeros(size(x));
for ii = 1:numel(u)
idx = (x == u(ii));
y(idx) = 1:nnz(idx);
end
This is a little inefficient because it generates an intermediate matrix, when actually only a triangular half is needed:
y = sum(triu(x==x.')).';
Here's a no-for-loop version. On my machine it's a bit faster than the previous working methods:
% if already sorted, can omit this first and last line
[s, is] = sort(x);
[u,~,iu] = unique(s);
c = accumarray(iu,1);
cs = cumsum([0;c]);
z = (1:numel(x))'-repelem(cs(1:end-1),c);
y(is) = z;

Can't recover the parameters of a model using ode45

I am trying to simulate the rotation dynamics of a system. I am testing my code to verify that it's working using simulation, but I never recovered the parameters I pass to the model. In other words, I can't re-estimate the parameters I chose for the model.
I am using MATLAB for that and specifically ode45. Here is my code:
% Load the input-output data
[torque outputs] = DataLogs2();
u = torque;
% using the simulation data
Ixx = 1.00;
Iyy = 2.00;
Izz = 3.00;
x0 = [0; 0; 0];
Ts = .02;
t = 0:Ts:Ts * ( length(u) - 1 );
[ T, x ] = ode45( #(t,x) rotationDyn( t, x, u(1+floor(t/Ts),:), Ixx, Iyy, Izz), t, x0 );
w = x';
N = length(w);
q = 1; % a counter for the A and B matrices
% The Algorithm
for k=1:1:N
w_telda = [ 0 -w(3, k) w(2,k); ...
w(3,k) 0 -w(1,k); ...
-w(2,k) w(1,k) 0 ];
if k == N % to handle the problem of the last iteration
w_dash(:,k) = (-w(:,k))/Ts;
else
w_dash(:,k) = (w(:,k+1)-w(:,k))/Ts;
end
a = kron( w_dash(:,k)', eye(3) ) + kron( w(:,k)', w_telda );
A(q:q+2,:) = a; % a 3N*9 matrix
B(q:q+2,:) = u(k,:)'; % a 3N*1 matrix % u(:,k)
q = q + 3;
end
% Forcing J to be diagonal. This is the case when we consider our quadcopter as two thin uniform
% rods crossed at the origin with a point mass (motor) at the end of each.
A_new = [A(:, 1) A(:, 5) A(:, 9)];
vec_J_diag = A_new\B;
J_diag = diag([vec_J_diag(1), vec_J_diag(2), vec_J_diag(3)])
eigenvalues_J_diag = eig(J_diag)
error = norm(A_new*vec_J_diag - B)
where my dynamic model is defined as:
function [dw, y] = rotationDyn(t, w, tau, Ixx, Iyy, Izz, varargin)
% The output equation
y = [w(1); w(2); w(3)];
% State equation
% dw = (I^-1)*( tau - cross(w, I*w) );
dw = [Ixx^-1 * tau(1) - ((Izz-Iyy)/Ixx)*w(2)*w(3);
Iyy^-1 * tau(2) - ((Ixx-Izz)/Iyy)*w(1)*w(3);
Izz^-1 * tau(3) - ((Iyy-Ixx)/Izz)*w(1)*w(2)];
end
Practically, what this code should do, is to calculate the eigenvalues of the inertia matrix, J, i.e. to recover Ixx, Iyy, and Izz that I passed to the model at the very begining (1, 2 and 3), but all what I get is wrong results.
Is the problem with using ode45?
Well the problem wasn't in the ode45 instruction, the problem is that in system identification one can create an n-1 samples-signal from an n samples-signal, thus the loop has to end at N-1 in the above code.

Vectorizing a nested for loop which fills a dynamic programming table

I was wondering if there was a way to vectorize the nested for loop in this function which is filling up the entries of the 2D dynamic programming table DP. I believe that at the very least the inner loop could be vectorized as each row only depends on the previous row. I'm not sure how to do it though. Note this function is called on large 2D arrays (images) so the nested for loop really doesn't cut it.
function [cols] = compute_seam(energy)
[r, c, ~] = size(energy);
cols = zeros(r);
DP = padarray(energy, [0, 1], Inf);
BP = zeros(r, c);
for i = 2 : r
for j = 1 : c
[x, l] = min([DP(i - 1, j), DP(i - 1, j + 1), DP(i - 1, j + 2)]);
DP(i, j + 1) = DP(i, j + 1) + x;
BP(i, j) = j + (l - 2);
end
end
[~, j] = min(DP(r, :));
j = j - 1;
for i = r : -1 : 1
cols(i) = j;
j = BP(i, j);
end
end
Vectorization of the innermost nested loop
You were right in postulating that at least the inner loop is vectorizable. Here's the modified code for the nested loops part -
rows_DP = size(DP,1); %// rows in DP
%// Get first row linear indices for a group of neighboring three columns,
%// which would be incremented as we move between rows with the row iterator
start_ind1 = bsxfun(#plus,[1:rows_DP:2*rows_DP+1]',[0:c-1]*rows_DP); %//'
for i = 2 : r
ind1 = start_ind1 + i-2; %// setup linear indices for the row of this iteration
[x,l] = min(DP(ind1),[],1); %// get x and l values in one go
DP(i,2:c+1) = DP(i,2:c+1) + x; %// set DP values of a row in one go
BP(i,1:c) = [1:c] + l-2; %// set BP values of a row in one go
end
Benchmarking
Benchmarking Code -
N = 3000; %// Datasize
energy = rand(N);
[r, c, ~] = size(energy);
disp('------------------------------------- With Original Code')
DP = padarray(energy, [0, 1], Inf);
BP = zeros(r, c);
tic
for i = 2 : r
for j = 1 : c
[x, l] = min([DP(i - 1, j), DP(i - 1, j + 1), DP(i - 1, j + 2)]);
DP(i, j + 1) = DP(i, j + 1) + x;
BP(i, j) = j + (l - 2);
end
end
toc,clear DP BP x l
disp('------------------------------------- With Vectorized Code')
DP = padarray(energy, [0, 1], Inf);
BP = zeros(r, c);
tic
rows_DP = size(DP,1); %// rows in DP
start_ind1 = bsxfun(#plus,[1:rows_DP:2*rows_DP+1]',[0:c-1]*rows_DP); %//'
for i = 2 : r
ind1 = start_ind1 + i-2; %// setup linear indices for the row of this iteration
[x,l] = min(DP(ind1),[],1); %// get x and l values in one go
DP(i,2:c+1) = DP(i,2:c+1) + x; %// set DP values of a row in one go
BP(i,1:c) = [1:c] + l-2; %// set BP values of a row in one go
end
toc
Results -
------------------------------------- With Original Code
Elapsed time is 44.200746 seconds.
------------------------------------- With Vectorized Code
Elapsed time is 1.694288 seconds.
Thus, you might enjoy a good 26x speedup improvement in performance with that little vectorization tweak.
More tweaks
Few more optimization tweaks could be tried into your code for performance -
cols = zeros(r) could be replaced with col(r,r) = 0.
DP = padarray(energy, [0, 1], Inf) could be replaced with
DP(1:size(energy,1),1:size(energy,2)+2)=Inf;
DP(:,2:end-1) = energy;
BP = zeros(r, c) could be replaced with BP(r, c) = 0.
The pre-allocation tweaks used here are inspired by this blog post.

Application of Neural Network in MATLAB

I asked a question a few days before but I guess it was a little too complicated and I don't expect to get any answer.
My problem is that I need to use ANN for classification. I've read that much better cost function (or loss function as some books specify) is the cross-entropy, that is J(w) = -1/m * sum_i( yi*ln(hw(xi)) + (1-yi)*ln(1 - hw(xi)) ); i indicates the no. data from training matrix X. I tried to apply it in MATLAB but I find it really difficult. There are couple things I don't know:
should I sum each outputs given all training data (i = 1, ... N, where N is number of inputs for training)
is the gradient calculated correctly
is the numerical gradient (gradAapprox) calculated correctly.
I have following MATLAB codes. I realise I may ask for trivial thing but anyway I hope someone can give me some clues how to find the problem. I suspect the problem is to calculate gradients.
Many thanks.
Main script:
close all
clear all
L = #(x) (1 + exp(-x)).^(-1);
NN = #(x,theta) theta{2}*[ones(1,size(x,1));L(theta{1}*[ones(size(x,1),1) x]')];
% theta = [10 -30 -30];
x = [0 0; 0 1; 1 0; 1 1];
y = [0.9 0.1 0.1 0.1]';
theta0 = 2*rand(9,1)-1;
options = optimset('gradObj','on','Display','iter');
thetaVec = fminunc(#costFunction,theta0,options,x,y);
theta = cell(2,1);
theta{1} = reshape(thetaVec(1:6),[2 3]);
theta{2} = reshape(thetaVec(7:9),[1 3]);
NN(x,theta)'
Cost function:
function [jVal,gradVal,gradApprox] = costFunction(thetaVec,x,y)
persistent index;
% 1 x x
% 1 x x
% 1 x x
% x = 1 x x
% 1 x x
% 1 x x
% 1 x x
m = size(x,1);
if isempty(index) || index > size(x,1)
index = 1;
end
L = #(x) (1 + exp(-x)).^(-1);
NN = #(x,theta) theta{2}*[ones(1,size(x,1));L(theta{1}*[ones(size(x,1),1) x]')];
theta = cell(2,1);
theta{1} = reshape(thetaVec(1:6),[2 3]);
theta{2} = reshape(thetaVec(7:9),[1 3]);
Dew = cell(2,1);
DewApprox = cell(2,1);
% Forward propagation
a0 = x(index,:)';
z1 = theta{1}*[1;a0];
a1 = L(z1);
z2 = theta{2}*[1;a1];
a2 = L(z2);
% Back propagation
d2 = 1/m*(a2 - y(index))*L(z2)*(1-L(z2));
Dew{2} = [1;a1]*d2;
d1 = [1;a1].*(1 - [1;a1]).*theta{2}'*d2;
Dew{1} = [1;a0]*d1(2:end)';
% NNRes = NN(x,theta)';
% jVal = -1/m*sum(NNRes-y)*NNRes*(1-NNRes);
jVal = -1/m*(a2 - y(index))*a2*(1-a2);
gradVal = [Dew{1}(:);Dew{2}(:)];
gradApprox = CalcGradApprox(0.0001);
index = index + 1;
function output = CalcGradApprox(epsilon)
output = zeros(size(gradVal));
for n=1:length(thetaVec)
thetaVecMin = thetaVec;
thetaVecMax = thetaVec;
thetaVecMin(n) = thetaVec(n) - epsilon;
thetaVecMax(n) = thetaVec(n) + epsilon;
thetaMin = cell(2,1);
thetaMax = cell(2,1);
thetaMin{1} = reshape(thetaVecMin(1:6),[2 3]);
thetaMin{2} = reshape(thetaVecMin(7:9),[1 3]);
thetaMax{1} = reshape(thetaVecMax(1:6),[2 3]);
thetaMax{2} = reshape(thetaVecMax(7:9),[1 3]);
a2min = NN(x(index,:),thetaMin)';
a2max = NN(x(index,:),thetaMax)';
jValMin = -1/m*(a2min-y(index))*a2min*(1-a2min);
jValMax = -1/m*(a2max-y(index))*a2max*(1-a2max);
output(n) = (jValMax - jValMin)/2/epsilon;
end
end
end
EDIT:
Below I present the correct version of my costFunction for those who may be interested.
function [jVal,gradVal,gradApprox] = costFunction(thetaVec,x,y)
m = size(x,1);
L = #(x) (1 + exp(-x)).^(-1);
NN = #(x,theta) L(theta{2}*[ones(1,size(x,1));L(theta{1}*[ones(size(x,1),1) x]')]);
theta = cell(2,1);
theta{1} = reshape(thetaVec(1:6),[2 3]);
theta{2} = reshape(thetaVec(7:9),[1 3]);
Delta = cell(2,1);
Delta{1} = zeros(size(theta{1}));
Delta{2} = zeros(size(theta{2}));
D = cell(2,1);
D{1} = zeros(size(theta{1}));
D{2} = zeros(size(theta{2}));
jVal = 0;
for in = 1:size(x,1)
% Forward propagation
a1 = [1;x(in,:)']; % added bias to a0
z2 = theta{1}*a1;
a2 = [1;L(z2)]; % added bias to a1
z3 = theta{2}*a2;
a3 = L(z3);
% Back propagation
d3 = a3 - y(in);
d2 = theta{2}'*d3.*a2.*(1 - a2);
Delta{2} = Delta{2} + d3*a2';
Delta{1} = Delta{1} + d2(2:end)*a1';
jVal = jVal + sum( y(in)*log(a3) + (1-y(in))*log(1-a3) );
end
D{1} = 1/m*Delta{1};
D{2} = 1/m*Delta{2};
jVal = -1/m*jVal;
gradVal = [D{1}(:);D{2}(:)];
gradApprox = CalcGradApprox(x(in,:),0.0001);
% Nested function to calculate gradApprox
function output = CalcGradApprox(x,epsilon)
output = zeros(size(thetaVec));
for n=1:length(thetaVec)
thetaVecMin = thetaVec;
thetaVecMax = thetaVec;
thetaVecMin(n) = thetaVec(n) - epsilon;
thetaVecMax(n) = thetaVec(n) + epsilon;
thetaMin = cell(2,1);
thetaMax = cell(2,1);
thetaMin{1} = reshape(thetaVecMin(1:6),[2 3]);
thetaMin{2} = reshape(thetaVecMin(7:9),[1 3]);
thetaMax{1} = reshape(thetaVecMax(1:6),[2 3]);
thetaMax{2} = reshape(thetaVecMax(7:9),[1 3]);
a3min = NN(x,thetaMin)';
a3max = NN(x,thetaMax)';
jValMin = 0;
jValMax = 0;
for inn=1:size(x,1)
jValMin = jValMin + sum( y(inn)*log(a3min) + (1-y(inn))*log(1-a3min) );
jValMax = jValMax + sum( y(inn)*log(a3max) + (1-y(inn))*log(1-a3max) );
end
jValMin = 1/m*jValMin;
jValMax = 1/m*jValMax;
output(n) = (jValMax - jValMin)/2/epsilon;
end
end
end
I've only had a quick eyeball over your code. Here are some pointers.
Q1
should I sum each outputs given all training data (i = 1, ... N, where
N is number of inputs for training)
If you are talking in relation to the cost function, it is normal to sum and normalise by the number of training examples in order to provide comparison between.
I can't tell from the code whether you have a vectorised implementation which will change the answer. Note that the sum function will only sum up a single dimension at a time - meaning if you have a (M by N) array, sum will result in a 1 by N array.
The cost function should have a scalar output.
Q2
is the gradient calculated correctly
The gradient is not calculated correctly - specifically the deltas look wrong. Try following Andrew Ng's notes [PDF] they are very good.
Q3
is the numerical gradient (gradAapprox) calculated correctly.
This line looks a bit suspect. Does this make more sense?
output(n) = (jValMax - jValMin)/(2*epsilon);
EDIT: I actually can't make heads or tails of your gradient approximation. You should only use forward propagation and small tweaks in the parameters to compute the gradient. Good luck!