1
$\begingroup$

I am trying to find the minimum value of a row of a matrix and its corresponding column. Please run the code below. OptV is the matrix that I would like to create which must give the output of the minimum of each row and its corresponding column index in VAll matrix.

    Clear[OptV, V,VAll, NU, EDD, PCP]
    binc = 0.2;
    InitV[cs_, cc_, ED_, P_, NL_, pR_, pW_, b_] = Table[1, {b, 0, 1, binc}];
    V[1] := InitV[cs, cc, ED, P, NL, pR, pW, b];
    NU[cs_, cc_, ED_, P_, NL_, pR_, pW_, b_] = Table[NL + (1 - b) (cs + (1 - pR) (P + pW ED)) + b ED, {b, 0, 1, 
binc}]; 
    PCP[cs_, cc_, ED_, P_, NL_, pR_, pW_, b_] = Table[(1 - b) cs + 
b cc + (1 - (1 - b) pR) (P + (b + (1 - b) pW) ED), {b, 0, 1, 
binc}]; 
    EDD[cs_, cc_, ED_, P_, NL_, pR_, pW_, b_] = Table[ED, {b, 0, 1, binc}];

    For[i = 2, i < 20, i++, V[i_Integer] := V[i] = Min /@ Transpose[{Table[(1 - b) cs + b cc + (1 - (1 - b) pR), {b, 0, 1, 
      binc}]*V[i - 1], PCP[cs, cc, ED, P, NL, pR, pW, b], 
   NU[cs, cc, ED, P, NL, pR, pW, b], 
   EDD[cs, cc, ED, P, NL, pR, pW, b]}]];
    W[cs_, cc_, ED_, P_, NL_, pR_, pW_, b_] = Table[(1 - b) cs + b cc + (1 - (1 - b) pR), {b, 0, 1, binc}]*V[i];
    VAll[cs_, cc_, ED_, P_, NL_, pR_, pW_, b_] = 
     Transpose[{W[cs, cc, ED, P, NL, pR, pW, b], 
    PCP[cs, cc, ED, P, NL, pR, pW, b], 
    EDD[cs, cc, ED, P, NL, pR, pW, b], 
    NU[cs, cc, ED, P, NL, pR, pW, b]}];
    OptV[cs_, cc_, ED_, P_, NL_, pR_, pW_, b_] = 
     With[{m = Min@#}, {m, Position[#, m][[1, 1]]}] & /@ 
      VAll[cs, cc, ED, P, NL, pR, pW, b];
     With[{cs = 1, cc = 10, ED = 100, P = 25, NL = 5, pR = 0.1, pW = 0.25},
     MatrixForm[VAll[cs, cc, ED, P, NL, pR, pW, b]]]
      With[{cs = 1, cc = 10, ED = 100, P = 25, NL = 5, pR = 0.1, pW = 0.25},
      MatrixForm[OptV[cs, cc, ED, P, NL, pR, pW, b]]]
$\endgroup$
  • $\begingroup$ I presume the ai in the first two functions was meant as multiplication? $\endgroup$ – ciao May 1 '16 at 1:04
  • $\begingroup$ Hi, yes it is multiplication, but please do not worry about the particular function written there. I am simply trying an example here a simple one. $\endgroup$ – Engin May 1 '16 at 1:05
  • $\begingroup$ With[{m = Min@#}, {m, Position[#, m][[1, 1]]}] & /@ Opt[...] if only 1 minimum is expected per row, With[{m = Min@#}, {m, Position[#, m]}] & /@ Opt[...] if multiple minimums can be in a row, in which case the vector of positions results. If the array is going to be huge, there are more efficient ways... $\endgroup$ – ciao May 1 '16 at 1:10
  • $\begingroup$ Hi, first of all thank you very much. And yes this will be a huge matrix most probably 1000 by 1000. $\endgroup$ – Engin May 1 '16 at 1:12
  • $\begingroup$ 1k x 1k is not all that big, so performance s/b fine with the above. Give it a whirl, if you need faster, comment... $\endgroup$ – ciao May 1 '16 at 1:21
2
$\begingroup$

You have your matrix,

mat = 
 With[{cs = 1, cc = 10, ED = 100, P = 25, NL = 5, pR = 0.1, 
   pW = 0.25}, VAll[cs, cc, ED, P, NL, pR, pW, b]]
(* {{87.4, 46., 100, 51.}, {229.896, 62.6, 100, 61.8}, {402.204,
   79.8, 100, 72.6}, {613.824, 97.6, 100, 83.4}, {864.756, 116., 100, 
  94.2}, {1100., 135., 100, 105.}} *)

You can get the list you want using Min, First, and Ordering,

{Min@#, First@Ordering[#, 1]} & /@ mat
(* {{46., 2}, {61.8, 4}, {72.6, 4}, {83.4, 4}, {94.2, 4}, {100, 
  3}} *)

You could make it slightly more efficient by using using With to avoid calling Min, but on a test matrix with over 400 million elements I got a speedup of less than .2 seconds.

Of course, this assumes that you only are interested to have a single column position for each row - so if the minimum value appears more than once you get the column number of its first appearance. From the OP it sounds like this is what is wanted.

$\endgroup$
  • 1
    $\begingroup$ If you're going to assume that there's only one minimum per row (and/or only care about first found, as it appears in OP), With[{o = First@Ordering[#, 1]}, {#[[o]], o}] & is much more efficient, particularly on large arrays... $\endgroup$ – ciao May 2 '16 at 8:00
  • $\begingroup$ @ciao - Thanks, that really does speed it up! $\endgroup$ – Jason B. May 2 '16 at 8:15
0
$\begingroup$

If I understand you right, you may want to try this,

k[a_, i_] := Position[opt[a, i], Min[opt[a, i]]] // Flatten

However, in your example the minimum will always be the upper leftmost element of your final array, Opt[a,i].

I would also advise using different symbols. Personally I avoid capitol letters generally and symbols that could conflict with Mathematica's built-in definitions.

$\endgroup$
  • $\begingroup$ This did not work $\endgroup$ – Engin May 2 '16 at 2:45
  • $\begingroup$ Could you check my code above? I edited my post now you can see the functions. $\endgroup$ – Engin May 2 '16 at 2:56
  • $\begingroup$ What went wrong? My code was designed to return the row and column indices of the minimal element(s). Maybe that's not what you want? You can also find the minimal values themselves by the following code, mm[[Sequence @@ #]] & /@ k[a,i] $\endgroup$ – DSkinner May 2 '16 at 13:37
  • $\begingroup$ I ran your first block of code and tested it the following code Position[test, Min[test]] // Flatten, where test is the matrix VAll evaluated at the values you specified. It gives the minimum at position {1,2}. test[[1,2]]=46 which, upon inspection of the matrix elements is correct. Again, maybe you are looking for something different than this? $\endgroup$ – DSkinner May 2 '16 at 14:13
  • $\begingroup$ Okay, try this--a modification of your code, OptV= With[{cs = 1, cc = 10, ED = 100, P = 25, NL = 5, pR = 0.1, pW = 0.25}, {#, Position[#, Min@#][[1, 1]]} & /@ VAll[cs, cc, ED, P, NL, pR, pW, b]] This produces a list of each row and the position within that row of the minimal element. $\endgroup$ – DSkinner May 2 '16 at 14:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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