Find the combination that minimizes a cost function - matlab

I am facing a problem and I would be grateful to anyone that could help. The problem is the following:
Consider that we have a vector D = [D1;D2;D3;...;DN] and a set of time instances TI = {t1,t2,t3,...,tM}. Each element of vector D, Di, corresponds to a subset of TI. For example D1 could correspond to time instances {t1,t2,t3} and D2 to {t2,t4,t5}.
I would like to find the combination of elements of D that corresponds to all elements of TI, without any of these being taken into account more than once, and at the same time minimizes the cost function sum(Dj). Dj are elements of vector D and each one corresponds to a set of time instances.
Let me give an example. Let us consider a vector
D = [15;10;5;2;35;15;25;25;25;30;45;5;1;40]
and a set
TI={5,10,15,20,25,30}
Each of D elements corresponds to
{[5 15];[5 20];[5 25];[5 30];[5 15 20];[5 20 25];[5 15 30];[5 20 25 30];[10 15];[10 20];[10 25];[10 15 20];[10 15 20 25];[10 30]}
respectively, e.g. D(1)=15 corresponds to time instance [5 15].
The solution that the procedure has to come up with is that the combination of D(4) and D(12), i.e. 2 and 1 respectively, has the minimum sum and correspond to all time instances.
I have to mention that the procedure has to be able to work with large vectors.
Thanks for every attempt to help!

The binary weight vector x places a weight on each D_i.
Let f=[D1;D2;...;DN].
Column j of A, A_j is a binary vector.
A_jk is 1 if D_j corresponds to Tk, else is zero.
The problem is:
min f^T*x s.t. A*x=1;
Then use bintprog to solve.
x = bintprog(f,[],[],A,ones(M,1))

Related

optimizing a matlab code involving for loop

I have a Matlab code that goes like this
s=[0.5 0.6 0.7];
u=[0.3618 0.9826 0.7237 0.0346 0.5525 0.0692 0.8949 0.1384
0.3418 0.9226 0.7213 0.0346 0.7525 0.0692 0.8949 0.1384
0.3318 0.9326 0.7237 0.0336 0.5575 0.0792 0.8949 0.1385]
A= u(1:2:7); % Here u is a 1-D vector and hence A
B=u(2:2:8); % Here u is a 1-D vector and hence B
C=mod(s(1)-(A+B),1);
I want to implement this code for the other two values of s also using next 8 values of u i.e now my code becomes
A=u(9:2:15);
B=u(10:2:16);
C=mod(s(2)-(A+B),1);
Similarly for last value of s. But each time i need the next 8 values of u. How do i code this so that it takes less time.
So you start with a 24 element array in u that you wish to perform this operation on in a vectorized fashion. I assume you have many more elements but that they all fit in memory. The way to do this is to reshape u to where you want the elements to be. You can do this via:
u1 = reshape(u1,[2,4,3]);
From there you also need to modify s to match it
s1 = permute(s,[1 3 2]);
Finally, you can calculate your C matrix in vectorized form
C1 = mod(s1-sum(u1),1);
For this problem, this gives a 1x4x3 matrix where the 3rd dimension represents each set of 8. From there you can then extract the problem set you want
C = squeeze(C1(1,:,1));

Logical statement where all matrix elements must be greater than those in another matrix

I'm looking for a way to test if all elements of a matrix are greater than or equal to their corresponding indexes values in another matrix, and if not to stop evaluating. This is part of an elseif statement for setting a lower bound for values, thus as simplified example:
Lower Bound matrix: A = [4 5 6 7]
New values matrix: B = [7 8 9 10]
Is B>=A then yes, accept and proceed
whereas
Lower Bound matrix: A = [4 5 6 7]
New values matrix: C = [5 3 5 8]
Is C>=A? then no, all elements of C are not greater than A, reject and stop
My solution so far is a bit hackneyed:
Is sum(C>=A) < length(C)? no, then reject and stop
This gives the sum of the true/false values in the comparison C>=A, which if all values of C were greater would equal the length of C, else the sum would be less than the length of C. I keep thinking there's a simple and more elegant solution to this that I'm overlooking and would be grateful for any thoughts. Thanks!
MATLAB has a built-in function for performing this action called all. You can use this on a logical matrix to determine if all values are true. In your case you would pass the logical matrix: B >= A.
A = [4,5,6,7];
B = [7,8,9,10];
all(B(:) >= A(:))
1
Notice that I have used (:) above which ensures that both A and B are column vectors prior to performing the comparison. This way, they can be of any arbitrary dimension and the result of all will always be a scalar.
While you're at it, you may also look into any.
You must indeed rely on logical indexing. To check whether a given matrix B has elements greater than or equal to their corresponding indexes values in another given matrix A you can do something like:
if (sum(sum(B>=A))==numel(A))
%enter if body here
end
The statement B>=A will return a logical matrix with 1 in position (i,j) if B(i,j)>=A(i,j). You then sum all the 1s inside such matrix and then check if such sum is equal to the number of elements (numel()) in A (or B).
In your example. Given
A=[4 5 6 7];
B=[7 8 9 10];
the statement B>=A will return
ans =
1 1 1 1
because all elements in B are greater then elements in A. Sum this vector, you'll get 4. Is the sum (4) equal to the number of elements (4)? Yes. Then all elements in B are greater than or equal to the elements in A.
Note: the double sum() makes your code more robust. It will indeed work also with matrices and not just with vectors. That is because if you do sum() on a matrix, Matlab by default does not return the sum of all its elements, but the sum along the first dimension whose size is different from 1. So if our matrix is:
C =
8 1 6
3 5 7
4 9 2
sum(C) will return
ans =
15 15 15
(Matlab took the sum of every column).
By taking also the sum of such vector we'll get the sum of all the elements.
This ends the quick explanation regarding the nested sum().
I assume by an elegant solution you mean a solution which is more efficient.
Lets create test data:
A = zeros(100000,100000); B = zeros(100000,100000);
Linear Loop
for i = 1:numel(A)
if A(i) < B(i)
display('different')
break
end
end
Logical indexing
if (sum(sum(B>=A))~=numel(A))
display('different')
end
The loop is better when its comes to the best case (first element is smaller):
Elapsed time is 0.000236 seconds. Elapsed time is 0.131802 seconds.
and when its the average case:
Elapsed time is 0.001993 seconds. Elapsed time is 0.196228 seconds.
But we only care about the worst case:
B(end) = 1;
Elapsed time is 8.181473 seconds. Elapsed time is 0.108002 seconds.

Possible "Traveling Salesman" function in Matlab?

I am looking to solve a Traveling Salesman type problem using a matrix in order to find the minimum time between transitions. The matrix looks something like this:
A = [inf 4 3 5;
1 inf 3 5;
4 5 inf 3;
6 7 1 inf]
The y-axis represents the "from" node and the x-axis represents the "to" node. I am trying to find the optimal time from node 1 to node 4. I was told that there is a Matlab function called "TravellingSalesman". Is that true, and if not, how would I go about solving this matrix?
Thanks!
Here's an outline of the brute-force algorithm to solve TSP for paths from node 1 to node n:
C = inf
P = zeros(1,n-2)
for each permutation P of the nodes [2..n-1]
// paths always start from node 1 and end on node n
C = A(1,P(1)) + A(P(1),P(2)) + A(P(2),P(3)) + ... +
A(P(n-3),P(n-2)) + A(P(n-2),n)
if C < minCost
minCost = C
minPath = P
elseif C == minCost // you only need this part if you want
minPath = [minPath; P] // ALL paths with the shortest distance
end
end
Note that the first and last factors in the sum are different because you know beforehand what the first and last nodes are, so you don't have to include them in the permutations. So in the example given, with n=4, there are actually only 2!=2 possible paths.
The list of permutations can be precalculated using perms(2:n-1), but that might involve storing a large matrix (n! x n). Or you can calculate the cost as you generate each permutation. There are several files on the Mathworks file exchange with names like nextPerm that should work for you. Either way, as n grows you're going to be generating a very large number of permutations and your calculations will take a very long time.

Calculation the elements of different sized matrix in Matlab

Can anybody help me to find out the method to calculate the elements of different sized matrix in Matlab ?
Let say that I have 2 matrices with numbers.
Example:
A=[1 2 3;
4 5 6;
7 8 9]
B=[10 20 30;
40 50 60]
At first,we need to find maximum number in each column.
In this case, Ans=[40 50 60].
And then,we need to find ****coefficient** (k).
Coefficient(k) is equal to 1 divided by quantity of column of matrix A.
In this case, **coefficient (k)=1/3=0.33.
I wanna create matrix C filling with calculation.
Example in MS Excel.
H4 = ABS((C2-C6)/C9)*0.33+ABS((D2-D6)/D9)*0.33+ABS((E2-E6)/E9)*0.33
I4 = ABS((C3-C6)/C9)*0.33+ABS((D3-D6)/D9)*0.33+ABS((E3-E6)/E9)*0.33
J4 = ABS((C4-C6)/C9)*0.33+ABS((D4-D6)/D9)*0.33+ABS((E4-E6)/E9)*0.33
And then (Like above)
H5 = ABS((C2-C7)/C9)*0.33+ABS((D2-D7)/D9)*0.33+ABS((E2-E7)/E9)*0.33
I5 = ABS((C3-C7)/C9)*0.33+ABS((D3-D7)/D9)*0.33+ABS((E3-E7)/E9)*0.33
J5 = ABS((C4-C7)/C9)*0.33+ABS((D4-D7)/D9)*0.33+ABS((E4-E7)/E9)*0.33
C =
0.34 =|(1-10)|/40*0.33+|(2-20)|/50*0.33+|(3-30)|/60*0.33
0.28 =|(4-10)|/40*0.33+|(5-20)|/50*0.33+|(6-30)|/60*0.33
0.22 =|(7-10)|/40*0.33+|(8-20)|/50*0.33+|(9-30)|/60*0.33
0.95 =|(1-40)|/40*0.33+|(2-50)|/50*0.33+|(3-60)|/60*0.33
0.89 =|(4-40)|/40*0.33+|(5-50)|/50*0.33+|(6-60)|/60*0.33
0.83 =|(7-40)|/40*0.33+|(8-50)|/50*0.33+|(9-60)|/60*0.33
Actually A is a 15x4 matrix and B is a 5x4 matrix.
Perhaps,the matrices dimensions are more than this matrices (variables).
How can i write this in Matlab?
Thanks you!
You can do it like so. Let's assume that A and B are defined as you did before:
A = vec2mat(1:9, 3)
B = vec2mat(10:10:60, 3)
A =
1 2 3
4 5 6
7 8 9
B =
10 20 30
40 50 60
vec2mat will transform a vector into a matrix. You simply specify how many columns you want, and it will automatically determine the right amount of rows to transform the vector into a correctly shaped matrix (thanks #LuisMendo!). Let's also define more things based on your post:
maxCol = max(B); %// Finds maximum of each column in B
coefK = 1 / size(A,2); %// 1 divided by number of columns in A
I am going to assuming that coefK is multiplied by every element in A. You would thus compute your desired matrix as so:
cellMat = arrayfun(#(x) sum(coefK*(bsxfun(#rdivide, ...
abs(bsxfun(#minus, A, B(x,:))), maxCol)), 2), 1:size(B,1), ...
'UniformOutput', false);
outputMatrix = cell2mat(cellMat).'
You thus get:
outputMatrix =
0.3450 0.2833 0.2217
0.9617 0.9000 0.8383
Seems like a bit much to chew right? Let's go through this slowly.
Let's start with the bsxfun(#minus, A, B(x,:)) call. What we are doing is taking the A matrix and subtracting with a particular row in B called x. In our case, x is either 1 or 2. This is equal to the number of rows we have in B. What is cool about bsxfun is that this will subtract every row in A by this row called by B(x,:).
Next, what we need to do is divide every single number in this result by the corresponding columns found in our maximum column, defined as maxCol. As such, we will call another bsxfun that will divide every element in the matrix outputted in the first step by their corresponding column elements in maxCol.
Once we do this, we weight all of the values of each row by coefK (or actually every value in the matrix). In our case, this is 1/3.
After, we then sum over all of the columns to give us our corresponding elements for each column of the output matrix for row x.
As we wish to do this for all of the rows, going from 1, 2, 3, ... up to as many rows as we have in B, we apply arrayfun that will substitute values of x going from 1, 2, 3... up to as many rows in B. For each value of x, we will get a numCol x 1 vector where numCol is the total number of columns shared by A and B. This code will only work if A and B share the same number of columns. I have not placed any error checking here. In this case, we have 3 columns shared between both matrices. We need to use UniformOutput and we set this to false because the output of arrayfun is not a single number, but a vector.
After we do this, this returns each row of the output matrix in a cell array. We need to use cell2mat to transform these cell array elements into a single matrix.
You'll notice that this is the result we want, but it is transposed due to summing along the columns in the second step. As such, simply transpose the result and we get our final answer.
Good luck!
Dedication
This post is dedicated to Luis Mendo and Divakar - The bsxfun masters.
Assuming by maximum number in each column, you mean columnwise maximum after vertically concatenating A and B, you can try this one-liner -
sum(abs(bsxfun(#rdivide,bsxfun(#minus,permute(A,[3 1 2]),permute(B,[1 3 2])),permute(max(vertcat(A,B)),[1 3 2]))),3)./size(A,2)
Output -
ans =
0.3450 0.2833 0.2217
0.9617 0.9000 0.8383
If by maximum number in each column, you mean columnwise maximum of B, you can try -
sum(abs(bsxfun(#rdivide,bsxfun(#minus,permute(A,[3 1 2]),permute(B,[1 3 2])),permute(max(B),[1 3 2]))),3)./size(A,2)
The output for this case stays the same as the previous case, owing to the values of A and B.

Vectorizing double for loop in Matlab

I have a matrix A that contains 24 values for each day of the year (one value for each hour). Each column of A is a different day and each day has 24 rows worth of data (A is 24-by-365). I want to compare each day to each other by comparing the hour data of each day. To do this, I take one column of data and compare it to the next column. I take the difference of each hour's data in the two columns and then square and sum them to get a single value indicating how similar the two days are. I then do this with every possible combination of days, creating a 365-by-365 matrix, d, indicating how similar each day is to each other day. For example, element d(20,100) contains a value indicating how similar the 20th day of the year is to the 100th. The code is working, but it is quite slow and I would like to be able to vectorize it. Help would be greatly appreciated.
for j=1:365
for k=1:365
d(j,k)=sqrt(sum((A(:,j)-A(:,k)).^2));
end
end
Pairwise Euclidean distance using pdist, which does the heavy-lifting in C, and squareform to create the distance matrix:
d = squareform(pdist(A.'));
If you need this to be even faster (365-by-365 is not very big though), see my answer here or try this File Exchange program.
You can't beat horchler's answer, but for completeness here's how this can be done using bsxfun
d = bsxfun(#minus, permute(A, [3 2 1]), permute(A, [2 1 3]));
d = sqrt( sum( d.^2, 3 ) );
Another nice way of doing this is using the fact that || x - y || = sqrt(||x||^2-2< x,y >+||y||^2). Therefore
n = sum(A.^2, 1); % norm of each vector
b = bsxfun(#plus, n, n') - 2 * A' * A;