how do i write a constraint and the sum of the z value? - matlab

i have the code and i try to make x as constraint but when i run i always get an error said that Undefined function or variable 'x'. below is the code and how can i get the sum of the z value?
clc;
clear;
%sum sum sum sum(fik*djq*xij*xkq)
%i,k= facilities
%j,q= location
%f(i,k)= flow between facilities i and k
%d(j,q)= distance between locations j and q
%xij = 1 if facility i is assigned to location j and if otherwise, xij = 0
% Flow matrix: flow assigning facility i (column) to facility k (row)
f = [0 5 7 9;
5 0 4 6;
7 4 0 3;
9 6 3 0];
%Distance matrix: distance assigning location j (column) to location q (row)
d = [0 6 8 9;
6 0 5 1;
8 5 0 2;
9 1 2 0];
z= 0;
nf= 4;%no of facilities
nd= 4;%no of locations
for i=1:nf
for j=1:nf
for k=1:nd
for q=1:nd
z = min('z','sum(sum(f(i,k)*d(j,q)*x(i,j)*x(k,q)))');
%if x(i,j)==1;
%else x(k,q)==0;
end
end
end
end
%Constraints
%x as binary 0 1,
%x(i,j) = 1 if facility i is assigned to location j 0r otherwise, x(i,j) = 0
Constraints.constr1 = (x(i,j))==1;
%The first set of constraints requires that each facility gets exactly one
%location, that is for each facility, the sum of the location values
%corresponding to that facility is exactly one
Constraints.constr2 = sum(x,2) == 1;
%The second set of constraints are inequalities. These constraints specify
%that each office has no more than one facility in it.
Constraints.constr3 = sum(x,1) == 1;
disp (z);
are the constraint i code is wrong?

In the attached code, as I can see, you are using matrix x 4 times.
The first use is inside the for-loops and other 3 uses are the one-liners following the loops.
First of all, I suspect you have used function min() in a wrong way. As the arguments should not be characters. Remove '' and use the following line:
z = min(z,sum(sum(f(i,k)*d(j,q)*x(i,j)*x(k,q))));
Now, coming to your question, you have not told what are the contents of your matrix x, so the code doesn't know what value is stored at say, x(1,1) or x(2,3).
It is, therefore, expected to throw an error.

Related

How to create an Octave function that evaluate the sum of pairs of numbers in the vector?

It's like a reverse version of Pascal's triangle.
I want to create a vector-input function named
y = lastnum(vect) on Octave, that evaluate the sum of each pair of numbers in any vectors to output the single number from the evaluation loops like this
0 1 2 3 4
1 3 5 7
4 8 12
12 20
32
And the input and output would be like this,
lastnum([0 1 2 3 4])
ans = 32
I mean... is there any progresses that I can do??? You may not understand but, the reverse triangle above can guide you about my question.
I also tagged MATLAB since it has similar language. MATLAB pros may help my problem.
Notice that the number of times each element gets added to produce the final result comes from Pascals triangle itself, so, e.g., for the vector [a b c d] the result will be a+3b+3c+d. So create a vector of entries in Pascals triangle and multiply and add with the original vector v.
I only have access to Matlab, Octave may not have all these functions.
This is a one-liner diag(fliplr(pascal(numel(v)))).'*v(:).
Or a looping version
s = 0;
for i = 0:numel(v)-1
s = s+nchoosek(numel(v)-1,i)*v(i+1);
end
s
Simplest thing I can think of is:
while length(x) > 0
disp(x)
x = x(1:end-1) + x(2:end);
end
or did I misunderstand the question?
Here is the version for both MATLAB and Octave:
function y = lastnum(v)
while 1
if length(v) == 2
y = sum(v)
break;
end
# disp(v); # if you want to print the progress
vt = [];
for k = 1:(length(v)-1)
vt(end+1) = sum(v(k:(k+1)));
end
v = vt;
end
end

how to compare all vector indexes with a constant value and switch the value of another variable (0 1) based on that

I have a 1x24 vector (a). I should define a command in Matlab which compare all 24 values of a vector (a) with a certain value (mean (b)) and if the vector (a) item is greater than certain value (mean (b)), ''I'' sets 1 and if the vector item is less than certain value ''I'' sets 0. I wrote the below code:
for i=1:length(a)
if a(i) >= mean(b)
I = 1;
else
I = 0;
end
end
But it implements the comparison only for the last index of vector a and sets I=0. How can I fix the command that do the comparison for all indexes of vector a?
In MATLAB, you can use the following syntax to do so:
I = a >= mean(b);
If you want to use your code for doing so, you'll need to initialize I as a vector, and modify its indices as follows:
I = zeros(length(a),1)
for ii=1:length(a)
if a(ii) >= mean(b)
I(ii) = 1;
else
I(ii) = 0;
end
end
You should read about logical indexing in matlab. You don't need for loops for what you are doing. For example, if you have,
rng(5);
a = rand(1,10);
b = 0.5;
then, I = a > b; will return a logical array with zeros and ones, where one indicates the position in the array where the given condition is satisfied,
I =
0 1 0 1 0 1 1 1 0 0
Using these indices, you can modify your original array. For example, if you wish to change all values of a greater than b to be 10, you would simply do,
a(a > b) = 10;
Specifically, if you need indices where the condition is satisfied, you can use, find(a > b), which in this example will give you,
ans =
2 4 6 7 8

Changing the elements of a matrix using a for loop in matlab

I'm having a few issues getting MATLAB to do what I want.
say I have a matrix x = [1 2 3 4; 1 4 4 5; 6 4 1 4]
I'm trying to write code that will go through the matrix and change each 4 to a 5, so it modifies the input matrix
I've tried a few things:
while index <= numel(x)
if index == 4
index = 5;
end
index = index + 1;
end
for item = x
if item == 4
item = 5;
end
end
the simplest thing i tried was
for item = x
if item == 4
item = 5;
end
end
i noticed by looking at the workspace that the value of item did indeed change but the value of x (the matrix) stayed the same.
How do I get the output that i'm looking for?
If you just want to change all the 4s to 5s then:
x(x==4)=5
basically x==4 will result in a logical matrix with 1s everywhere there was a 4 in x:
[0 0 0 1
0 1 1 0
0 1 0 1]
We then use logical index to only affect the values of x where those 1s are and change them all to 5s.
If you wanted to do this using a loop (which I highly recommend against) then you can do this:
for index = 1:numel(x)
if x(index) == 4
x(index) = 5;
end
end
Short answer to achieve what you want:
x(x==4) = 5
Answer to why your code doesn't do what you expected:
You are changing the item to a 5. But that item is a new variable, it does not point to the same item in your matrix x. Hence the original matrix x remains unchanged.

Recurring Function with Matrix Input

I believe most functions in MATLAB should be able to receive matrix input and return the output in the form of matrix.
For example sqrt([1 4 9]) would return [1 2 3].
However, when I tried this recurring factorial function:
function k = fact(z)
if z ~= 0
k = z * fact(z-1);
else
k = 1;
end
end
It works perfectly when a number is input into fact. However, when a matrix is input into fact, it returns the matrix itself, without performing the factorial function.
E.g.
fact(3) returns 6
fact([1 2 3]) returns [1 2 3] instead of [1 2 6].
Any help is appreciated. Thank you very much!
Since MATLAB is not known to be good with recursive functions, how about a vectorized approach? Try this for a vector input -
mat1 = repmat([1:max(z)],[numel(z) 1])
mat1(bsxfun(#gt,1:max(z),z'))=1
output1 = prod(mat1,2)
Sample run -
z =
1 2 7
output1 =
1
2
5040
For the sake of answering your original question, here's the annoying loopy code for a vector or 2D matrix as input -
function k1 = fact1(z1)
k1 = zeros(size(z1));
for ii = 1:size(z1,1)
for jj = 1:size(z1,2)
z = z1(ii,jj);
if z ~= 0
k1(ii,jj) = z .* fact1(z-1);
else
k1(ii,jj) = 1;
end
end
end
return
Sample run -
>> fact1([1 2 7;3 2 1])
ans =
1 2 5040
6 2 1
You can use the gamma function to compute the factorial without recursion:
function k = fact(z)
k = gamma(z+1);
Example:
>> fact([1 2 3 4])
ans =
1 2 6 24
Not sure if all of you know, but there is an actual factorial function defined in MATLAB that can take in arrays / matrices of any size, and computes the factorial element-wise. For example:
k = factorial([1 2 3 4; 5 6 7 8])
k =
1 2 6 24
120 720 5040 40320
Even though this post is looking for a recursive implementation, and Divakar has provided a solution, I'd still like to put my two cents in and suggest an alternative. Also, let's say that we don't have access to factorial, and we want to compute this from first principles. What I would personally do is create a cell array that's the same size as the input matrix, but each element in this cell array would be a linear index array from 1 up to the number defined for each location in the original matrix. You would then apply prod to each cell element to compute the factorial. A precondition is that no number is less than 1, and that all elements are integers. As such:
z1 = ... ; %// Define input matrix here
z1_matr = arrayfun(#(x) 1:x, z1, 'uni', 0);
out = cellfun(#prod, z1_matr);
If z1 = [1 2 3 4; 5 6 7 8];, from my previous example, we get the same output with the above code:
out =
1 2 6 24
120 720 5040 40320
This will obviously be slower as there is an arrayfun then cellfun call immediately after, but I figured I'd add another method for the sake of just adding in another method :) Not sure how constructive this is, but I figured I'd add my own method and join Divakar and Luis Mendo :)

How to detect equal rows of a matrix compare with another matrix with a 10 per cent of margin?

I have a matrix and I want to compare rows of this matrix to rows of another matrix and verify if there are rows wich match them.
For example:
A = [ 1 2 3;...
4 5 6;...
7 8 9 ];
B = [ 54 23 13;...
54 32 12;...
1.1 2.2 2.9];
I need to detect that row 1 of the Matrix A match with the row 3 of the Matrix B. The rows are not equal because I want a +-10 per cent of margin.
Thank you very much.
This code is untested, but should do it:
valid = all(abs(A(1,:) - B(3,:)) ./ A(1,:) < 0.1)
An explanation:
A(1,:) takes the first row of A, and B(3,:) takes the third row of B.
abs(...) takes the absolute value.
abs(...) ./ A(1,:) gives the percentage change
< 0.1 ensures that each element is less than 10%.
all(...) aggregates the values from the last step and tests that they're all true.
In general, if you don't know which row of A may match with B, I wrote a for loop, which is an extension of Fabian answer....
for i = 1:size(A,1)
match(:,i) = sum(abs(ones(size(A,1),1)*A(i,:) - B) ./ (ones(size(A,1),1)*A(i,:)) <= 0.100001, 2) == size(A,2)*ones(size(A,1),1);
end
match(i,j) == 1 if ith row of B matches with jth row of A
I ask this question in other forums and I get the best answer possible to me:
margin = 0.1;
A = [1 2 3; 4 5 6; 7 8 9];
B = [7 8 10; 4 5 12; 1.1 2.2 2.9; 1.101 2 3; 6.3 7.2 9.9];
k = 0;
for i = 1:size(A,1)
for j = 1:size(B,1)
if all(abs((A(i,:)-B(j,:))./A(i,:)) <= margin+eps)
k = k+1;
match(:,k) = [i;j];
end
end
end
fprintf('A row %d matches B row %d.\n',match)
I would like to thank all your answers and I would give you accepted answers, but I think this is the best code for me.