2
$\begingroup$

I have created an "array" of sorts using

For[i = 1, i <= Length[vector], i++,
  codes[i] = {}
  ];

The vector is a vector of probabilities, the sum of the vector is 1. I want to start halfing the vector and after each halfing, I want to add a number to the appropriate codes[i] variable. Meaning I half the vector, then I half the halves, etc. etc., until only individuals are left, and that is where the program ends, with each codes[i] filled with appropriate numbers. The halfing is done based on the sums of probabilities, not the length of the vector, so a 6 item vector could be halfed into 2 and 4 items.

I have tried looping the halfing, but of course, it cuts it, assigns numbers, and then starts halfing the first half, and ignores the second, from where it progresses, and only a small part of the vector is done correctly in the end.

total = 1;
sum = 0;
For[i = 1, sum < (total/2), i++,    
  sum = sum + vector[[i]];
  cut = i;
  ]; 

To cut a vector in half I run a cycle, summing the probabilities in the vector until the sum is greater or equal to half of what I need. The value of total is 1, because the sum of all the probabilities is 1, therefore I run a cycle adding up until the sum is greater than 0.5, then I save the index of the last number, and I run more cycles that fill the codes[i] vectors with numbers. I fill them with 0s and 1s, so I fill codes[i] with 0s up until the cut variable, then I fill the rest with 1s.

Is it possible to make such a loop, where it completes the entire vector?

$\endgroup$
6
  • 5
    $\begingroup$ Perhaps an example illustrating how "halving" a vector of probabilities is done will be helpful. $\endgroup$ – J. M.'s torpor Apr 22 '20 at 13:52
  • $\begingroup$ ` total = 1; sum = 0; For[i = 1, sum < (total/2), i++, sum = sum + vector[[i]]; cut = i; ]; ` I run a cycle, summing the probabilities in the vector until the sum is greater or equal to half of what I need. The value of total is 1, because the sum of all the probabilities is 1, therefore I run a cycle adding up until the sum is greater than 0.5, then I save the index of the last number, and I run more cycles that fill the codes[i] vectors with numbers. I fill them with 0s and 1s, so I fill codes[i] with 0s up until the cut variable, then I fill the rest with 1s. $\endgroup$ – Drobdien Apr 22 '20 at 14:50
  • 2
    $\begingroup$ Please include this information in your question, instead of the comments. $\endgroup$ – J. M.'s torpor Apr 22 '20 at 15:00
  • $\begingroup$ can you illustrate the steps using vector = {.2, .1, .4, .3}? $\endgroup$ – kglr Apr 22 '20 at 23:55
  • $\begingroup$ in the first step you find cut=3 and split vector into two pieces vector2 ={{0.2, 0.1, 0.4}, {0.3}}... then what? $\endgroup$ – kglr Apr 22 '20 at 23:57
3
$\begingroup$
ClearAll[splitF, codeF]

splitF = ReplaceRepeated[lst : {_?NumericQ, __?NumericQ} :> 
    TakeDrop[lst, 1 + LengthWhile[Accumulate[Normalize[lst, Total]], # < .5 &]]];

codeF = Position[splitF@#, {_?NumericQ}] - 1 &;

splitF splits an input list repeatedly until all sublists are singletons. A non-singleton list is first normalized (so that its sum is 1) and accumulated and then split when accumulated total exceeds the threshold .5.

codeF uses the position indices as the code for each singleton sublist.

Examples:

vec1 = {.4, .3, .2, .1};
vec2 = {.3, .3, .2, .1, .1};
vec3 = {.3, .1, .1, .1, .1, .1, .1, .1};
SeedRandom[777]
vec4 = ReverseSort@Normalize[RandomReal[1, 8], Total];

Grid[Prepend[Column /@ {#, splitF@#, codeF@#} & /@ {vec1, vec2, vec3,  vec4}, 
  {"vec", "splitF@vec", "codeF@vec"}], Dividers -> All]

enter image description here

We can pad the codes on the left (by repeating the left-most digit) or right (by repeating the right-most digit) to get equal-length codes:

ClearAll[padLeft, padRight, codeFL, codeFR]

padLeft = PadLeft[#, Automatic, \[FormalX]] /. 
    l : {Longest[\[FormalX] ..], a_, b___} :> (l /. \[FormalX] -> a) &;

padRight = PadRight[#, Automatic, \[FormalX]] /. 
    l : {b___, a_, Longest[\[FormalX] ..]} :> (l /. \[FormalX] -> a) &;

codeFL = padLeft[Position[splitF@#, {_?NumericQ}] - 1] &;

codeFR = padRight[Position[splitF@#, {_?NumericQ}] - 1] &;
Grid[Prepend[Column/@ {#, splitF @ #,  codeF @ #, codeFL @ #, codeFR @ #} & /@ 
     {vec1, vec2, vec3, vec4},
   {"vec", "splitF@vec", "codeF@vec", "codeFL@vec", "codeFR@vec"}], Dividers -> All]

enter image description here

SeedRandom[777]
vec5 = ReverseSort@Normalize[RandomReal[1, 30], Total];

Row[ArrayPlot[ToExpression[#] @ vec5, PlotLabel -> Style[#, 16], 
    ImageSize -> 1 -> 20, 
    FrameTicks -> {{Transpose[{Range @ Length @ vec5, 
         Row /@ ToExpression[#] @ vec5}], None}, 
       {All, All}}] & /@ 
    {"codeF", "codeFL", "codeFR"}, 
  Spacer[20]]

enter image description here

$\endgroup$
2
  • $\begingroup$ Could you please explain the first block of code? From 'Clear All' to 'codeFR'. $\endgroup$ – Drobdien Apr 25 '20 at 5:03
  • $\begingroup$ @Drobdien, added a few notes. Hope this helps. $\endgroup$ – kglr Apr 25 '20 at 5:38

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.