4
$\begingroup$

First of all, I don't really know how to formulate the question, so if you understand my question and know a better way to phrase it, please revise.

I have the following Matrixes:

a[n_, m_] := Table[n + m - i - j, {i, 1, n}, {j, 1, m}]
b[n_, m_] := Round[Table[(n*m/2)*(1 + 2 j/m), {j, 1, m}]]

(these are just chosen to test the sequence). Where a[n,m] is a nxm Matrix, and b[n,m] a vector of length m.

I want to make a sequence that accumulates a[n,m], but, when it becomes higher than b[n,m] at a certain m, it has to take the respective value of b[n,m] and continue the accumulations (or another exception).

I tried a couple of ways like with FoldList and MapThread or RecurrenceTable. But I just didn't get there. I think there is a simple way which I just didn't think of.

Finally I just did it by hand (and called it c[n,m]) with a[3,8] and b[3,8]

a[3,8] =
{{9, 8, 7, 6, 5, 4, 3, 2},
 {8, 7, 6, 5, 4, 3, 2, 1},
 {7, 6, 5, 4, 3, 2, 1, 0}}

b[3,8] = {15, 18, 21, 24, 27, 30, 33, 36}

c[3,8] = {{9, 17, 21, 24, 27, 30, 33, 35}, {8, 15, 21, 24, 27, 30, 32, 33}, {7, 13, 18, 22, 25, 27, 28, 28}}

I hope you can help me out.

$\endgroup$
1
$\begingroup$

Initial setting:

Clear[a, b, A, B]
a[3, 8] = {{9, 8, 7, 6, 5, 4, 3, 2}, {8, 7, 6, 5, 4, 3, 2, 1}, {7, 6, 
    5, 4, 3, 2, 1, 0}};
b[3, 8] = {15, 18, 21, 24, 27, 30, 33, 36};

Prepare data:

B = Prepend[b[3, 8], 0]; A = Prepend[#, 0] & /@ a[3, 8];

Function:

f[A_, B_] :=
 Module[{i = 2, a = A, b = B},
  While[i++ < Length@b, 
   a[[i]] = Min[b[[i]], Total@a[[i - 1 ;; i]]]];
  Rest@a
 ]

Application:

f[#, B] & /@ A

Result:

{{9, 17, 21, 24, 27, 30, 33, 35}, {8, 15, 21, 24, 27, 30, 32, 33}, {7, 13, 18, 22, 25, 27, 28, 28}}

$\endgroup$
  • $\begingroup$ @immaan, thank you for accepting. Note that uppercase for variables is a bit agains convention in MMA, but I've used it for better transparency of the code. $\endgroup$ – garej Dec 9 '15 at 11:04
  • $\begingroup$ I very well see! but how did you get to this solution... it is way shorter then the others and more understandable. But as I continue, I am wondering how to do it in more arbitrary ways. $\endgroup$ – immaan Dec 9 '15 at 21:11
  • $\begingroup$ @immaan, I'm not sure what do you mean by 'arbitrary'. A for the task, it seemed to me a good example where traditional 'procedural' style is ok. in general, try to compare flat simple lists at first. Matrixes (lists of lists) just add some complexity. $\endgroup$ – garej Dec 10 '15 at 8:02
  • $\begingroup$ I mean how to create a more sequences like this in more general way. (timed sequences) like 'f[t] == g[t,f[t-1]]'. But I think that will just be my next question to ask here in public. So if you don't know how to answer it, please tell me how these sequences are called, so I can formulate my question right. $\endgroup$ – immaan Dec 10 '15 at 8:58
  • $\begingroup$ @immaan, I would start from this question and related links. I guess your concern is recurrence sequences. There are a lot of syntactic sugar in MMA for that stuff. $\endgroup$ – garej Dec 10 '15 at 10:28
2
$\begingroup$
a[n_, m_] := Table[n + m - i - j, {i, 1, n}, {j, 1, m}];
b[n_, m_] := Round[Table[(n*m/2)*(1 + 2 j/m), {j, 1, m}]]; 

fun[li_, rp_] :=
 Module[{p = First@FirstPosition[li - rp, _?Positive]},
  If[p === "NotFound", li, Join[li[[;; p - 1]], rp[[p ;;]]]]]

fun[#, b[3, 8]] & /@ Accumulate /@ a[3, 8] // MatrixForm

enter image description here

$\endgroup$
  • $\begingroup$ First of all, thank you for your reaction! It looks pretty complicated and is on the right path. But, there is a point where your function did not work. For the first row its the last number, and for the second row the last two numbers. There you can see that it did not go back to the state where it had to check for the Minimum again. Like in my output, First row: 33+2<36, Second row: 30+2<32, 30+2+1<35 $\endgroup$ – immaan Dec 8 '15 at 14:44
1
$\begingroup$

The function below in association with NestList can be used for two list of equal length.

myAccumulate[{lista_, listb_}] :=
Module[{tot, l1, l2},
l1 = lista; l2 = listb;
(*collect the minimum value*)
ans = Flatten[Join[{ans, Min[l1[[1]], l2[[1]]]}]];

 Which[Length[l1] == 1 && Length[l2] == 1, {l1, l2} = {{}, {}}, True,
l1 = Drop[l1, {1}];
tot = Total[{Last[ans], l1[[1]]}];
l1 = Drop[l1, {1}];
PrependTo[l1, tot];
l2 = Drop[l2, {1}]];
{l1, l2}
 ]

For example with the following two list we get

list1 = {9, 8, 7, 6, 5, 4, 3, 2};
list2 = {15, 18, 21, 24, 27, 30, 33, 36};
ans = {};
NestList[myAccumulate, {list1, list2}, 8];
ans

(*{9, 17, 21, 24, 27, 30, 33, 35}*)

The list ans stores the minimum value for each iteration. For your list you can use it as follows:

Table[
ans = {};
NestList[myAccumulate, {a[3, 8][[i]], b[3, 8]}, Length[b[3, 8]]];
ans, {i, 3}]

(*{{9, 17, 21, 24, 27, 30, 33, 35}, {8, 15, 21, 24, 27, 30, 32, 33}, {7,
13, 18, 22, 25, 27, 28, 28}}*)
$\endgroup$

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.