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
How to md5 a list of filepaths contained in a file?
What is the job of the acoustic cavities inside the main combustion chamber?
Received a dinner invitation through my employer's email, is it ok to attend?
Integer Lists of Noah
Has anyone in space seen or photographed a simple laser pointer from Earth?
Print the last, middle and first character of your code
Cops: The Hidden OEIS Substring
Credit score and financing new car
Referring to different instances of the same character in time travel
What is a solution?
Can fluent English speakers distinguish “steel”, “still” and “steal”?
Changing trains in the Netherlands
Why did Harry Potter get a bedroom?
Constructive proof of existence of free algebras for infinitary equational theories
Machine learning and operations research projects
Is "I do not want you to go nowhere" a case of "DOUBLE-NEGATIVES" as claimed by Grammarly?
How to loop for 3 times in bash script when docker push fails?
During copyediting, journal disagrees about spelling of paper's main topic
If your plane is out-of-control, why does military training instruct releasing the joystick to neutralize controls?
How do you glue a text to a point?
Why can a destructor change the state of a constant object?
US Civil War story: man hanged from a bridge
Does Lufthansa weigh your carry on luggage?
definition of "percentile"
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