Matlab: Block Tridiagonal with Non-Square Vectors - matlab

I'm trying to create a diagonal matrix using the following matrix as the diagonal
base = [a b c d e f 0;
0 g h i j k l];
I need the resulting matrix to look like this...
[a b c d e f 0 0 0;
0 g h i j k l 0 0;
0 0 a b c d e f 0;
0 0 0 g h i j k l];
except it needs to be "n" elements tall
I have tried using the kron function, but it shifts each consecutive row too many elements to the right.
How can I accomplish what I need in a way where I can select n arbitrarily?

You can do it pretty fast with a 2D convolution:
n = 4; %// desired number of rows in result. Should be a multiple of size(base,1)
T = eye(n-1);
T(2:size(base,1):end,:) = 0;
result = conv2(base,T);
Example: with
base =
0.7497 0.3782 0.4470 0.5118 0.6698 0.3329 0
0 0.9850 0.5638 0.9895 0.4362 0.4545 0.8578
and n=4 the result is
result =
0.7497 0.3782 0.4470 0.5118 0.6698 0.3329 0 0 0
0 0.9850 0.5638 0.9895 0.4362 0.4545 0.8578 0 0
0 0 0.7497 0.3782 0.4470 0.5118 0.6698 0.3329 0
0 0 0 0.9850 0.5638 0.9895 0.4362 0.4545 0.8578

The easy way is to use repeated out-of-bounds assignment. MATLAB will automatically pad any missing entries with 0 in those cases. Here's how:
%// Some test variables
a = rand; g = rand;
b = rand; h = rand;
c = rand; i = rand;
d = rand; j = rand;
e = rand; k = rand;
f = rand; l = rand;
%// base matrix
base = [
a b c d e f 0;
0 g h i j k l];
%// use out-of-bounds assignment
n = 3;
output = base;
for ii = 1:n
output(end+1:end+size(base,1), size(base,1)*ii+1:end+size(base,1)) = base;
end
The hard way is the faster way (relevant for when n is large and/or you need to repeat this very often). Figure out the pattern behind which indices would be filled in the final matrix by which values in the original matrix, then generate a list of those indices and assign those values to those indices:
[b1,b2] = size(base);
[ii,jj,vv] = find(base);
inds = bsxfun(#plus, (ii + (n+1)*b1*(jj-1)).', (0:n).'*b1*(1 + (n+1)*b1));
output = zeros( (n+1)*b1, b2+n*b1 );
output(inds) = repmat(vv.', n+1, 1)
I'll leave it as an exercise for you to figure out what happens here exactly :)

Related

Matlab CPLEX: add multiple SOCP constraints in cplexmiqcp

I have written my problem in MATLAB, using CPLEX as the solver. Due issues that are beyond my control (it is feasible), the CPLEX class API screws up when solving my problem. So, based on post found elsewhere on the internet, I am trying to solve using the toolbox API.
To solve my problem I need to use cplexmiqcp, which has the inputs:
cplexmiqcp(H,f,Aineq,bineq,Aeq,beq,l,Q,r,sostype,sosind,soswt,varLB,varUB,vartype,x0,options);
I have multiple SOCP constraints, and using the class API, I am able to define each of them using a structure, such as:
for n=1:numQCs
cplex.Model.qc(n).a=QC.a{n};
cplex.Model.qc(n).Q=QC.Q{n,1};
cplex.Model.qc(n).sense=QC.sense{n};
cplex.Model.qc(n).rhs=QC.rhs{n};
cplex.Model.qc(n).lhs=QC.lhs{n};
end
But how do I define multiple quadratic constraints for cplexmiqcp inputs? These are l,Q,r. When I try creating a structure as before, I get "Error: incorrect l,Q,r."
The documentation for the cplexmiqcp toolbox function is here. Quoting the documentation, for l, Q, and r, we have:
l: Double column vector or matrix for linear part of quadratic constraints
Q: Symmetric double matrix or row cell array of symmetric double matrices for quadratic constraints
r: Double or double row vector for rhs of quadratic inequality constraints
So, when we want to create one quadratic constraint, we can give a double column vector, a symmetric double matrix, and a double for l, Q, and r, respectively. When we want to create multiple quadratic constraints, we need to provide a matrix, a row cell array of symmetric double matrices, and a row vector for l, Q, and r, respectively.
Consider the following simple model:
Minimize
obj: x1 + x2 + x3 + x4 + x5 + x6
Subject To
c1: x1 + x2 + x5 = 8
c2: x3 + x5 + x6 = 10
q1: [ - x1 ^2 + x2 ^2 + x3 ^2 ] <= 0
q2: [ - x4 ^2 + x5 ^2 ] <= 0
Bounds
x2 Free
x3 Free
x5 Free
End
The MATLAB code would look like the following:
H = [];
f = [1 1 1 1 1 1]';
Aineq = []
bineq = []
Aeq = [1 1 0 0 1 0;
0 0 1 0 1 1];
beq = [8 10]';
l = [0 0;
0 0;
0 0;
0 0;
0 0;
0 0;];
Q = {[-1 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 0 0 0], ...
[0 0 0 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 1 0;
0 0 0 0 0 0]};
r = [0 0];
sostype = [];
sosind = [];
soswt = [];
lb = [ 0; -inf; -inf; 0; -inf; 0];
ub = []; % implies all inf
ctype = []; % implies all continuous
options = cplexoptimset;
options.Display = 'on';
options.ExportModel = 'test.lp';
[x, fval, exitflag, output] = cplexmiqcp (H, f, Aineq, bineq, Aeq, beq,...
l, Q, r, sostype, sosind, soswt, lb, ub, ctype, [], options);
fprintf ('\nSolution status = %s \n', output.cplexstatusstring);
fprintf ('Solution value = %f \n', fval);
disp ('Values =');
disp (x');

Solving a system of matrix equations using MATLAB?

I have a system of three equations that I'd like to solve via MATLAB, and I'm a bit confused on how to go about doing it.
I have three equations:
A = R*P1
B = R*P2
C = R*P3
A, B, C, and P1, P2, and P3 are 3x1 matrices, while R is a 3x3 matrix. R is the same for all three equations.
I need to find R, and am given A, B, C, and the P's.
I wanted to use fsolve, but it seems that fsolve doesn't work when the variables are matrices. What is an alternative method that you would recommend using?
Just making up some numbers to work with:
P1 = [1;1;1];
P2 = [2;3;4];
P3 = [5;4;3];
R = [2 4 5; 1 5 4; 1 2 3];
Which would mean that:
A = [11;10;6];
B = [36;33;20];
C = [41;37;22];
If A, B, C, P1, P2, P3 are all numerical, why don't you simply use the ldivide or \ operator? This will allow you to solve your linear system directly. I can see that you have the following relationships:
R*P1 = A
R*P2 = B
R*P3 = C
You can see that each matrix equation yields three constraints. What you can do is create one system that encapsulates all matrix equations together thus yielding 9 constraints. As such, you'll need to reformulate this to be able to solve for your coefficients in your matrix R differently. To do this, we need to reshape your matrix R such that it becomes a 9-element vector. In other words, we can then reformulate your system like so:
[P1 0 0 0 0 0 0] [R1] [ ]
[0 0 0 P1 0 0 0] [R2] [ A ]
[0 0 0 0 0 0 P1] [R3] [ ]
[P2 0 0 0 0 0 0] [R4] [ ]
[0 0 0 P2 0 0 0] * [R5] = [ B ]
[0 0 0 0 0 0 P2] [R6] [ ]
[P3 0 0 0 0 0 0] [R7] [ ]
[0 0 0 P3 0 0 0] [R8] [ C ]
[0 0 0 0 0 0 P3] [R9] [ ]
P * R = D
You'll see that we have a 9 x 9 matrix called P, our matrix R which is reshaped into a vector so that we can solve for the coefficients and D are A,B,C concatenated together into one vector. R1 to R9 are the coefficients of the matrix R that are read from left to right and top to bottom.
Therefore, to find your coefficients in your matrix, simply do:
R = P^{-1}*D
As such, simply construct the matrix P and vector D like so:
P = [P1.' zeros(1,6); zeros(1,3) P1.' zeros(1,3); zeros(1,6) P1.'; ...
P2.' zeros(1,6); zeros(1,3) P2.' zeros(1,3); zeros(1,6) P2.'; ...
P3.' zeros(1,6); zeros(1,3) P3.' zeros(1,3); zeros(1,6) P3.'];
D = [A; B; C];
Now, simply solve for R and reshape it back into a 3 x 3 matrix. Therefore:
R = P \ D;
R = reshape(R, 3, 3).';
reshape turns our vector into a 3 x 3 matrix, but it constructs the matrix in column-major format, so you need to transpose the result after you call reshape. With your example, this is what we get. I construct P1, P2, P3, A, B, C, then use the code I had from before:
P1 = [1;1;1];
P2 = [2;3;4];
P3 = [5;4;3];
A = [11;10;6];
B = [36;33;20];
C = [41;37;22];
P = [P1.' zeros(1,6); zeros(1,3) P1.' zeros(1,3); zeros(1,6) P1.'; ...
P2.' zeros(1,6); zeros(1,3) P2.' zeros(1,3); zeros(1,6) P2.'; ...
P3.' zeros(1,6); zeros(1,3) P3.' zeros(1,3); zeros(1,6) P3.'];
D = [A; B; C];
R = P \ D;
R = reshape(R, 3, 3).';
To verify that R is correct, do:
A1 = R*P1;
B1 = R*P2;
C1 = R*P3;
We get for each:
A1 =
11
10
6
B1 =
36
33
20
C1 =
41
37
22
This matches up with your example. However, note that you may get a warning that R is ill-conditioned. This is because you may not have enough constraints to properly find a unique inverse. You may have to add more constraints to get a unique inverse, but if you can't, then use this with caution.
Have you tried to flatten out the matrices inside of the solve function? There is a collect function in MATLAB that collects coefficients, but you need to check if it works with supplying a row matrix, as opposed to a sum. (maybe sum(row matrix) - if it also combines like terms)
Something like:
[x,y,x] = solve(sum(R*P1)==A, sum(R*P2)==B, sum(R*P3)==C, x,y,z)
or the fsolve function

Performance of vectorizing code to create a sparse matrix with a single 1 per row from a vector of indexes

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.

matlab - find all possible vectors satisfying irregular constraints

In Matlab, I need to find all possible combinations of a vector that satisfies some constraints that I find quite irregular.
The vector, x, has 12 entries: x_0,x_1,...,x_11
Local constraints:
x_0 in {1,...,6}
x_i in {0,...,6}, i = 1,...,6
x_j in {0,...,12-j}, j = 7,...,11
Global constraints:
sum(x) = 12
for any k, x_k = y ==> x_{k+j} = 0 for j = 1,...,y-1
I have thought about this for quite a while now and can't seem to solve it myself - any ideas anyone?
Use recursion and intermediate constraint checking. Something like this does the trick:
function dispConstraintSatisfyingVectors()
global lb ub sumVal
lb = [1 0 0 0 0 0 0 0 0 0 0 0];
ub = [6 6 6 6 6 6 6 5 4 3 2 1];
sumVal = 12;
x = zeros(1,12);
addValueRecursive(x,1);
end
function addValueRecursive(x,idx)
global lb ub sumVal
for val = lb(idx):ub(idx)
x(idx) = val;
if checkZerosConstraint(x) == 0 && sum(x) <= sumVal
if idx < 12
addValueRecursive(x,idx+1);
else
if sum(x) == sumVal
disp(num2str(x))
end
end
end
end
end
function c = checkZerosConstraint(x)
c = 0;
for j=1:11
c = c + sum(x(j+1:j+x(j)-1));
end
end

Generate boolean matrix by predicate on row and column

I have the following vector:
y = [1; 3; 2; 3; 1];
All its values are between 1 and n (in this case, 3) and denote different options.
I want to create a matrix of size size(y, 1) x n whose rows correpond to y values:
1 0 0 % because y(1) = 1
0 0 1 % because y(2) = 3
0 1 0 % because y(3) = 2
0 0 1
1 0 0
One way to do this would be
Y = zeros(size(y, 1), num_labels);
for i = 1:m
Y(i, y(i)) = 1;
end
Is there a better way to do this, maybe in a single expression?
Basically, what I need is to generate a matrix with boolean predicate (i, j) => j == y(i).
You can try this if a is a column vector
a = [1; 3; 2; 3; 1];
bsxfun(#eq, a, [1:max(a)])
and this if it is a row vector
a = [1; 3; 2; 3; 1]';
bsxfun(#eq, a', [1:max(a)])
If you have access to Statistics Toolbox, the command dummyvar does exactly what you need.
>> y = [1; 3; 2; 3; 1];
>> dummyvar(y)
ans =
1 0 0
0 0 1
0 1 0
0 0 1
1 0 0
You can use sub2ind after initializing the matrix as follows:
y = [1; 3; 2; 3; 1];
m = length(y);
n = max(y);
Y = zeros(m, n);
Y(sub2ind(size(Y), 1:m, y')) = 1
Y =
1 0 0
0 0 1
0 1 0
0 0 1
1 0 0
The trick here is to know that the corresponding rows of y go from 1 to m one by one.
accumarray([(1:length(y)).' y], 1)
As suggested by Dmitri Bouianov on Coursera discussion forum, this also works:
Y = eye(num_labels)(y, :);
This solution uses elements of y to as indices to select rows from an identity matrix.
In Octave (at least as of 3.6.3, not sure when it was introduced), you can use broadcasting to do this extremely easily. It works like this:
Y = y==1:3
(if y is a row matrix, you need to transpose it first - if you want to have Y transposed instead, use y==(1:3)')