Need Help for creating constraint with If conditions

I have 'Z(im)', 't(m)', and f(i) vectors as following (left side is parameter indices=Zim):
im Zim t(m) f(i)
11 0 12 6
12 0 11 6
13 1 10 6
21 0 12 3
22 1 11 3
23 0 10 3
31 0 12 5
32 1 11 5
33 0 10 5
and an equality constraint as following:
Z(im)*Y(im)+S(im)=t(m)-Z(im)*f(i) for all i and m, *IF Zim=1*
I need to find Rhs of equalities for values where Zim=1.
For instance, we know Z13, Z22, and Z32 are all equal to 1. Thus I want to create a 3x1 (mx1) column vector for those right hand side values as following:
b=[4; 8; 6]
I believe, I need to use for loop and if command. But, I can't figure out a way to construct a loop for this question.
Thanks for help.

 Accepted Answer

No loops needed...given your above array as m,
>> ix=m(:,2)==1;
>> b=m(ix,3)-m(ix,4)
b =
4
8
6
>>

8 Comments

They were all in separate vectors, however, it works well once they are combined in one matrix. Thank you very much dpb.
Just substitute the vector variable for the column, then; no need to combine. And, of course, then it's only a single index needed as there would only be the one column.
I have one more question. If Zim=1, I want to create a matrix as following:
S11 S12 S13 S21 S22 S23 S31 S32 S33 Y11 Y12 Y13 Y21 Y22 Y23 Y31 Y32 Y33
0 0 1 0 0 0 0 0 0 0 0 1 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 0 0 1 0 0 0 0 0 0 0 0 1 0
Basically I need to create a matrix that contains coefficients of variables (Y(im) and S(im)). Since I will create constraints based on the occurrence of Zim=1 condition, coefficients of Y(im) will always be 1. Similarly, S(im) will always have a coefficient of 1. The only problem is to detect their places on this 3x18 matrix. The size 3 depends on number of i, I assume i=3 in here. The column number 18 depends on 2*i*m since the question have 2 indices and 2 different variables. If you may formulate this by using if command or within another way, I would really appreciate it. This formulation is really challenging for my level.
Just write the row location desired from the i,m indices...
1,1-->1
1,2-->2
1,3-->3
2,1-->4
...
It's simply a linear expression in i,m,
Spos=(m-1)+3*(i-1)+1;
Y is the same relation except just offset by 9 so first location is 10 instead of 1.
Ypos=(m-1)+3*(i-1)+9;
There's a convenient conversion function in Matlab that converts from subscripts to linear indices; sub2ind. But, since Matlab stores in column major order instead of row, you'll need to reverse i,m in order to use it...the above would be using it
Spos=ind2sub([3,3],m(ix),i(ix));
Ypos=Spos+9;
where ix again is the logical addressing vector from the Z==1 operation and i,m are the two coordinates. The [3,3] is the size of the array for which the indices are being converted; that's what gives the function the multiplier in the explicit expression above. Note the reversal of i,m to account for row-major rather than default column-major storage order.
See
doc ind2sub % and friends for details
and read up on array indexing in the "Getting Started" tutorial information on using Matlab; it's critical to understand and be able to use the order of array storage in matrices to effectively perform many operations in Matlab such as this.
Tried all this, but couldn't find a true solution. It seems very easy, but tricky. I also tried using double for loops and if condition. But, they just confused me more.
For Spos and Ypos, you could say:
Spos = i*m;
Ypos = 2*i*m;
because i=3 and m=3. However, I couldn't understand what we are going to do with 9 and 18.
In here:
Spos=ind2sub([3,3],m(ix),i(ix));
Ypos=Spos+9;
You are basically saying:
9 = ind2sub([3,3], 3(ix), 3(ix)); %which doesn't make sense to me.
Ypos = 9+9
Either I am missing something or I expressed i and m wrongly in my question.
Tried what, specifically...??? It's pretty much straightforward as shown once you've calculated the locations, it's just setting those values in an array--again, since I had your original data already in an array m
>> posS=sub2ind([3,3],mod(m(ix,1),10),fix(m(ix,1)/10));
>> j=[posS posS+9]; % the offset to Y from S is 9 as shown...
>> j
j =
3 12
5 14
8 17
>> a=zeros(3,18); % a target array
>> for i=1:3, a(i,j(i,:))=1;end % set the locations wanted
>> num2str(a,'%3d') % display result in closed format
ans =
0 0 1 0 0 0 0 0 0 0 0 1 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 0 0 1 0 0 0 0 0 0 0 0 1 0
>>
QED
ADDENDUM
It is, of course, also possible w/o looping...create the vector of row positions 1:3 n(2) times to go along with the column positions and use sub2ind again excepting on the new array size of nx18--
>> ii=reshape(repmat([1:3],2,1),[],1); % try it, see what gets... :)
>> jj=[posS.'; posS.'+9]; jj=jj(:);
>> a=zeros(3,18);
>> a(sub2ind(size(a),ii,jj))=1;
>> num2str(a,'%3d')
ans =
0 0 1 0 0 0 0 0 0 0 0 1 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 0 0 1 0 0 0 0 0 0 0 0 1 0
>>
Again, the above are based on knowing about Matlab internal storage order so that rearranging an array created in the correct order to begin with will lead to the desired result--here, 2 copies or the 3 row indices to go with the two column positions to be set for each row. Note that you'll often see a Matlab idiom used here instead altho it takes two steps instead of one--
ii=repmat([1:3],2,1);
ii=ii(:); % force all elements of array into column vector
ERRATUM I did make an "off by one error" in adding 10 instead of nine; sorry. Corrected above.
Is that what was confusing you? The expression you've written with ind2sub isn't correct interpretation of what it does. Read the documentation and 'spearmint with it to understand -- it takes the [i,j] row, column indices vectors of an array of a given size (first argument) and returns the linear address of those indices. They're the same locations in storage order whether the array is nxn or nx1 or 1xn; it's the last we're interested in here--converting that array location to it's corresponding position in a row vector. As the demo I posted later shows, the internal computation is the same as the explicit calculation; it just needs to know the array size (actually, only the number of rows for the location for 2D; the number of columns simply lets it check that the indices given are in the bounds of the original array) in order to know the factor for adjusting the second bound.
All I can say is work through the details and read the section in "Getting Started" of the documentation on array storage and the subtopic "linear indexing".
ONE LAST ADDENDUM :)
Ok, maybe it will help to point out that all that
a(sub2ind(size(a),ii,jj))=1;
is doing is the equivalent of what
a(ii,jj)=1;
IF (the proverbial "big if") Matlab were to interpret the above as assigning each row of the two indices vectors together as the corresponding subscript location. But, it doesn't work that way if you'll try it you'll see don't get the desired answer. That's why I wrote the looping solution first; figured it would be easier to follow even though it's not "the Matlab way" of using vectorized expressions. sub2ind, however, does take the two index variables passed as row,column as pairs, computes the linear address in the array of the given size from them, and assigns the RHS to that location--exactly what we want here.
All these are above my recent programming knowledge. I understand you can create multiple ways to solve my problem, but, I can't really understand how you are doing these. I believe, I need to start from the beginning to learn all. I am lost in your codes :(
By the way, the reason is I asked the question in a wrong format. That is experience. Now, I got how I need to ask it :)
"For Spos and Ypos, you could say: Spos = i*m; Ypos = 2*i*m; because i=3 and m=3"
No. The general expression for the row location from 1 thru 9 for the 3x3 array locations is (m-1)+3(i-1)+1.
>> a=reshape(1:9,3,3) % a 3x3 array in memory order
a =
1 4 7
2 5 8
3 6 9
>> [i j]=ind2sub(size(a),1:9); % the subscripts from linear order
>> [i.' j.']
ans =
1 1
2 1
3 1
1 2
2 2
3 2
1 3
2 3
3 3
>> for i=1:3, % from explicit expression
for m=1:3,
disp([m i (m-1)+3*(i-1)+1]),
end,end
1 1 1
2 1 2
3 1 3
1 2 4
2 2 5
3 2 6
1 3 7
2 3 8
3 3 9
>>
The locations you're wanting in the 18-column array are simply two 9-column array locations placed one to the right of the other. Since each has the same i,m values, they're simply offset by 10 positions from each other; no reason to compute but the left one and then shift it to the right to compute the other.

Sign in to comment.

More Answers (0)

Asked:

on 9 Jul 2016

Edited:

dpb
on 11 Jul 2016

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!