enter image description hereI 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: enter image description here

  • $\begingroup$ Hi @kguler. Thanks for editing but not sure how can someone else edit my post? :) $\endgroup$ Commented Nov 8, 2012 at 12:41
  • $\begingroup$ 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 ? $\endgroup$ Commented Nov 8, 2012 at 14:30
  • $\begingroup$ @sebastiancheung see here $\endgroup$
    – acl
    Commented Nov 8, 2012 at 15:57
  • $\begingroup$ 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 $\endgroup$ Commented Nov 9, 2012 at 13:37
  • $\begingroup$ 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? $\endgroup$ Commented Nov 12, 2012 at 14:06

3 Answers 3


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]

enter image description here

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}}}]

enter image description here

  • $\begingroup$ 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. $\endgroup$ Commented Nov 9, 2012 at 14:47
  • $\begingroup$ 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 :) $\endgroup$ Commented Nov 9, 2012 at 15:24
  • $\begingroup$ 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.) $\endgroup$
    – kglr
    Commented Nov 10, 2012 at 0:54
  • $\begingroup$ @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". $\endgroup$
    – kglr
    Commented Nov 10, 2012 at 22:15
  • $\begingroup$ Hi @kguler, possible to work with pp with one more row than ww as well as evaluating when ss has elements containing 1s? $\endgroup$ Commented Nov 10, 2012 at 22:28

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.

  • $\begingroup$ 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? $\endgroup$ Commented Nov 8, 2012 at 14:30
  • $\begingroup$ @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. $\endgroup$
    – wxffles
    Commented Nov 8, 2012 at 18:58

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]}

Mathematica graphics

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}}

Mathematica graphics

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}]

Mathematica graphics

  • $\begingroup$ Hi @image_doctor, this is very similar to kguler solution? $\endgroup$ Commented Nov 12, 2012 at 12:50
  • $\begingroup$ 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. $\endgroup$ Commented Nov 12, 2012 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.