Mixed-integer linear programming: How to generate constraints? - matlab

I have an objective function such as
(for simplicity I omitted the coefficients).
I want to minimize this function using intlinprog with the following constraints:
and
with all x binary. These sums result in these 4 inequalities:
It is clear that the constaints matrix is
This works well if I create this matrix manually. Now suppose I have 6 or 8 or 10 variables instead of 4 in my objective function and in the constraints (same pattern). How can I use Matlab to generate this constraints matrix for these larger problems?

I recommend writing down some other cases a bit. So it seems you want to constraint all row-sums and all column-sums:
For N=3, there are 9 vars (i'm assuming a square case here; you did not provide complete info):
x00 x01 x02
x10 x11 x12
x20 x21 x22
Now the constraint matrix looks like:
x00 x01 x02 | x10 x11 x12 | x20 x21 x22
---------------------------------------
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
That's pretty regular. Not it's time to check out matlab's matrix-creation functions. Sadly i'm not much of a matlab-user, but:
the lower half of rows consist of:
horizontal stacking of N identity-matrices each of size N
the upper half of rows consist of:
block-diagonal matrix of N 1-row-vectors each of size N
the final matrix is a vertical stacking of both components
A full sparse-matrix python-example (sorry, no matlab here; but there should be nearly a 1:1 mapping), to be more clear would look like:
import numpy as np
import scipy.sparse as sp
N = 3
component_a = sp.hstack([sp.eye(N) for i in range(N)])
row_full_1 = sp.csr_matrix(np.ones(N))
component_b = sp.block_diag([row_full_1 for i in range(N)]) # matlab: blkdiag?
matrix = sp.vstack((component_b, component_a))
print(matrix.todense())
Output:
[[ 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 1. 1. 1. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 1. 1. 1.]
[ 1. 0. 0. 1. 0. 0. 1. 0. 0.]
[ 0. 1. 0. 0. 1. 0. 0. 1. 0.]
[ 0. 0. 1. 0. 0. 1. 0. 0. 1.]]
Remark: depending on N, you need to think about using dense or sparse-matrices. Given N, the ratio of non-zeros in the matrix will be 1/N.

Related

(q/kdb+) Interpolation formula not working for some cases

I have the formulas below to generate a linear interpolation in q:
lsfit:{(enlist y) lsq x xexp/: til 1+z};
interp:{[xn;x;y]sum (1;xn)*flip lsfit[x;y;1]};
and the data below to interpolate:
xn:(4.7;7.5;4.9);
x:(3 5f;7.5 7.5;3 5f);
y:(1.3 1.5;2 2f;1.3 1.5);
interp'[xn;x;y]
which is generating
index value
0 enlist 1.47
1 enlist 0nf
2 enlist 1.49
why am I getting 0 in the second row?
Update: Inconsistet behaviour for other examples
xn:(6;7;8;9);
x:(6 6f;7 7f;8 8f;9 9f);
y:(1 1f;1 1f;1 1f;1 1f);
interp'[xn;x;y]
generates
index value
0 enlist 1f
1 enlist 0nf
2 enlist 0nf
3 enlist 1f
So, it looks like sometimes the formula works, rows 0 and 3, and sometimes it does not, rows 1 and 2.
How can I fix it?
Thanks!
The reason you are encountering this issue is because of the mathematical details matrix division.
Matrix division can be performed by taking the inverse of a matrix and then matrix multiplying. In q, this can be seen by performing those operations directly.
q) enlist[2 2f] lsq (1 2f;3 4f)
-1 1
q) enlist[2 2f] mmu inv (1 2f;3 4f)
-1 1
One of your input x values to lsfit is the row 7.5 7.5. With a z value of 1f, this converts that vector into a matrix (1 1;7.5 7.5) in the xexp operation. This matrix is then used in the lsq operation.
The problem then occurs because (1 1;7.5 7.5) is not invertible. A matrix is invertible if and only if the determinant is non-zero. The determinant for a 2 x 2 matrix is AD - BC. In your example, A = 1, B = 1, C = 7.5, and D = 7.5. So the determinant is zero, the matrix is not invertible, and the output from the function is Onf.
To resolve this issue, you would have to ensure that the two items in each row of x are not identical.
Hope that helps.

Generate reciprocal matrices from sequences in the cell array ( Matlab )

I have 3 sequences in a cell-array :
S= {'ABC','ACB','AB'}
S{1}='ABC' means A<B<C and have the weights : A:3, B:2, C:1
S{2}='ACB' means A<C<B and have the weights : A:3, C:2, B:1
S{3}='AB' means A<B and have the weights : A:3, B:2
I want to convert each of the strings in the Input_cell into a matrix M[i,j] which has to satisfy those conditions :
M[i,i] =1
M[i,j] = 1/M[j,i]
If S{1}(i)<S{1}(j) then M[i,j]=weight(S{1}(i))/weight(S{1}(j))
For example:
In S{1}= 'ABC' , and weights will be A:3, B:2, C:1
If A<B then M[A,B]=3/2 and M[B,A]=2/3
If B<C then M[B,C]=2/1 and M[C,B]=1/2 ....etc
So the expected matrix for S{1} would be:
A B C
A [1 3/2 3
B 2/3 1 2
C 1/3 1/2 1]
In S{2}='ACB', the weights of ACB will be A:3, C:2, B:1. So the expected matrix of S{2} would be:
A B C
A [1 3 3/2
B 1/3 1 1/2
C 2/3 2 1]
In S{3}='AB', the weights of AB will be A:3, B:2, C:unknown. If there is an unknown value, we will put 1 in the matrix. Such as M[A,C]=M[C,A]=M[B,C]=M[C,B]=1. So the expected matrix of S{3} would be:
A B C
A [1 3/2 1
B 2/3 1 1
C 1 1 1]
How can I input the cell array of strings and convert them into matrices as above ?
This task has 2 parts (for each element of cell array):
1) Get numbers from strings. For example, ACB sequence is transformed to [3, 1, 2], because strength of the first column will be 3, the second 1, the third 2.
2) Create matrix from that array.
1) Check which letter is first and put 3 on the correct place. Then check which is second, put 2. Third, put 1. If there is no number, put nan (= initialize array by nan). If you can have arbitrarily many letters thing works the same, just first figure out how big array you need. But then your 3rd case will cease to work, as it will assume you only have 2 elements and will make 2x2 matrix.
The second part goes like this:
seq=[3,1,2];
M = seq' * (1./seq);
M(isnan(M)) = 1; % all the numbers with nan become 1.
Note that this will have doubles - M=1.5 and 0.3333, not fractions (1/3, 3/2). To represent it as fractions, you will require a bit more work to do it in general. For each element of the matrix, find gcd of the nominator and denominator and divide by it. In this simple case of 3 elements, you simply put nominator and denominator in the matrix with 1 on the diagonal - there are no common divisors.
denominator = repmat(seq, 3, 1);

Matlab: Covariance Matrix from matrix of combinations using E(X) and E(X^2)

I have a set of independent binary random variables (say A,B,C) which take a positive value with some probability and zero otherwise, for which I have generated a matrix of 0s and 1s of all possible combinations of these variables with at least a 1 i.e.
A B C
1 0 0
0 1 0
0 0 1
1 1 0
etc.
I know the values and probabilities of A,B,C so I can calculate E(X) and E(X^2) for each. I want to treat each combination in the above matrix as a new random variable equal to the product of the random variables which are present in that combination (show a 1 in the matrix). For example, random variable Row4 = A*B.
I have created a matrix of the same size to the above, which shows the relevant E(X)s instead of the 1s, and 1s instead of the 0s. This allows me to easily calculate the vector of Expected values of the new random variables (one per combination) as the product of each row. I have also generated a similar matrix which shows E(X^2) instead of E(X), and another one which shows prob(X>0) instead of E(X).
I'm looking for a Matlab script that computes the Covariance matrix of these new variables i.e. taking each row as a random variable. I presume it will have to use the formula:
Cov(X,Y)=E(XY)-E(X)E(Y)
For example, for rows (1 1 0) and (1 0 1):
Cov(X,Y)=E[(AB)(AC)]-E(X)E(Y)
=E[(A^2)BC]-E(X)E(Y)
=E(A^2)E(B)E(C)-E(X)E(Y)
These values I already have from the matrices I've mentioned above. For each Covariance, I'm just unsure how to know which two variables appear in both rows, because for those I will have to select E(X^2) instead of E(X).
Alternatively, the above can be written as:
Cov(X,Y)=E(X)E(Y)*[1/prob(A>0)-1]
But the problem remains as the probabilities in the denominator will only be the ones of the variables which are shared between two combinations.
Any advice on how automate the computation of the Covariance matrix in Matlab would be greatly appreciated.
I'm pretty sure this is not the most efficient way to do that but that's a start:
Assume r1...n the combinations of the random variables, R is the matrix:
A B C
r1 1 0 0
r2 0 1 0
r3 0 0 1
r4 1 1 0
If you have the vector E1, E2 and ER as:
E1 = [E(A) E(B) E(C) ...]
E2 = [E(A²) E(B²) E(C²) ...]
ER = [E(r1) E(r2) E(r3) ...]
If you want to compute E(r1,r2) you can:
1) Extract the R1 and R2 columns from R
v1 = R(1,:)
v2 = R(2,:)
2) Sum both vectors in vs
vs = v1 + v2
3) Loop in vs, if you see a 2 that means the value in R2 has to be used, if you see a 1 it is the value in R1, if it is 0 do not use the value.
4) Using the loop, compute your E(r1,r2) as wanted.

Matlab chol function returns single number Choleksy decomposition

I have a matrix A which is 390 by 390 and contains numbers such as:
141270,991258825 -92423,2972762164
-92423,2972762164 60465,8168198016
139998,877391881 -91591,0460330842
30573,0969789307 -20001,7456206658 ...
If I try chol(A), Matlab fails and says that the matrix must be positive definite. Ok I saw in the API that [R,p] = chol(A) also works for negative definite matrices. I tried this, but R then becomes a 1x1 matrix. But I expect a 390x390 matrix.
The help file is slightly unclear here, but it doesn't mean that you can just use a non-positive definite matrix and get the same result by changing the way you call the function:
[R,p] = chol(A) for positive definite A, produces an upper triangular
matrix R from the diagonal and upper triangle of matrix A, satisfying
the equation R'*R=A and p is zero. If A is not positive definite, then
p is a positive integer and MATLAB® does not generate an error. When A
is full, R is an upper triangular matrix of order q=p-1 such that
R'*R=A(1:q,1:q).
If your matrix is not positive definite, p > 0, therefore the size of your result R will depend on p. In fact, I think this particular syntax is simply designed to allow you to use chol as a way of checking if A is positive definite, rather than just giving an error if it is not. The help file even says:
Note Using chol is preferable to using eig for determining positive definiteness.
Example - take pascal(5) and set the last element to something negative:
A =
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 -3
[R,p] = chol(A) returns
R =
1 1 1 1
0 1 2 3
0 0 1 3
0 0 0 1
p =
5
Sure enough, R'*R' == A(1:4,1:4)
By setting element X(2,2) to be negative, on the other hand, gives p of 2 and therefore a single value in R which will be sqrt(A(1,1). Setting A(1,1) to be negative returns p = 1 and an empty R.

Why sprank(A) and A\b report different rank in matlab?

I have a point set P and I construct it's adjacent matrix A by k-nearest neighbor. Each row of A is [...+1...-1...], indicates a pair of neighbor points. The size of A is 48348 x 8058, sprank(A) is 8058. But when I do the following, it gives me a warning: "Warning: Rank deficient, rank = 8055, tol = 8.307912e-10."
a=A*b;
c=A\a;
and norm(c-b) is quite large. It seems something is wrong with the adjacent matrix A, but I can't figure it out. Thanks in advance!
sprank only tells you how many rows/columns of your matrix have non-zero elements, while A\b is reporting the actual rank of the matrix which indicates how many rows of your matrix are linearly independent. For example, for following matrix:
A = [-1 1 0 0;
0 1 -1 0;
1 0 -1 0;
0 0 1 -1]
sprank(A) is 4 but rank(A) is only 3 because you can write the third row as a linear combination of the other rows, specifically A(2,:) - A(1,:).
The issue that you need to address is either in how you're computing A (if you expect that to generate a system of linearly independent equations) or you need to find a way to use A that doesn't require factorizing a rank deficient matrix.