Matlab: how to solve a binary system of equations? - matlab

I'm trying to solve a system of equation with the following form:
a5 + a6 + a7 + f5 + f6 + f7 = 11;
b5 + b6 + b7 + e5 + e6 + e7 = 100;
c5 + c6 + c7 + d5 + d6 + d7 = 100;
a5 + b5 + c5 + d5 + e5 + f5 = 11;
a6 + b6 + c6 + d6 + e6 + f6 = 100;
a7 + b7 + c7 + d7 + e7 + f7 = 100;
where all the variables and digits are binaries.
Is there a way to do this in Matlab?
For example, by substituting the binary numbers by there decimal values:
a5 + a6 + a7 + f5 + f6 + f7 = 3;
b5 + b6 + b7 + e5 + e6 + e7 = 4;
c5 + c6 + c7 + d5 + d6 + d7 = 4;
a5 + b5 + c5 + d5 + e5 + f5 = 3;
a6 + b6 + c6 + d6 + e6 + f6 = 4;
a7 + b7 + c7 + d7 + e7 + f7 = 4;
and tell Matlab somehow that the unknowns should be integers and from the interval [0:1]?
Here is the A x = b form:
A = [1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1;
0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0;
0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0;
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0;
0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0;
0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1];
b = [3 4 4 3 4 4];
what would be then the next step?

bintprog, if you have the optimization toolbox.
Since there are likely multiple solutions, I'll choose the solution which has the minimum sum.
>> A = [1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1;
0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0;
0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0;
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0;
0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0;
0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1];
>> b = [3 4 4 3 4 4];
>> bintprog(ones(1,18),[],[],A,b)
Optimization terminated.
ans =
0
1
1
1
1
1
1
1
1
1
0
0
0
0
1
0
1
0

Related

Changing data diagonally in matrix based on formula and table

Let says I have this matrix:
(x)
X = [1 1 1 0 1 0 0 0;
1 1 0 1 0 1 0 0;
1 0 1 1 0 0 1 0;
0 1 1 1 0 0 0 1;
1 0 0 0 1 1 1 0;
0 1 0 0 1 1 0 1;
0 0 1 0 1 0 1 1;
0 0 0 1 0 1 1 1];
and this table:
kzz
_______
1 80
2 80
3 23
4 14
5 63
6 36
7 41
8 5
and this equation:
f = (1/visc)*((2*kzz2*kzz1*az2*az1)/(kzz2*az2*delz+kzz1*az1*delz)
visc = 2
az2 = 6400
az1 = 6400
delz = 30
kzz1 = ? < From the table
kzz2 = ? < From the table
f = (1/2)*((2*kzz2*kzz1*6400*6400)/(kzz2*6400*30+kzz1*6400*30)
this equation represent the diagonal started from column 5 in the matrix, just below the (X).
The required task is: changing the ones in this diagonal to this equation:
f = (1/2)*((2*kzz2*kzz1*6400*6400)/(kzz2*6400*30+kzz1*6400*30)
For the first value in the diagonal " Matrix(5,1) "
kzz2 = 63 and kzz1 = 80 << which obtained from the table
therefore, the equation will be as follow:
f = (1/2)*((2*63*80*6400*6400)/(63*6400*30+80*6400*30)
so based on the location on matrix, the code should take the value from the table and substitute it in the equation.
My trial is:
k = (4);
d = diag(Matrix,k);
n = d;
n(n==1) = f;
XX = XX - diag(d,k) + diag(n,k);
Example of required output
the output should look like this (imaginary numbers)
1 1 1 0 5 0 0 0
1 1 0 1 0 8 0 0
1 0 1 1 0 0 9 0
0 1 1 1 0 0 0 2
1 0 0 0 1 1 1 0
0 1 0 0 1 1 0 1
0 0 1 0 1 0 1 1
0 0 0 1 0 1 1 1
other equations will be used to change the other diagonals to get this result:
1 2 1 0 5 0 0 0
1 1 0 1 0 8 0 0
1 0 1 6 0 0 9 0
0 1 1 1 0 0 0 2
1 0 0 0 1 7 1 0
0 1 0 0 1 1 0 1
0 0 1 0 1 0 1 4
0 0 0 1 0 1 1 1
Your question is not very clear. If the az1,az2,delz,visc are constants and kzz1=kzz(rowIndex), kzz2=kzz(columnIndex) as it seems to be the case from your example, this seems to be ok for what you are trying to do.
az1 = 6400;
az2 = 6400;
delz = 30;
visc = 2;
i=0;
for j=5:8
i=i+1;
X(i,j) = (1/visc)*(2*kzz(j)*kzz(i)*az2*az1)/(kzz(j)*az2*delz+kzz(i)*az1*delz);
end
If you want to generalize for a diagonal starting at the startColumnIndex, the for loop can be something like that:
i=0;
startColumnIndex = 5;
numberOfColumns = size(X,2);
for j = startColumnIndex : numberOfColumns
i=i+1;
.....stuff you want to do......
end

Change vector if even/odd in a matrix

I'm new to Matlab programming and I've only had 3 classes so far. I'm having problem with my homework. (Also I am from Iceland so english is not my first language, so please forgive my grammar)
I'm given a matrix, A and I'm supposed to change the value? of a vector to 0 if it is an even number and to 1 if it is an odd number.
This is what I have so far.
A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
B = zeros(size(A));
for k = 1:length(A)
if mod(A(k),2)== 0 %%number is even
B(k) = 0;
else
B(k) = 1; %%number is odd
end
end
B(A,2==0) = 0;
B(A,2~=0) = 1
What I am getting it this:
B =
0 0 0 0 0 0
1 1 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
If anyone could please help me, it would be greatly appreciated :)
You are very close. Don't use length(A) - use numel(A). length(A) returns the number of elements along the largest dimension. As such, because you have 6 columns and 4 rows, this loop will only iterate 6 times. numel returns the total number of elements in the array A, which is what you want as you want to iterate over each value in A.
Therefore:
A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
B = zeros(size(A));
for k = 1:numel(A) %// Change
if mod(A(k),2)== 0 %%number is even
B(k) = 0;
else
B(k) = 1; %%number is odd
end
end
The above loop will go through every single element in the matrix and set the corresponding element to 0 if even and 1 if odd.
However, I encourage you to use vectorized operations on your code. Don't use loops for this. Specifically, you can do this very easily with a single mod call:
B = mod(A,2);
mod(A,2) will compute the modulus of every value in the matrix A with 2 as the operand and output a matrix B of the same size. This will exactly compute the parity of each number.
We get for B:
>> A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
>> B = mod(A,2)
B =
0 0 1 1 0 0
1 1 0 0 0 0
1 1 0 1 1 0
1 1 0 1 0 1

Changing index of matrix

I'm trying to change the following code so that the first matrix will become the second matrix:
function BellTri = matrix(n)
BellTri = zeros(n);
BellTri(1,1) = 1;
for i = 2:n
BellTri(i,1) = BellTri(i-1,i-1);
for j = 2:i
BellTri(i,j) = BellTri(i - 1,j-1) + BellTri(i,j-1);
end
end
BellTri
First matrix (when n = 7)
1 0 0 0 0 0 0
1 2 0 0 0 0 0
2 3 5 0 0 0 0
5 7 10 15 0 0 0
15 20 27 37 52 0 0
52 67 87 114 151 203 0
203 255 322 409 523 674 877
Second matrix
1 1 2 5 15 52 877
1 3 10 37 151 674 0
2 7 27 114 523 0 0
5 20 87 409 0 0 0
15 67 322 0 0 0 0
52 255 0 0 0 0 0
203 0 0 0 0 0 0
An option is to cyclically permute the columns using circshift.
function [BellTri, Second] = matrix(n)
BellTri = zeros(n);
BellTri(1,1) = 1;
for i = 2:n
BellTri(i,1) = BellTri(i-1,i-1);
for j = 2:i
BellTri(i,j) = BellTri(i - 1,j-1) + BellTri(i,j-1);
end
end
Second = BellTri;
for i = 1:n
Second(:, i) = circshift(Second(:,i), 1-i);
end
for i = n-1:-1:2
Second(1, i) = Second(1, i-1);
end
end
Input: [BellTri, Second] = matrix(7)
Output:
BellTri =
1 0 0 0 0 0 0
1 2 0 0 0 0 0
2 3 5 0 0 0 0
5 7 10 15 0 0 0
15 20 27 37 52 0 0
52 67 87 114 151 203 0
203 255 322 409 523 674 877
Second =
1 1 2 5 15 52 877
1 3 10 37 151 674 0
2 7 27 114 523 0 0
5 20 87 409 0 0 0
15 67 322 0 0 0 0
52 255 0 0 0 0 0
203 0 0 0 0 0 0
One approach:
out = zeros(size(A));
out(logical(fliplr(triu(ones(size(A,1)))))) = A(logical(tril(ones(size(A,1)))));
Note: As Divakar pointed out, there should be a typo in the first row. This method gives the corrected one.
Results:
A = [1 0 0 0 0 0 0;
1 2 0 0 0 0 0;
2 3 5 0 0 0 0;
5 7 10 15 0 0 0;
15 20 27 37 52 0 0;
52 67 87 114 151 203 0;
203 255 322 409 523 674 877];
>> out
out =
1 2 5 15 52 203 877
1 3 10 37 151 674 0
2 7 27 114 523 0 0
5 20 87 409 0 0 0
15 67 322 0 0 0 0
52 255 0 0 0 0 0
203 0 0 0 0 0 0

Taking a matrix and retrieving both the diagonals keeping the dimensions of the original matrix in MATLAB

Given the matrix A = magic(5) you get:
A = 17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
I want to use commands such as rot90, diag, triu, tril and matrices sum to get the matrix:
A = 17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
Please, if you can't think of a way to solve this without the commands I wrote, it's OK to do it your own way.
You can use eye function for indexing
>> A(~eye(size(A)) & ~flipud(eye(size(A))))=0
A =
17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
You can simply use linear indexing to access the diagonals:
n = size(A,1);
B = zeros(n);
B( 1:(n+1):end ) = A( 1:(n+1):end ); %// main diagonal
B( n:(n-1):(end-n+1) ) = A( n:(n-1):(end-n+1) )
And you get
B =
17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
Another approach is:
mDiag = diag(diag(A));
aDiag = rot90(diag(diag(rot90(A))))';
overlap = A.*((diag(diag(A)) ~= 0) & (rot90(diag(diag(rot90(A)))) ~= 0));
solution = mDiag + aDiag - overlap
And than:
solution =
17 0 0 0 15
0 5 0 14 0
0 0 13 0 0
0 12 0 21 0
11 0 0 0 9
Using bsxfun
out = A.*bsxfun(#(x,y) x == y | x+y == size(A,1)+1,(1:size(A,1)).',1:size(A,1)) %//'

Set colorbar ranges in 3d graph in matlab

I would like to create a three dimensional surface using this:
>> a=X
a =
Columns 1 through 8
0 50 100 150 200 250 300 350
Columns 9 through 16
400 450 500 550 600 650 700 750
Columns 17 through 21
800 850 900 950 1000
>> b=Y
b =
0
50
100
150
200
250
300
350
400
>> c=Z
c =
Columns 1 through 8
0 0 0 0 0 0 0 0
16 32 67 98 127 164 194 234
120 171 388 773 1086 1216 1770 2206
189 270 494 1978 2755 3134 5060 10469
133 166 183 348 647 937 1446 2304
192 162 154 113 161 189 266 482
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Columns 9 through 16
0 0 0 0 0 0 0 0
366 604 529 504 346 226 228 179
4027 11186 10276 5349 2560 1322 996 799
27413 76387 37949 15591 5804 2654 1803 1069
9844 24152 14772 4613 1777 849 459 290
1288 2623 1538 582 280 148 90 56
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Columns 17 through 21
0 0 0 0 0
108 94 79 0 0
646 476 612 0 0
884 858 722 0 0
266 215 139 0 0
48 48 31 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
>> surf(X,Y,Z)
At the same time I would like to define that Z values < = 1803 will be shown with red color on the surface graph, 1803 < Z < 2755 yellow and Z > = 2755 green. The limits of the colorbar can be the min and max values of Z (from 0 to 76387). How can I set the ranges of the colorbar in order to get this result?
This will do as you ask:
%# add red (row 1), yellow (row 2), green (row 2)
map = [1 0 0; 0 1 1; 0 1 0];
%# set the new map as the current map
colormap(map);
colors = zeros(size(c)); %# create colors array
colors(c <= 1803) = 1; %# red (1)
colors(c > 1803 & c < 2755) = 2; %# yellow (2)
colors(c >= 2755) = 3; %# green (3)
%# and pass it into surf
surf(a,b,c, colors)