Generating random numbers that keep a minimum distanceSimple algorithm to find cycles in edge listHow to Gather a list with some elements considered uniqueFinding Local Minima / Maxima in Noisy DataGarbage collection for memoized functions on subkernelsIssue with very large lists in MathematicaGenerating random symmetric matrixNeed Help Writing code to find Capparelli PartitionsDoes Mathematica have a functional programming idiom to loop over a list till a condition is met?Toroidal metric in a random geometric graphLooking up one additional array element increases runtime by three orders of magnitude
Storming Area 51
US Civil War story: man hanged from a bridge
Is there any word for "disobedience to God"?
Why does the U.S. tolerate foreign influence from Saudi Arabia and Israel on its domestic policies while not tolerating that from China or Russia?
Generating random numbers that keep a minimum distance
Graduate student with abysmal English writing skills, how to help
How can I effectively communicate to recruiters that a phone call is not possible?
Why were Er and Onan punished if they were under 20?
Using Newton's shell theorem to accelerate a spaceship
How would vampires avoid contracting diseases?
How to convert a file with several spaces into a tab-delimited file?
When casting Eldritch Blast with the Agonizing Blast eldritch invocation, what do I add to my damage roll?
Are there any sports for which the world's best player is female?
Cops: The Hidden OEIS Substring
Constructive proof of existence of free algebras for infinitary equational theories
C program to parse source code of another language
Why isn't pressure filtration popular compared to vacuum filtration?
Is "I do not want you to go nowhere" a case of "DOUBLE-NEGATIVES" as claimed by Grammarly?
Are unclear "take-it or leave-it" contracts interpreted in my favor?
How to md5 a list of filepaths contained in a file?
How were Martello towers supposed to work?
Why weren't bootable game disks ever common on the IBM PC?
How to tell someone I'd like to become friends without causing them to them think I'm romantically interested in them?
How can I get a player to accept that they should stop trying to pull stunts without thinking them through first?
Generating random numbers that keep a minimum distance
Simple algorithm to find cycles in edge listHow to Gather a list with some elements considered uniqueFinding Local Minima / Maxima in Noisy DataGarbage collection for memoized functions on subkernelsIssue with very large lists in MathematicaGenerating random symmetric matrixNeed Help Writing code to find Capparelli PartitionsDoes Mathematica have a functional programming idiom to loop over a list till a condition is met?Toroidal metric in a random geometric graphLooking up one additional array element increases runtime by three orders of magnitude
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
I want to create a list of n random integers from 1 to m, where all integers have to be at least a certain distance min apart (i.e. 3 integers out of Range[10], keeping a minimum distance of 2)
This is the module I created to fullfill that purpose:
StartGen[MinimalDistance_] :=
Module[nCells, min,test,i,j,r,
min = MinimalDistance;
(*Just create a Random Sample from Range[m] if min=0
is chosen*)
If[min == 0,
nCells = Sort[RandomSample[Range[m], n]];
Return[nCells]
,
nCells = Table[0, n];
nCells[[1]] = RandomInteger[m];
i = 1; j = 1;
(*Only execute if n integers out of m actually can
keep a minimum distance of min*)
If[m/(n (min + 1)) >= 1,
While[i <= n,
(*Generate random integers from Range[m] until one
fits with the already assigned Integers*)
r = RandomInteger[m];
test = True;
Do[If[Abs[nCells[[j]] - r] <= min,
test = False; Break[],
test = True], j, i
];
If[test == True, nCells[[i]] = r; i++, Null];
];
nCells = Sort[nCells];
Return[nCells];
,
Print["Impossible figuration for m n and min"];
];
];
];
Now the performance problem this creates is quite obvious: If the number of possible integers m and the minimum distance min are too big, as the While loop goes on fewer and fewer generated integers will fit the requirements and it gets harder and harder to hit those few integers through generating random numbers out of Range[m]. (For me this module couldn't produce lists for n=100,m=1000,min=8.)
I think the solution to this problem lies in reducing the number of Integers to choose from as the calculation go on, i.e. eliminate integers that dont fit the requirements anymore.
I tried implementing this with some variants of the DeleteCases[] function but I always ended up just creating more iterative calculations that would worsen the performance once again.
Is there an elegant way to do this?
list-manipulation performance-tuning
New contributor
$endgroup$
add a comment |
$begingroup$
I want to create a list of n random integers from 1 to m, where all integers have to be at least a certain distance min apart (i.e. 3 integers out of Range[10], keeping a minimum distance of 2)
This is the module I created to fullfill that purpose:
StartGen[MinimalDistance_] :=
Module[nCells, min,test,i,j,r,
min = MinimalDistance;
(*Just create a Random Sample from Range[m] if min=0
is chosen*)
If[min == 0,
nCells = Sort[RandomSample[Range[m], n]];
Return[nCells]
,
nCells = Table[0, n];
nCells[[1]] = RandomInteger[m];
i = 1; j = 1;
(*Only execute if n integers out of m actually can
keep a minimum distance of min*)
If[m/(n (min + 1)) >= 1,
While[i <= n,
(*Generate random integers from Range[m] until one
fits with the already assigned Integers*)
r = RandomInteger[m];
test = True;
Do[If[Abs[nCells[[j]] - r] <= min,
test = False; Break[],
test = True], j, i
];
If[test == True, nCells[[i]] = r; i++, Null];
];
nCells = Sort[nCells];
Return[nCells];
,
Print["Impossible figuration for m n and min"];
];
];
];
Now the performance problem this creates is quite obvious: If the number of possible integers m and the minimum distance min are too big, as the While loop goes on fewer and fewer generated integers will fit the requirements and it gets harder and harder to hit those few integers through generating random numbers out of Range[m]. (For me this module couldn't produce lists for n=100,m=1000,min=8.)
I think the solution to this problem lies in reducing the number of Integers to choose from as the calculation go on, i.e. eliminate integers that dont fit the requirements anymore.
I tried implementing this with some variants of the DeleteCases[] function but I always ended up just creating more iterative calculations that would worsen the performance once again.
Is there an elegant way to do this?
list-manipulation performance-tuning
New contributor
$endgroup$
$begingroup$
Your problem is thatLength[Range[8, 1000, 2 8 - 1]]
equals67
which is less than100
. So that's just not always possible with n=100, m=1000, and min=8.
$endgroup$
– Henrik Schumacher
8 hours ago
add a comment |
$begingroup$
I want to create a list of n random integers from 1 to m, where all integers have to be at least a certain distance min apart (i.e. 3 integers out of Range[10], keeping a minimum distance of 2)
This is the module I created to fullfill that purpose:
StartGen[MinimalDistance_] :=
Module[nCells, min,test,i,j,r,
min = MinimalDistance;
(*Just create a Random Sample from Range[m] if min=0
is chosen*)
If[min == 0,
nCells = Sort[RandomSample[Range[m], n]];
Return[nCells]
,
nCells = Table[0, n];
nCells[[1]] = RandomInteger[m];
i = 1; j = 1;
(*Only execute if n integers out of m actually can
keep a minimum distance of min*)
If[m/(n (min + 1)) >= 1,
While[i <= n,
(*Generate random integers from Range[m] until one
fits with the already assigned Integers*)
r = RandomInteger[m];
test = True;
Do[If[Abs[nCells[[j]] - r] <= min,
test = False; Break[],
test = True], j, i
];
If[test == True, nCells[[i]] = r; i++, Null];
];
nCells = Sort[nCells];
Return[nCells];
,
Print["Impossible figuration for m n and min"];
];
];
];
Now the performance problem this creates is quite obvious: If the number of possible integers m and the minimum distance min are too big, as the While loop goes on fewer and fewer generated integers will fit the requirements and it gets harder and harder to hit those few integers through generating random numbers out of Range[m]. (For me this module couldn't produce lists for n=100,m=1000,min=8.)
I think the solution to this problem lies in reducing the number of Integers to choose from as the calculation go on, i.e. eliminate integers that dont fit the requirements anymore.
I tried implementing this with some variants of the DeleteCases[] function but I always ended up just creating more iterative calculations that would worsen the performance once again.
Is there an elegant way to do this?
list-manipulation performance-tuning
New contributor
$endgroup$
I want to create a list of n random integers from 1 to m, where all integers have to be at least a certain distance min apart (i.e. 3 integers out of Range[10], keeping a minimum distance of 2)
This is the module I created to fullfill that purpose:
StartGen[MinimalDistance_] :=
Module[nCells, min,test,i,j,r,
min = MinimalDistance;
(*Just create a Random Sample from Range[m] if min=0
is chosen*)
If[min == 0,
nCells = Sort[RandomSample[Range[m], n]];
Return[nCells]
,
nCells = Table[0, n];
nCells[[1]] = RandomInteger[m];
i = 1; j = 1;
(*Only execute if n integers out of m actually can
keep a minimum distance of min*)
If[m/(n (min + 1)) >= 1,
While[i <= n,
(*Generate random integers from Range[m] until one
fits with the already assigned Integers*)
r = RandomInteger[m];
test = True;
Do[If[Abs[nCells[[j]] - r] <= min,
test = False; Break[],
test = True], j, i
];
If[test == True, nCells[[i]] = r; i++, Null];
];
nCells = Sort[nCells];
Return[nCells];
,
Print["Impossible figuration for m n and min"];
];
];
];
Now the performance problem this creates is quite obvious: If the number of possible integers m and the minimum distance min are too big, as the While loop goes on fewer and fewer generated integers will fit the requirements and it gets harder and harder to hit those few integers through generating random numbers out of Range[m]. (For me this module couldn't produce lists for n=100,m=1000,min=8.)
I think the solution to this problem lies in reducing the number of Integers to choose from as the calculation go on, i.e. eliminate integers that dont fit the requirements anymore.
I tried implementing this with some variants of the DeleteCases[] function but I always ended up just creating more iterative calculations that would worsen the performance once again.
Is there an elegant way to do this?
list-manipulation performance-tuning
list-manipulation performance-tuning
New contributor
New contributor
New contributor
asked 9 hours ago
Maxim HanselowskiMaxim Hanselowski
161 bronze badge
161 bronze badge
New contributor
New contributor
$begingroup$
Your problem is thatLength[Range[8, 1000, 2 8 - 1]]
equals67
which is less than100
. So that's just not always possible with n=100, m=1000, and min=8.
$endgroup$
– Henrik Schumacher
8 hours ago
add a comment |
$begingroup$
Your problem is thatLength[Range[8, 1000, 2 8 - 1]]
equals67
which is less than100
. So that's just not always possible with n=100, m=1000, and min=8.
$endgroup$
– Henrik Schumacher
8 hours ago
$begingroup$
Your problem is that
Length[Range[8, 1000, 2 8 - 1]]
equals 67
which is less than 100
. So that's just not always possible with n=100, m=1000, and min=8.$endgroup$
– Henrik Schumacher
8 hours ago
$begingroup$
Your problem is that
Length[Range[8, 1000, 2 8 - 1]]
equals 67
which is less than 100
. So that's just not always possible with n=100, m=1000, and min=8.$endgroup$
– Henrik Schumacher
8 hours ago
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
- Construct a random sample from
Range[m]
satisfying the minimum
distance requirements taking into account the fact that if $x_k$ is
selected at step $k$, the choices in step $k+1$ are restricted to
the range from $x_k + d$ to $m - (n-k)d$ to be able to get $n-k$
additional elements in remaining steps satisfying the minimum distance constraint. - Shuffle the list obtained in the first step
ClearAll[f]
f[m_, n_, d_] /; n d <= m := RandomSample @ Rest @
FoldList[RandomChoice[Range[# + Boole[#2 > 1] d, m - (n - #2) d]] &, 1, Range[n]]
Examples:
Table[f[10, 3, 2], 5]
8, 3, 6, 6, 10, 8, 8, 5, 10, 8, 10, 6, 10, 1, 4
Min[Differences@Sort@#] & /@ %
2, 2, 2, 2, 3
f[10, 4, 3]
f[10, 4, 3] (* impossible *)
f[1000, 100, 8]
848, 808, 189, 776, 680, 824, 472, 728, 352, 976, 736, 544, 504,
936, 904, 408, 720, 400, 816, 448, 856, 560, 279, 336, 312, 512, 888,
928, 424, 944, 584, 480, 238, 552, 920, 568, 528, 600, 952, 304, 536,
688, 632, 712, 992, 592, 616, 221, 896, 456, 864, 344, 792, 744, 392,
624, 320, 984, 576, 206, 648, 960, 368, 840, 872, 376, 328, 752, 832,
24, 288, 640, 416, 1000, 760, 696, 520, 488, 672, 464, 249, 800, 968,
768, 664, 432, 384, 784, 271, 912, 296, 656, 704, 496, 608, 230, 880,
360, 257, 440
Min @ Differences@ Sort @ %
8
res = f[10000000, 10000, 800]; // AbsoluteTiming // First
0.105936
Min @ Differences @ Sort @ res
800
Update: An alternative implementation using NestList
:
ClearAll[f2]
f2[m_, n_, d_] /; n d <= m := Module[k = 1, RandomSample @ Rest @
NestList[RandomChoice[Range[# + Boole[k++ > 1] d, m - (n - k) d]] &, 1, n]]
$endgroup$
add a comment |
$begingroup$
How about something like this - rather than picking random numbers until one satisfies the minimum distance criteria, pick the random number from a set that excludes disallowed values.
gen2[m_, n_, min_] := Module[nCells, set,
set = Range[m];
nCells = RandomSample[set, 1];
While[Length[nCells] < n && Length[set] > 0,
set = Complement[set,
Range[nCells[[-1]] - min + 1, nCells[[-1]] + min - 1]];
If[Length[set] < 1, Print["Couldn't pick ", n],
nCells = Join[nCells, RandomSample[set, 1]]];
];
nCells]
Table[gen2[10, 3, 2], 10] // Column
(*
4,7,10
8,3,6
2,6,9
5,8,3
7,10,1
3,10,6
3,7,10
3,9,6
1,10,5
9,2,6 *)
As noted by Henrik Schumacher in the comments, n=100, m=1000, min=8 doesn't work most of the time (you get an empty set before you pick 100 numbers):
gen2[1000, 100, 8]
(*
Couldn't pick 100
599, 14, 526, 475, 52, 448, 791, 576, 196, 711, 941, 35, 211, 483,
371, 401, 827, 354, 757, 547, 858, 86, 222, 336, 696, 913, 419, 386,
812, 363, 982, 974, 563, 966, 665, 279, 955, 494, 243, 675, 151, 994,
742, 5, 298, 438, 901, 316, 24, 627, 636, 873, 411, 684, 261, 516,
107, 586, 138, 768, 508, 290, 650, 253, 850, 116, 73, 464, 173, 163,
129, 94, 428, 346, 842, 609, 888, 306, 619, 181, 922, 44, 555, 931,
231, 539, 327, 731, 776, 456, 799, 64, 722, 271 *)
But 7 is fine:
test = gen2[1000, 100, 7]
(*
556, 966, 917, 863, 425, 155, 414, 504, 43, 82, 395, 196, 765, 701,
55, 330, 935, 626, 337, 843, 511, 885, 441, 834, 756, 117, 572, 285,
519, 17, 189, 658, 563, 817, 266, 727, 28, 854, 805, 747, 775, 210,
997, 546, 138, 303, 608, 295, 900, 145, 718, 355, 176, 666, 130, 946,
259, 102, 405, 795, 452, 649, 480, 591, 240, 363, 63, 641, 95, 694,
493, 221, 536, 978, 633, 784, 739, 387, 871, 827, 675, 465, 10, 954,
580, 599, 686, 878, 36, 1, 926, 373, 320, 529, 348, 248, 708, 893,
311, 273 *)
Test the minimum distance between numbers:
stest = Sort[test];
Min[Table[stest[[i]] - stest[[i - 1]], i, 2, Length[test]]]
(* 7 *)
```
$endgroup$
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "387"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Maxim Hanselowski is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f201889%2fgenerating-random-numbers-that-keep-a-minimum-distance%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
- Construct a random sample from
Range[m]
satisfying the minimum
distance requirements taking into account the fact that if $x_k$ is
selected at step $k$, the choices in step $k+1$ are restricted to
the range from $x_k + d$ to $m - (n-k)d$ to be able to get $n-k$
additional elements in remaining steps satisfying the minimum distance constraint. - Shuffle the list obtained in the first step
ClearAll[f]
f[m_, n_, d_] /; n d <= m := RandomSample @ Rest @
FoldList[RandomChoice[Range[# + Boole[#2 > 1] d, m - (n - #2) d]] &, 1, Range[n]]
Examples:
Table[f[10, 3, 2], 5]
8, 3, 6, 6, 10, 8, 8, 5, 10, 8, 10, 6, 10, 1, 4
Min[Differences@Sort@#] & /@ %
2, 2, 2, 2, 3
f[10, 4, 3]
f[10, 4, 3] (* impossible *)
f[1000, 100, 8]
848, 808, 189, 776, 680, 824, 472, 728, 352, 976, 736, 544, 504,
936, 904, 408, 720, 400, 816, 448, 856, 560, 279, 336, 312, 512, 888,
928, 424, 944, 584, 480, 238, 552, 920, 568, 528, 600, 952, 304, 536,
688, 632, 712, 992, 592, 616, 221, 896, 456, 864, 344, 792, 744, 392,
624, 320, 984, 576, 206, 648, 960, 368, 840, 872, 376, 328, 752, 832,
24, 288, 640, 416, 1000, 760, 696, 520, 488, 672, 464, 249, 800, 968,
768, 664, 432, 384, 784, 271, 912, 296, 656, 704, 496, 608, 230, 880,
360, 257, 440
Min @ Differences@ Sort @ %
8
res = f[10000000, 10000, 800]; // AbsoluteTiming // First
0.105936
Min @ Differences @ Sort @ res
800
Update: An alternative implementation using NestList
:
ClearAll[f2]
f2[m_, n_, d_] /; n d <= m := Module[k = 1, RandomSample @ Rest @
NestList[RandomChoice[Range[# + Boole[k++ > 1] d, m - (n - k) d]] &, 1, n]]
$endgroup$
add a comment |
$begingroup$
- Construct a random sample from
Range[m]
satisfying the minimum
distance requirements taking into account the fact that if $x_k$ is
selected at step $k$, the choices in step $k+1$ are restricted to
the range from $x_k + d$ to $m - (n-k)d$ to be able to get $n-k$
additional elements in remaining steps satisfying the minimum distance constraint. - Shuffle the list obtained in the first step
ClearAll[f]
f[m_, n_, d_] /; n d <= m := RandomSample @ Rest @
FoldList[RandomChoice[Range[# + Boole[#2 > 1] d, m - (n - #2) d]] &, 1, Range[n]]
Examples:
Table[f[10, 3, 2], 5]
8, 3, 6, 6, 10, 8, 8, 5, 10, 8, 10, 6, 10, 1, 4
Min[Differences@Sort@#] & /@ %
2, 2, 2, 2, 3
f[10, 4, 3]
f[10, 4, 3] (* impossible *)
f[1000, 100, 8]
848, 808, 189, 776, 680, 824, 472, 728, 352, 976, 736, 544, 504,
936, 904, 408, 720, 400, 816, 448, 856, 560, 279, 336, 312, 512, 888,
928, 424, 944, 584, 480, 238, 552, 920, 568, 528, 600, 952, 304, 536,
688, 632, 712, 992, 592, 616, 221, 896, 456, 864, 344, 792, 744, 392,
624, 320, 984, 576, 206, 648, 960, 368, 840, 872, 376, 328, 752, 832,
24, 288, 640, 416, 1000, 760, 696, 520, 488, 672, 464, 249, 800, 968,
768, 664, 432, 384, 784, 271, 912, 296, 656, 704, 496, 608, 230, 880,
360, 257, 440
Min @ Differences@ Sort @ %
8
res = f[10000000, 10000, 800]; // AbsoluteTiming // First
0.105936
Min @ Differences @ Sort @ res
800
Update: An alternative implementation using NestList
:
ClearAll[f2]
f2[m_, n_, d_] /; n d <= m := Module[k = 1, RandomSample @ Rest @
NestList[RandomChoice[Range[# + Boole[k++ > 1] d, m - (n - k) d]] &, 1, n]]
$endgroup$
add a comment |
$begingroup$
- Construct a random sample from
Range[m]
satisfying the minimum
distance requirements taking into account the fact that if $x_k$ is
selected at step $k$, the choices in step $k+1$ are restricted to
the range from $x_k + d$ to $m - (n-k)d$ to be able to get $n-k$
additional elements in remaining steps satisfying the minimum distance constraint. - Shuffle the list obtained in the first step
ClearAll[f]
f[m_, n_, d_] /; n d <= m := RandomSample @ Rest @
FoldList[RandomChoice[Range[# + Boole[#2 > 1] d, m - (n - #2) d]] &, 1, Range[n]]
Examples:
Table[f[10, 3, 2], 5]
8, 3, 6, 6, 10, 8, 8, 5, 10, 8, 10, 6, 10, 1, 4
Min[Differences@Sort@#] & /@ %
2, 2, 2, 2, 3
f[10, 4, 3]
f[10, 4, 3] (* impossible *)
f[1000, 100, 8]
848, 808, 189, 776, 680, 824, 472, 728, 352, 976, 736, 544, 504,
936, 904, 408, 720, 400, 816, 448, 856, 560, 279, 336, 312, 512, 888,
928, 424, 944, 584, 480, 238, 552, 920, 568, 528, 600, 952, 304, 536,
688, 632, 712, 992, 592, 616, 221, 896, 456, 864, 344, 792, 744, 392,
624, 320, 984, 576, 206, 648, 960, 368, 840, 872, 376, 328, 752, 832,
24, 288, 640, 416, 1000, 760, 696, 520, 488, 672, 464, 249, 800, 968,
768, 664, 432, 384, 784, 271, 912, 296, 656, 704, 496, 608, 230, 880,
360, 257, 440
Min @ Differences@ Sort @ %
8
res = f[10000000, 10000, 800]; // AbsoluteTiming // First
0.105936
Min @ Differences @ Sort @ res
800
Update: An alternative implementation using NestList
:
ClearAll[f2]
f2[m_, n_, d_] /; n d <= m := Module[k = 1, RandomSample @ Rest @
NestList[RandomChoice[Range[# + Boole[k++ > 1] d, m - (n - k) d]] &, 1, n]]
$endgroup$
- Construct a random sample from
Range[m]
satisfying the minimum
distance requirements taking into account the fact that if $x_k$ is
selected at step $k$, the choices in step $k+1$ are restricted to
the range from $x_k + d$ to $m - (n-k)d$ to be able to get $n-k$
additional elements in remaining steps satisfying the minimum distance constraint. - Shuffle the list obtained in the first step
ClearAll[f]
f[m_, n_, d_] /; n d <= m := RandomSample @ Rest @
FoldList[RandomChoice[Range[# + Boole[#2 > 1] d, m - (n - #2) d]] &, 1, Range[n]]
Examples:
Table[f[10, 3, 2], 5]
8, 3, 6, 6, 10, 8, 8, 5, 10, 8, 10, 6, 10, 1, 4
Min[Differences@Sort@#] & /@ %
2, 2, 2, 2, 3
f[10, 4, 3]
f[10, 4, 3] (* impossible *)
f[1000, 100, 8]
848, 808, 189, 776, 680, 824, 472, 728, 352, 976, 736, 544, 504,
936, 904, 408, 720, 400, 816, 448, 856, 560, 279, 336, 312, 512, 888,
928, 424, 944, 584, 480, 238, 552, 920, 568, 528, 600, 952, 304, 536,
688, 632, 712, 992, 592, 616, 221, 896, 456, 864, 344, 792, 744, 392,
624, 320, 984, 576, 206, 648, 960, 368, 840, 872, 376, 328, 752, 832,
24, 288, 640, 416, 1000, 760, 696, 520, 488, 672, 464, 249, 800, 968,
768, 664, 432, 384, 784, 271, 912, 296, 656, 704, 496, 608, 230, 880,
360, 257, 440
Min @ Differences@ Sort @ %
8
res = f[10000000, 10000, 800]; // AbsoluteTiming // First
0.105936
Min @ Differences @ Sort @ res
800
Update: An alternative implementation using NestList
:
ClearAll[f2]
f2[m_, n_, d_] /; n d <= m := Module[k = 1, RandomSample @ Rest @
NestList[RandomChoice[Range[# + Boole[k++ > 1] d, m - (n - k) d]] &, 1, n]]
edited 3 hours ago
answered 7 hours ago
kglrkglr
204k10 gold badges233 silver badges463 bronze badges
204k10 gold badges233 silver badges463 bronze badges
add a comment |
add a comment |
$begingroup$
How about something like this - rather than picking random numbers until one satisfies the minimum distance criteria, pick the random number from a set that excludes disallowed values.
gen2[m_, n_, min_] := Module[nCells, set,
set = Range[m];
nCells = RandomSample[set, 1];
While[Length[nCells] < n && Length[set] > 0,
set = Complement[set,
Range[nCells[[-1]] - min + 1, nCells[[-1]] + min - 1]];
If[Length[set] < 1, Print["Couldn't pick ", n],
nCells = Join[nCells, RandomSample[set, 1]]];
];
nCells]
Table[gen2[10, 3, 2], 10] // Column
(*
4,7,10
8,3,6
2,6,9
5,8,3
7,10,1
3,10,6
3,7,10
3,9,6
1,10,5
9,2,6 *)
As noted by Henrik Schumacher in the comments, n=100, m=1000, min=8 doesn't work most of the time (you get an empty set before you pick 100 numbers):
gen2[1000, 100, 8]
(*
Couldn't pick 100
599, 14, 526, 475, 52, 448, 791, 576, 196, 711, 941, 35, 211, 483,
371, 401, 827, 354, 757, 547, 858, 86, 222, 336, 696, 913, 419, 386,
812, 363, 982, 974, 563, 966, 665, 279, 955, 494, 243, 675, 151, 994,
742, 5, 298, 438, 901, 316, 24, 627, 636, 873, 411, 684, 261, 516,
107, 586, 138, 768, 508, 290, 650, 253, 850, 116, 73, 464, 173, 163,
129, 94, 428, 346, 842, 609, 888, 306, 619, 181, 922, 44, 555, 931,
231, 539, 327, 731, 776, 456, 799, 64, 722, 271 *)
But 7 is fine:
test = gen2[1000, 100, 7]
(*
556, 966, 917, 863, 425, 155, 414, 504, 43, 82, 395, 196, 765, 701,
55, 330, 935, 626, 337, 843, 511, 885, 441, 834, 756, 117, 572, 285,
519, 17, 189, 658, 563, 817, 266, 727, 28, 854, 805, 747, 775, 210,
997, 546, 138, 303, 608, 295, 900, 145, 718, 355, 176, 666, 130, 946,
259, 102, 405, 795, 452, 649, 480, 591, 240, 363, 63, 641, 95, 694,
493, 221, 536, 978, 633, 784, 739, 387, 871, 827, 675, 465, 10, 954,
580, 599, 686, 878, 36, 1, 926, 373, 320, 529, 348, 248, 708, 893,
311, 273 *)
Test the minimum distance between numbers:
stest = Sort[test];
Min[Table[stest[[i]] - stest[[i - 1]], i, 2, Length[test]]]
(* 7 *)
```
$endgroup$
add a comment |
$begingroup$
How about something like this - rather than picking random numbers until one satisfies the minimum distance criteria, pick the random number from a set that excludes disallowed values.
gen2[m_, n_, min_] := Module[nCells, set,
set = Range[m];
nCells = RandomSample[set, 1];
While[Length[nCells] < n && Length[set] > 0,
set = Complement[set,
Range[nCells[[-1]] - min + 1, nCells[[-1]] + min - 1]];
If[Length[set] < 1, Print["Couldn't pick ", n],
nCells = Join[nCells, RandomSample[set, 1]]];
];
nCells]
Table[gen2[10, 3, 2], 10] // Column
(*
4,7,10
8,3,6
2,6,9
5,8,3
7,10,1
3,10,6
3,7,10
3,9,6
1,10,5
9,2,6 *)
As noted by Henrik Schumacher in the comments, n=100, m=1000, min=8 doesn't work most of the time (you get an empty set before you pick 100 numbers):
gen2[1000, 100, 8]
(*
Couldn't pick 100
599, 14, 526, 475, 52, 448, 791, 576, 196, 711, 941, 35, 211, 483,
371, 401, 827, 354, 757, 547, 858, 86, 222, 336, 696, 913, 419, 386,
812, 363, 982, 974, 563, 966, 665, 279, 955, 494, 243, 675, 151, 994,
742, 5, 298, 438, 901, 316, 24, 627, 636, 873, 411, 684, 261, 516,
107, 586, 138, 768, 508, 290, 650, 253, 850, 116, 73, 464, 173, 163,
129, 94, 428, 346, 842, 609, 888, 306, 619, 181, 922, 44, 555, 931,
231, 539, 327, 731, 776, 456, 799, 64, 722, 271 *)
But 7 is fine:
test = gen2[1000, 100, 7]
(*
556, 966, 917, 863, 425, 155, 414, 504, 43, 82, 395, 196, 765, 701,
55, 330, 935, 626, 337, 843, 511, 885, 441, 834, 756, 117, 572, 285,
519, 17, 189, 658, 563, 817, 266, 727, 28, 854, 805, 747, 775, 210,
997, 546, 138, 303, 608, 295, 900, 145, 718, 355, 176, 666, 130, 946,
259, 102, 405, 795, 452, 649, 480, 591, 240, 363, 63, 641, 95, 694,
493, 221, 536, 978, 633, 784, 739, 387, 871, 827, 675, 465, 10, 954,
580, 599, 686, 878, 36, 1, 926, 373, 320, 529, 348, 248, 708, 893,
311, 273 *)
Test the minimum distance between numbers:
stest = Sort[test];
Min[Table[stest[[i]] - stest[[i - 1]], i, 2, Length[test]]]
(* 7 *)
```
$endgroup$
add a comment |
$begingroup$
How about something like this - rather than picking random numbers until one satisfies the minimum distance criteria, pick the random number from a set that excludes disallowed values.
gen2[m_, n_, min_] := Module[nCells, set,
set = Range[m];
nCells = RandomSample[set, 1];
While[Length[nCells] < n && Length[set] > 0,
set = Complement[set,
Range[nCells[[-1]] - min + 1, nCells[[-1]] + min - 1]];
If[Length[set] < 1, Print["Couldn't pick ", n],
nCells = Join[nCells, RandomSample[set, 1]]];
];
nCells]
Table[gen2[10, 3, 2], 10] // Column
(*
4,7,10
8,3,6
2,6,9
5,8,3
7,10,1
3,10,6
3,7,10
3,9,6
1,10,5
9,2,6 *)
As noted by Henrik Schumacher in the comments, n=100, m=1000, min=8 doesn't work most of the time (you get an empty set before you pick 100 numbers):
gen2[1000, 100, 8]
(*
Couldn't pick 100
599, 14, 526, 475, 52, 448, 791, 576, 196, 711, 941, 35, 211, 483,
371, 401, 827, 354, 757, 547, 858, 86, 222, 336, 696, 913, 419, 386,
812, 363, 982, 974, 563, 966, 665, 279, 955, 494, 243, 675, 151, 994,
742, 5, 298, 438, 901, 316, 24, 627, 636, 873, 411, 684, 261, 516,
107, 586, 138, 768, 508, 290, 650, 253, 850, 116, 73, 464, 173, 163,
129, 94, 428, 346, 842, 609, 888, 306, 619, 181, 922, 44, 555, 931,
231, 539, 327, 731, 776, 456, 799, 64, 722, 271 *)
But 7 is fine:
test = gen2[1000, 100, 7]
(*
556, 966, 917, 863, 425, 155, 414, 504, 43, 82, 395, 196, 765, 701,
55, 330, 935, 626, 337, 843, 511, 885, 441, 834, 756, 117, 572, 285,
519, 17, 189, 658, 563, 817, 266, 727, 28, 854, 805, 747, 775, 210,
997, 546, 138, 303, 608, 295, 900, 145, 718, 355, 176, 666, 130, 946,
259, 102, 405, 795, 452, 649, 480, 591, 240, 363, 63, 641, 95, 694,
493, 221, 536, 978, 633, 784, 739, 387, 871, 827, 675, 465, 10, 954,
580, 599, 686, 878, 36, 1, 926, 373, 320, 529, 348, 248, 708, 893,
311, 273 *)
Test the minimum distance between numbers:
stest = Sort[test];
Min[Table[stest[[i]] - stest[[i - 1]], i, 2, Length[test]]]
(* 7 *)
```
$endgroup$
How about something like this - rather than picking random numbers until one satisfies the minimum distance criteria, pick the random number from a set that excludes disallowed values.
gen2[m_, n_, min_] := Module[nCells, set,
set = Range[m];
nCells = RandomSample[set, 1];
While[Length[nCells] < n && Length[set] > 0,
set = Complement[set,
Range[nCells[[-1]] - min + 1, nCells[[-1]] + min - 1]];
If[Length[set] < 1, Print["Couldn't pick ", n],
nCells = Join[nCells, RandomSample[set, 1]]];
];
nCells]
Table[gen2[10, 3, 2], 10] // Column
(*
4,7,10
8,3,6
2,6,9
5,8,3
7,10,1
3,10,6
3,7,10
3,9,6
1,10,5
9,2,6 *)
As noted by Henrik Schumacher in the comments, n=100, m=1000, min=8 doesn't work most of the time (you get an empty set before you pick 100 numbers):
gen2[1000, 100, 8]
(*
Couldn't pick 100
599, 14, 526, 475, 52, 448, 791, 576, 196, 711, 941, 35, 211, 483,
371, 401, 827, 354, 757, 547, 858, 86, 222, 336, 696, 913, 419, 386,
812, 363, 982, 974, 563, 966, 665, 279, 955, 494, 243, 675, 151, 994,
742, 5, 298, 438, 901, 316, 24, 627, 636, 873, 411, 684, 261, 516,
107, 586, 138, 768, 508, 290, 650, 253, 850, 116, 73, 464, 173, 163,
129, 94, 428, 346, 842, 609, 888, 306, 619, 181, 922, 44, 555, 931,
231, 539, 327, 731, 776, 456, 799, 64, 722, 271 *)
But 7 is fine:
test = gen2[1000, 100, 7]
(*
556, 966, 917, 863, 425, 155, 414, 504, 43, 82, 395, 196, 765, 701,
55, 330, 935, 626, 337, 843, 511, 885, 441, 834, 756, 117, 572, 285,
519, 17, 189, 658, 563, 817, 266, 727, 28, 854, 805, 747, 775, 210,
997, 546, 138, 303, 608, 295, 900, 145, 718, 355, 176, 666, 130, 946,
259, 102, 405, 795, 452, 649, 480, 591, 240, 363, 63, 641, 95, 694,
493, 221, 536, 978, 633, 784, 739, 387, 871, 827, 675, 465, 10, 954,
580, 599, 686, 878, 36, 1, 926, 373, 320, 529, 348, 248, 708, 893,
311, 273 *)
Test the minimum distance between numbers:
stest = Sort[test];
Min[Table[stest[[i]] - stest[[i - 1]], i, 2, Length[test]]]
(* 7 *)
```
answered 7 hours ago
MelaGoMelaGo
2,0361 gold badge1 silver badge7 bronze badges
2,0361 gold badge1 silver badge7 bronze badges
add a comment |
add a comment |
Maxim Hanselowski is a new contributor. Be nice, and check out our Code of Conduct.
Maxim Hanselowski is a new contributor. Be nice, and check out our Code of Conduct.
Maxim Hanselowski is a new contributor. Be nice, and check out our Code of Conduct.
Maxim Hanselowski is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Mathematica Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f201889%2fgenerating-random-numbers-that-keep-a-minimum-distance%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
Your problem is that
Length[Range[8, 1000, 2 8 - 1]]
equals67
which is less than100
. So that's just not always possible with n=100, m=1000, and min=8.$endgroup$
– Henrik Schumacher
8 hours ago