2
$\begingroup$

In the past I have pretty much stuck to expression building when using Mathematica, but recently I have been writing a procedure to populate an array, which I guess are called "lists" in Mathematica. The list is generated from two random sequences, one of which is weighted more heavily than the other. Because of an "offset" parameter which itself is randomized, I could only think of a "Do" method of making my output as follows:

min = 0;
max = 10000;
k := 0.5;
RandomValue := RandomReal[{min, max + max *k}];
randomA = RandomReal[{min, max}, 1000];
randomB = RandomReal[{min, max}, 1000];

Clear[effect];

effect = Range[1000];

Module[{offset},
  Do[
   offset = RandomInteger[{1, 10}];
   If[ xEffect - offset < 1 ,
    effect[[ xEffect ]] = RandomValue,
    effect[[ xEffect ]] = randomA[[ xEffect - offset ]] + k * randomB [[ xEffect - offset ]] ];
   , { xEffect, 1, 1000 }]
  ];

Take[effect, 20]

(* Out: {9118.77, 12599.2, 3892.83, 5083.62, 12517.1, 9102.53, \
5083.62, 5083.62, 5083.62, 9801.6, 8169.35, 9801.6, 3809.98, 8169.35, \
9801.6, 8670.78, 9443.65, 9026.42, 3013.94, 3013.94} *)

The output looks plausible (except some bug is causing sequential values in the output array to be duplicated sometimes) so my code seems to be kind of correct. My questions are: (1) Is there a better way to write this as functional, rather than procedural code? (2) I clear and initialize my "effect" global before running the module to populate it, do I need to do this? Another bizarre issue I don't understand, is that sometimes when I run it, I get output like this:

Take[effect, 20]

{9102.53, 1.5 List, 13497.6, 7457.65, 12517.1, 8869.53, 5603.8, 7457.65, \
5603.8, 8869.53, 11289.6, 3809.98, 12517.1, 7427.27, 3809.98, \
9211.48, 8670.78, 3013.94, 7229.46, 3809.98}

Why would one of the elements be "1.5 List" ?

$\endgroup$
6
  • $\begingroup$ The reason you sometimes get List, Mr. Montoya, is that xEffect can be 0, and the 0th element of an expression is its Head: {}[[0]] === List. $\endgroup$ Commented Jun 17, 2015 at 23:15
  • $\begingroup$ @2012rcampion How can xEffect be zero? The Do statement ends with { xEffect, 1, 1000 }. Doesn't that mean it goes from 1 to 1000? $\endgroup$ Commented Jun 17, 2015 at 23:17
  • $\begingroup$ Sorry, xEffect - offset can be zero $\endgroup$ Commented Jun 17, 2015 at 23:31
  • $\begingroup$ @2012rcampion Yes, but if xEffect - offset < 1 then shouldn't the If-clause prevent a [[0]] reference? The idea of the If was to make the effect[xEffect]] value be a random value if the offset adjusted value is under 1. Did I use the If-statement incorrectly? $\endgroup$ Commented Jun 18, 2015 at 0:13
  • $\begingroup$ each pick has a 1 in 10 chance of duplicating the prior one (or nearly so..) $\endgroup$
    – george2079
    Commented Jun 18, 2015 at 2:41

2 Answers 2

5
$\begingroup$

This should be much faster than using a loop or mapping:

rng = 100000;
min = 0;
max = 10000;
k := 0.5;

 offsets = RandomInteger[{1, 10}, rng];
 randomA = RandomReal[{min, max}, rng];
 randomB = RandomReal[{min, max}, rng];
 effect = xEffect = Range@rng;

 us = UnitStep[xEffect - offsets - 1];
 nr = Pick[Range@Length@effect, us, 0];
 nr2 = Pick[Range@Length@effect, us, 1];

 effect[[nr]] = RandomReal[{min, max + max*k}, Length@nr];
 effect[[nr2]] = randomA[[nr2 - offsets[[nr2]]]] + k*randomB[[nr2 - offsets[[nr2]]]];

N.b.: rng is just the range you want, e.g., 1000 in your example...

As for seeing duplicates (I interpret this as two or more of same value in sequence) - this will happen - all it takes is for the offsets of a sequential pair of elements to differ by +1, leading to the same value, and with only 10 possible offsets... the probability is left as an exercise...

$\endgroup$
2
  • $\begingroup$ That makes sense, the duplicates are a side effect of the way the number is being composed. What does the final bracket in your code connect to? It seems to be extra. $\endgroup$ Commented Jun 17, 2015 at 22:57
  • $\begingroup$ @TylerDurden: Oops - yes, that was left over close of a Timing I'd used to benchmark speed - fixed. $\endgroup$
    – ciao
    Commented Jun 18, 2015 at 0:52
3
$\begingroup$

Like this:

computeEffect[xEffect_] := With[{offset = RandomInteger[{1, 10}]},
  If[xEffect - offset < 1,
   RandomValue,
   randomA[[xEffect - offset]] + k randomB[[xEffect - offset]]
   ]
  ]

effect = computeEffect /@ Range[1000];

Or

effectLength = 1000;
diffs = Range[effectLength] - RandomInteger[{1, 10}, effectLength];

computeEffect2[diff_] := If[
  diff < 1,
  RandomValue,
  randomA[[diff]] + k randomB[[diff]]
  ]

computeEffect2 /@ diffs

Regarding (2): You don't need to clear the variable before you set it to something else but you do have to initialize it if you want to do it your way. Otherwise it will complain about you trying to access parts of the expression that don't exist. For example list[[5]] = 1 doesn't work if, if list doesn't already have a part 5.

Regarding your last question I could not reproduce the issue. Try to restart the kernel or if it doesn't work please describe how often this happens.

$\endgroup$
2
  • $\begingroup$ When I do this I get the same problem: duplicate values in the output. $\endgroup$ Commented Jun 17, 2015 at 22:25
  • $\begingroup$ @TylerDurden I supposed you were asking only the enumerated questions. You should probably give the duplication issue a number or something so people understand it's a question. $\endgroup$
    – C. E.
    Commented Jun 17, 2015 at 22: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.