# Is there a way to do conditional matrix loop using 'continue'

I have the following:

n = 3;
m = 5;
ww = RandomReal[{0, 0.1}, {n, n}];
uu = RandomReal[{0, 1}, {m, n}];
pp = RandomReal[{0, 1}, {n, n}];
ss = RandomInteger[{0, 5}, {m, n}];
Grid[{{"ww", "uu", "pp", "ss"}, {ww // TableForm, uu // TableForm,
pp // TableForm, ss // TableForm}}, Spacings -> {5, 2},
Dividers -> All]


where I would like to look at every element of matrix ss and produce a matrix tt, with zeroes at the locations in ss which have zeroes, and in all other positions do the following:

tt = (-1/Subscript[ww, m]) Log[(1 - uu)/(Subscript[pp, m - 1])],


where Subscript[ww, m] is the value at index of ww matrix and where Subscript[pp, m - 1] is the value at index-1 of pp matrix.

So for example if the first value ever read from matrix ss happens to be 2, then value taken from matrix ww would be from the row 2, but from pp would be from row 1.

Also how to tell difference between a 0 as a valid value from within the matrix elements to end of matrix if I do not know the actual size of the matrix beforehand?

Given the data as above, tt matrix would be like this:

-
Hi @kguler. Thanks for editing but not sure how can someone else edit my post? :) –  sebastian c. Nov 8 '12 at 12:41
I'm a little unclear about what tt is intended to do. As it is presented tt has a small syntax error, the training comma. Secondly Subscript[ww,m] is a formatted object with ww displayed with a typographical subscript m. Your text suggests that it is the value at index of ww. Does index refer to m? If the value in ss is 2 then the "value" to be taken from ww would be from row 2. Do you mean all of row 2 or some particular element in row 2, if so which element ? –  image_doctor Nov 8 '12 at 14:30
@sebastiancheung see here –  acl Nov 8 '12 at 15:57
Hi @image_doctor, I just added what matrix tt would look like using the input data prescribed. i.e, looking at 2nd column 1st row of ss value at 2: gives (-1/ww22)Log(1-uu12)/pp12)=(-1/0.05565)Log(1-0.8498)/0.490 = 21.25. Similarly 3rd column, 1st row of ss, take corresponding value from element uu13 (0.5322), with value of 3 means take value of ww33 (0.053) and pp23 (0.882) = 11.93 –  sebastian c. Nov 9 '12 at 13:37
Can I clarify, is it the case that you want an output matrix, which has scalar values at each position and not an output matrix which has a matrix tt of zeroes at each position in which ss has a zero and a scalar value tt at other positions? –  image_doctor Nov 12 '12 at 14:06
show 1 more comment

## 3 Answers

Two gaps in the information provided in the question : First, the elements of ss cannot be greater than 3 (row dimension of ww and pp). Second, how do you process the case ss[[i, j]] = 1 ? (Which row of pp do you use?) You need to change the rule so that either ss does not contain any 1s or treat the 1s as you treat 0s. In the following I restricted ss to values in {0, 2, 3}.

n = 3; m = 5;
ww = RandomReal[{0, 0.1}, {n, n}];
uu = RandomReal[{0, 1}, {m, n}];
pp = RandomReal[{0, 1}, {n, n}];
ss = RandomChoice[{0, 2, 3}, {m, n}];


Define tt as

tt = SparseArray[{i_, j_} /; ss[[i, j]] != 0 :>
(-1/ww[[ss[[i, j]], j]]) Log[(1 - uu[[i, j]])/ pp[[ss[[i, j]] - 1, j]]], {m, n}]


With this,

Grid[Transpose@{{"ww", "uu", "pp", "ss", "tt"},
TableForm /@ {ww, uu, pp, ss, Normal[tt]}}, Spacings -> {5, 2}, Dividers -> All]


UPDATE: Incorporating OP's latest clarifications:

ww2 = Prepend[ww, {a, b, c}];
f2[i_, j_] := (-1/ww2[[ss[[i, j]] + 1, j]]) Log[(1 - uu[[i, j]])/pp[[ss[[i, j]], j]]];
tt2 = SparseArray[{i_, j_} /; ss[[i, j]] != 0 :> f2[i, j], {m, n}];
Grid[Transpose@{{"uu", "ww", "pp", "ss", "ww2", "tt2"},
TableForm /@ {uu, ww, pp, ss, ww2, Normal[tt2]}},
Spacings -> {5, 2},
Dividers -> {{All, {1 -> Thick, -1 -> Thick}},
{All, {5 -> Thick, 1 -> Thick, -1 -> Thick}}}]


-
Hi @kguler, Well spotted! Therefore pp matrix has to have one more row greater than matrix ww, I filled it with 1 1 1, so that if elements within ss happens to be value of 1, tt has to go one more row back. –  sebastian c. Nov 9 '12 at 14:47
Hi @kguler, how long you have been using Mathematica? Seems like you know everything there is about it? It is the solution I am looking for. In that case what do you need to modify? Great Help :) –  sebastian c. Nov 9 '12 at 15:24
sebastian, adding a row of 1s to pp will not work --you still would be referring to pp[[0,j]] when the corresponding element in ss is 1. You can leave 1s in ss instead. (I have been using Mma off and on version 1; but only after version 6 it has become my main tool/toy.) –  kguler Nov 10 '12 at 0:54
@sebastian, I meant define tt so that tt[[i,j]]=ss[[i,j] if ss[[[i,j]]=0 or ss[[i,j]]=1. That is, change the part inside SparseArray following :> to If[ss[[i, j]] == 1, 1, (-1/ww[[ss[[i, j]], j]]) Log[(1 - uu[[i, j]])/ pp[[ss[[i, j]] - 1, j]]]]. This should work when "1s are present in ss". –  kguler Nov 10 '12 at 22:15
Hi @kguler, possible to work with pp with one more row than ww as well as evaluating when ss has elements containing 1s? –  sebastian c. Nov 10 '12 at 22:28
show 6 more comments

MapIndexed might be what you are looking for. For example, start with a matrix of zero and non-zero elements:

s = RandomInteger[{0, 1}, {3, 3}]


{{0, 1, 1}, {0, 1, 0}, {1, 1, 1}}

And another matrix of stuff:

instead = Table[w[i, j], {i, 3}, {j, 3}]


{{w[1, 1], w[1, 2], w[1, 3]}, {w[2, 1], w[2, 2], w[2, 3]}, {w[3, 1], w[3, 2], w[3, 3]}}

The use MapIndexed to trawl through and substitute as required:

MapIndexed[If[#1 == 0, #1, instead[[Sequence @@ #2]]] &, s, {2}]


{{0, w[1, 2], w[1, 3]}, {0, w[2, 2], 0}, {w[3, 1], w[3, 2], w[3, 3]}}

This goes through each element of s, if it's zero keep it as it is, if not use the current index to pull something out of another matrix.

-
Hi @wxffles very fast response and it seems to work, though not exactly what I asked for, but could be adapted. Also what is this last argument levelspec set to 2 does? –  sebastian c. Nov 8 '12 at 14:30
@sebastiancheung The {2} is to map on to exactly the elements that are 2 levels deep. Just what you need for a 2D matrix. I was a little hazy on exactly what you required, but confident it could be adapted. You can of course modify the index #2 before you use it. –  wxffles Nov 8 '12 at 18:58
add comment

Here is a solution which uses replacement rules. It looks at each element in a matrix and replaces it with something based upon the value of the element.

Define a function which can be used to replace an element based on the values of matrices defined in some global variables ( here we take the row referred to by element from ww and pp):

f[element_]:=ww[[element]] + pp[[element]]


Define an arbitrary array of zeroes, the size of this could be based on the value of element if desired:

zeroes = ConstantArray[0,{2,2}]


Replace elements of matrix ss with things based on the value of its elements:

ss /. {0 :> zeroes, elem_?Positive :>f[elem]}


The entire solution could be condensed to by abstracting out the auxiliary functions:

  ss /. {0 :>  ConstantArray[0,{2,2}], elem_?Positive :> ww[[elem]] + pp[[elem]] }


Update based on clarifications to original question:

Both the following solutions build an intermediate matrix, merging a value from ss with its indices, of the form {{{ss[[1,1]],1,1},{ss[[1,2]],1,2},...},{...},{...,{ss[[m,n]],m,n}}}

An outline solution in which myFunc takes the place of whatever needs to be done in case of a non-zero element in ss.

A function based on element indices from ss:

myFunc[i_, j_] := {i^2, j^2}


Solution using replacement rules

Derive a new matrix from the elements of ss

tt=Array[{ss[[#1, #2]], #1, #2} &, Dimensions@ss] /.
{{0, _, _} :> 0, {a_?Positive, b_, c_} :> myFunc @@ {b, c}}


Solution using Apply

Define what to do to each element:

myFunc[0, i_, j_] := 0
myFunc[val_, i_, j_] := {i^2, j^2}


Apply the function to ss:

Apply[myFunc, Array[{ss[[#1, #2]], #1, #2} &, Dimensions@ss], {2}]


-
Hi @image_doctor, this is very similar to kguler solution? –  sebastian c. Nov 12 '12 at 12:50
Yes, broadly similar in that they both use replacement rules. I've updated the solution in light of your clarifications and added an alternate using Apply. –  image_doctor Nov 12 '12 at 14:31
add comment