2
$\begingroup$

This one is somewhat hard to explain, but I'll try my best to.
I'm trying to generate a list of numbers (containing only pi/10, 0, -pi/10). Numbers are randomly selected from these 3, where the probability of getting 0 is always 70%. But the probability of getting pi/10 and -pi/10 depend on the previous outcomes.

Here's I'm going to explain it how it depends:

Initially, the probability of getting pi/10 is 25%, and of getting -pi/10 is 5%. But once I get -pi/10 as an outcome, probabilities will be switched. (i.e., the probability of getting pi/10 will be 5%, and of getting -pi/10 will be 25%.)
Similarly, when pi/10 comes next comes as an outcome, probabilities will again get switched and so on...

So, here's what I've tried, but didn't get the desired result.

rr := RandomReal[{0, 1}]
x1 = \[Piecewise]{{0, # < 0.7}, {-\[Pi]/10, 0.7 <= # < 0.75}, {\ [Pi]/10,True}} &@rr
x2 = \[Piecewise]{{0, # < 0.7}, {\[Pi]/10, 0.7 <= # < 0.75}, {-\[Pi]/10, True}} &@rr

And then I run a for-loop:
(Here, where I have used which function, my 3rd condition is when I get 0, and in that case, probabilites don't get switched, so it remains the previous "a". If you have a better way to that also, then that'll be great.)

list{}
For[i = 1 ; a = 1, i <= 100, i++;
If[a == 0, x = x1, x = x2];
a = Which[x == \[Pi]/10, 0, x == -\[Pi]/10, 1, True, a];
AppendTo[list, x]]
list

Your help will be really appreciated!!

P.S.: There might be some syntax errors, if you could point that out too, I'll be thankful to you (as I'm new to Mathematica).

$\endgroup$

4 Answers 4

2
$\begingroup$

This answer relies on the built-in function $\texttt{DiscreteMarkovProcess}$. In order to use it, the states of the world must be specified. A state is composed of two items: the current value and the most recent nonzero value. (Again I use {-1, 0, 1} for the values instead of {-Pi/10, 0, Pi/10}.)

There are four possible states

State: {current, most recent nonzero}
1       {-1,      -1}
2       { 0,      -1}
3       { 0,       1}
4       { 1,       1}

Note that third state cannot be reached directly from either of the first two states. Similarly, the second state cannot be reached from either of the last two states.

Let us construct the transition matrix and setup the Markov process object:

row = {.25, .7, 0., .05};
mat = {row, row, Reverse[row], Reverse[row]};

(* start in the first state *)
process = DiscreteMarkovProcess[{1, 0, 0, 0}, mat];

In order to convert the state numbers 1 through 4 into the current values, it is convenient to define a helper function:

fun = Function @@ {x, Piecewise[{{-1, x == 1}, {1, x == 4}}]}

We are now set to simulate from this process:

ran = fun /@ RandomFunction[process, {1, 10^6}]["ValueList"][[1]];

On my MacBook this takes about 0.33 seconds. (This is faster than my other answer, which see for additional post processing.)

$\endgroup$
4
$\begingroup$

Here's a way using NestList:

probabilities = {0.25, 0.05};
f[{result_, pList_}] := With[{x = RandomReal[]},
  Which[x < 0.7, {0, pList},
   (x > 0.7) && (x < 0.7 + pList[[1]]), {Pi/10, Reverse@pList},
  True, {-Pi/10, Reverse@pList}]];

Then run it, for example 10 times:

#[[1]] & /@ NestList[f, {0, probabilities}, 10]

(* {0, 0, \[Pi]/10, 0, -(\[Pi]/10), -(\[Pi]/10), -(\[Pi]/
10), 0, 0, \[Pi]/10, 0}*)

Edit: After reading your comment, I wrote a small update. Here's a new code.

probabilities = {0.25, 0.05};
f2[{result_, pList_}] := With[{x = RandomReal[]},
Which[x < 0.7, {0, pList},
(x > 0.7) && (x < 0.7 + pList[[1]]), {Pi/10, 
If[pList[[1]] == probabilities[[2]], pList, Reverse@pList]},
True, {-Pi/10, 
If[pList[[1]] == probabilities[[1]], pList, Reverse@pList]}]]
$\endgroup$
9
  • $\begingroup$ Thanks a lot, Whelp!! $\endgroup$
    – Rishabh
    May 31, 2018 at 11:32
  • 1
    $\begingroup$ @Rishabh If you're new to Mathematica, you might want to read up a little bit about the principles and basics of the language. In general, procedural programming is discouraged, and you can often find simpler solutions using functions. $\endgroup$
    – Whelp
    May 31, 2018 at 11:37
  • 1
    $\begingroup$ I suggest starting here: wolfram.com/language/elementary-introduction/2nd-ed $\endgroup$
    – Whelp
    May 31, 2018 at 12:20
  • 1
    $\begingroup$ And see also mathematica.stackexchange.com/questions/18/… $\endgroup$
    – Whelp
    May 31, 2018 at 12:22
  • 1
    $\begingroup$ @Rishabh The variable "result" is defined because the function is passed to NestList. The function "f" doesn't need "result", but having it as an argument allows it to be displayed in the list created by NestList. $\endgroup$
    – Whelp
    Jun 5, 2018 at 7:49
2
$\begingroup$

Here is different approach.

weight = {0.25, 0.7, 0.05};
list = Table[       
   Which[val = First@RandomSample[weight -> {π/10, 0, -π/10},1]; 
(val == -(π/10)) || (val == π/10), 
        weight = Reverse@weight; val, True, val], 10000];

Count[list, #] & /@ {0, Pi/10, -Pi/10}

{7061, 1467, 1472}

Edit: Please double check if this is what you want.

ClearAll["Global`*"]
weight = {0.25, 0.7, 0.05};
list = {};
sign = {};
list = Last@Table[

    Which[
     val = First@
       RandomSample[weight -> {π/10, 0, -(π/10)}, 1]; 
     If[Last@list != 0, AppendTo[sign, Last@list], True, Nothing]; 
     sign = SplitBy[sign, Sign]; Length@sign == 2, 
     weight = Reverse@weight; sign = Rest@sign; AppendTo[list, val]; 
     list, True, AppendTo[list, val]; list]
    , 100] // Quiet

$\left\{\frac{\pi }{10},\frac{\pi }{10},0,0,0,-\frac{\pi }{10},0,0,\frac{\pi }{10},0,0,0,-\frac{\pi }{10},0,0,\frac{\pi }{10}, \frac{\pi }{10},0,\frac{\pi }{10},0,0,0,0,0,\frac{\pi }{10},-\frac{\pi }{10},\frac{\pi }{10},0,\frac{\pi }{10},0,0,0,0,0,0,-\frac{\pi }{10},-\frac{\pi }{10},0,-\frac{\pi }{10},-\frac{\pi }{10},0,0,0, -\frac{\pi }{10},0,0,-\frac{\pi }{10},\frac{\pi }{10},0,0,0,0,\frac{\pi }{10},\frac{\pi }{10},0,\frac{\pi }{10},\frac{\pi }{10},0,\frac{\pi }{10}, \frac{\pi }{10},0,0,0,\frac{\pi }{10},0,-\frac{\pi }{10},\frac{\pi }{10},\frac{\pi }{10},-\frac{\pi }{10},-\frac{\pi }{10},0,0,0,0,0,\frac{\pi }{10},0,-\frac{\pi }{10},-\frac{\pi }{10},0,-\frac{\pi }{10}, -\frac{\pi }{10},0,0,\frac{\pi }{10},0,0,0,0,0,0,0,0,0,0,0,0,\frac{\pi }{10},0,-\frac{\pi }{10}\right\}$

$\endgroup$
3
  • $\begingroup$ Thanks for the answer. But what you answered, is that it flips the probability, whenever I get pi/10 or -pi/10. What I did ask was: suppose the probability of getting pi/10 is 0.25 and that of -pi/10 is 0.05. Now, For eg.: I got this sequence: 0, 0, 0, pi/10, 0, pi/10, pi/10, 0, 0, 0, -pi/10. Now the moment I get -pi/10. The probs. will be switched. i.e. the prob. of getting -pi/10 is more. Similarly when the next time I'll get pi/10, the prob. will get switched, and so on.. $\endgroup$
    – Rishabh
    May 31, 2018 at 20:13
  • $\begingroup$ Yes, I noticed your last comment after I posted my solution which does not answer your question. You should unselect your acceptance so that other people comes and try different solution. $\endgroup$ May 31, 2018 at 20:21
  • $\begingroup$ Not exactly but I'll try to work it out from here on my own. Anyway, thanks a lot, man! It's a great help. $\endgroup$
    – Rishabh
    Jun 1, 2018 at 8:38
1
$\begingroup$

If I have understood correctly, then I think the following code does what you want. (To keep things simple, I have used {-1, 0, 1} instead of {-Pi/10, 0, Pi/10}. One can easily modify the output as shown at the end.) I have compiled the function for speed.

cf = Compile[{{n, _Integer}},
  Module[{
    probs = {.25, .7, .05},
    state = -1,
    current
    },
  Table[
   current =
     RandomChoice[
      If[
        state == -1,
        probs,
        Reverse[probs]
        ] -> {-1, 0, 1}
      ];
    If[
     current == 0,
     current,
     state = current
     ],
    n]
   ]
  ]

Here is the usage (this takes about 0.4 seconds on my MacBook):

ran = cf[10^6];

We can examine the output:

KeySort[Counts[Partition[ran, 2, 1]]] -->

<|{-1, -1} -> 37211, {-1, 0} -> 104798, {-1, 1} -> 7324, 
  {0, -1} -> 104713, {0, 0} -> 491009,  {0, 1} -> 105168, 
  {1, -1} -> 7410,   {1, 0} -> 105082,  {1, 1} -> 37284|>

Making the substitution takes about 0.23 seconds:

ran1 = ran /. {-1 -> -Pi/10, 1 -> Pi/10};

Let me know if I have misunderstood.

$\endgroup$

Your Answer

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

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