RW
Raymond West
Sun, Oct 16, 2022 5:20 PM
I generate a block of 'strands', each strand has a random factor applied
to its width. How can I create a duplicate of it such that the ends are
fixed, but the points in between are random. The example code the
strands do not change for each iteration of block, which can lead to
repeating pattern when joined up. If I do not use a seed, then the ends
are different for each iteration, and will not align.
if you run one block, with len= 80, then that will show more or less
what I am trying to explain it should look like, apart from the
endpoints of the blocks in the tessellated version.
module strand(ysep,see){ // rand at 20
ty=ysep+10+rands(-2,2,1,see)[0];
by=ysep+rands(-2,2,1,see)[0];
b=[0,ty];
c=[for (j=[1:1:(len/2)-1]) [j*20,ysep+10+rands(-2,2,1)[0] ]];
d= [(len/2)*20,ty];
e=[(len/2)*20,by];
f=[for
(j=[(len/2)+2:1:len])[(len-j+1)*20,ysep++rands(-2,2,1)[0]]];
g=[0,by] ;
p=concat([b],c,[d],[e],f,[g]);
polygon(p);
}
module block(){
for (j=[0:1:ns-1])
strand(sepj,j7);
}
ns=100; // number of strands
sep=18; // strand separation
len= 20; // length of strand
block();
translate([200,0,0])block();
translate([400,0,0])block();
translate([600,0,0])block();
I generate a block of 'strands', each strand has a random factor applied
to its width. How can I create a duplicate of it such that the ends are
fixed, but the points in between are random. The example code the
strands do not change for each iteration of block, which can lead to
repeating pattern when joined up. If I do not use a seed, then the ends
are different for each iteration, and will not align.
if you run one block, with len= 80, then that will show more or less
what I am trying to explain it should look like, apart from the
endpoints of the blocks in the tessellated version.
module strand(ysep,see){ // rand at 20
ty=ysep+10+rands(-2,2,1,see)[0];
by=ysep+rands(-2,2,1,see)[0];
b=[0,ty];
c=[for (j=[1:1:(len/2)-1]) [j*20,ysep+10+rands(-2,2,1)[0] ]];
d= [(len/2)*20,ty];
e=[(len/2)*20,by];
f=[for
(j=[(len/2)+2:1:len])[(len-j+1)*20,ysep++rands(-2,2,1)[0]]];
g=[0,by] ;
p=concat([b],c,[d],[e],f,[g]);
polygon(p);
}
module block(){
for (j=[0:1:ns-1])
strand(sep*j,j*7);
}
ns=100; // number of strands
sep=18; // strand separation
len= 20; // length of strand
block();
translate([200,0,0])block();
translate([400,0,0])block();
translate([600,0,0])block();
JB
Jordan Brown
Mon, Oct 17, 2022 1:39 PM
I am not completely following what you are trying to do, but I think
what you are saying is that you want a random wavy line, and then you
want to attach a random wavy line onto the end of it, and another, and
so on, and you want the ends of those lines to connect.
The best answer would seem to be to generate the entire wavy line in one
operation, rather than in segments.
Failing that, it would depend on exactly how you're generating your
waviness. So far, your problem is that your random end point isn't the
same as the random start point on the next one, right?
So, perhaps to point out the obvious, your start point for the next
segment can't be random.
One answer would be to do what model railroaders do when they want to
have individual people build modules for a layout, and want the modules
to interconnect https://www.nmra.org/introduction-layout-modules:
have the interconnection points not be random at all. Assuming that
your waviness is around a zero point, you could have all segments start
and end at the zero point. But if you do an vertical array of these
strands, I suspect that would be a visible pattern.
Another approach would be to plan out the whole line in advance, so that
you know where the start/end points are before you start building
anything else. But mostly that seems equivalent to generating the
entire line in one pass.
I am not completely following what you are trying to do, but I think
what you are saying is that you want a random wavy line, and then you
want to attach a random wavy line onto the end of it, and another, and
so on, and you want the ends of those lines to connect.
The best answer would seem to be to generate the entire wavy line in one
operation, rather than in segments.
Failing that, it would depend on exactly how you're generating your
waviness. So far, your problem is that your random end point isn't the
same as the random start point on the next one, right?
So, perhaps to point out the obvious, your start point for the next
segment can't be random.
One answer would be to do what model railroaders do when they want to
have individual people build modules for a layout, and want the modules
to interconnect <https://www.nmra.org/introduction-layout-modules>:
have the interconnection points not be random at all. Assuming that
your waviness is around a zero point, you could have all segments start
and end at the zero point. But if you do an vertical array of these
strands, I suspect that would be a visible pattern.
Another approach would be to plan out the whole line in advance, so that
you know where the start/end points are before you start building
anything else. But mostly that seems equivalent to generating the
entire line in one pass.
BL
Bryan Lee
Mon, Oct 17, 2022 5:09 PM
So if I'm understanding this correctly, you want the endpoints of strand_1
to be the start points of strand_2?
I'm pretty sure that in order to do this in OpenSCAD you will need to
generate those end points outside of your loop.
One way to do this is to generate an array of starting point rands in
"block()" or "main" and pass "start_point[j]" and "start_point[j+1]" into
strand() also. These would be used by strand as it's start and end points.
You could also generate a list of rands in "main"
SEED=42284;
start_point_array=rands(-2,2,ns+1,SEED);
and just have block() also pass j into strand(),
so then each itteration of strand() uses that j to lookup it's own start
and end points.
Thus Raymond West hast written on Sun, Oct 16, 2022 at 06:20:26PM +0100, and, according to prophecy, it shall come to pass that:
I generate a block of 'strands', each strand has a random factor applied to
its width. How can I create a duplicate of it such that the ends are fixed,
but the points in between are random. The example code the strands do not
change for each iteration of block, which can lead to repeating pattern when
joined up. If I do not use a seed, then the ends are different for each
iteration, and will not align.
if you run one block, with len= 80, then that will show more or less what I
am trying to explain it should look like, apart from the endpoints of the
blocks in the tessellated version.
module strand(ysep,see){ // rand at 20
ty=ysep+10+rands(-2,2,1,see)[0];
by=ysep+rands(-2,2,1,see)[0];
b=[0,ty];
c=[for (j=[1:1:(len/2)-1]) [j*20,ysep+10+rands(-2,2,1)[0] ]];
d= [(len/2)*20,ty];
e=[(len/2)*20,by];
f=[for
(j=[(len/2)+2:1:len])[(len-j+1)*20,ysep++rands(-2,2,1)[0]]];
g=[0,by] ;
p=concat([b],c,[d],[e],f,[g]);
polygon(p);
}
module block(){
for (j=[0:1:ns-1])
strand(sepj,j7);
}
ns=100; // number of strands
sep=18; // strand separation
len= 20; // length of strand
block();
translate([200,0,0])block();
translate([400,0,0])block();
translate([600,0,0])block();
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
So if I'm understanding this correctly, you want the endpoints of strand_1
to be the start points of strand_2?
I'm pretty sure that in order to do this in OpenSCAD you will need to
generate those end points outside of your loop.
One way to do this is to generate an array of starting point rands in
"block()" or "main" and pass "start_point[j]" and "start_point[j+1]" into
strand() also. These would be used by strand as it's start and end points.
You could also generate a list of rands in "main"
SEED=42284;
start_point_array=rands(-2,2,ns+1,SEED);
and just have block() also pass j into strand(),
so then each itteration of strand() uses that j to lookup it's own start
and end points.
Thus Raymond West hast written on Sun, Oct 16, 2022 at 06:20:26PM +0100, and, according to prophecy, it shall come to pass that:
> I generate a block of 'strands', each strand has a random factor applied to
> its width. How can I create a duplicate of it such that the ends are fixed,
> but the points in between are random. The example code the strands do not
> change for each iteration of block, which can lead to repeating pattern when
> joined up. If I do not use a seed, then the ends are different for each
> iteration, and will not align.
>
> if you run one block, with len= 80, then that will show more or less what I
> am trying to explain it should look like, apart from the endpoints of the
> blocks in the tessellated version.
>
>
> module strand(ysep,see){ // rand at 20
>
> ty=ysep+10+rands(-2,2,1,see)[0];
> by=ysep+rands(-2,2,1,see)[0];
>
> b=[0,ty];
> c=[for (j=[1:1:(len/2)-1]) [j*20,ysep+10+rands(-2,2,1)[0] ]];
> d= [(len/2)*20,ty];
> e=[(len/2)*20,by];
> f=[for
> (j=[(len/2)+2:1:len])[(len-j+1)*20,ysep++rands(-2,2,1)[0]]];
> g=[0,by] ;
> p=concat([b],c,[d],[e],f,[g]);
> polygon(p);
> }
>
> module block(){
> for (j=[0:1:ns-1])
> strand(sep*j,j*7);
> }
>
> ns=100; // number of strands
> sep=18; // strand separation
>
> len= 20; // length of strand
>
> block();
> translate([200,0,0])block();
> translate([400,0,0])block();
> translate([600,0,0])block();
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
M
mikeonenine@web.de
Tue, Oct 18, 2022 2:27 AM
Methinks it should be possible to do occasional random droplets of dirty black, hot engine oil splashing against the viewport from behind and running down into a puddle at the bottom. Delicious!
(Sorry, but my formative years were before the anthropocene had been given a name.)
Methinks it should be possible to do occasional random droplets of dirty black, hot engine oil splashing against the viewport from behind and running down into a puddle at the bottom. Delicious!
(Sorry, but my formative years were before the anthropocene had been given a name.)
GH
gene heskett
Tue, Oct 18, 2022 3:42 AM
Methinks it should be possible to do occasional random droplets of dirty black, hot engine oil splashing against the viewport from behind and running down into a puddle at the bottom. Delicious!
(Sorry, but my formative years were before the anthropocene had been given a name.)
Mine were about that far back, I made it to 88 back on the 4th.
Cheers, Gene Heskett.
"There are four boxes to be used in defense of liberty:
soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author, 1940)
If we desire respect for the law, we must first make the law respectable.
On 10/17/22 22:29, mikeonenine@web.de wrote:
> Methinks it should be possible to do occasional random droplets of dirty black, hot engine oil splashing against the viewport from behind and running down into a puddle at the bottom. Delicious!
>
> (Sorry, but my formative years were before the anthropocene had been given a name.)
Mine were about that far back, I made it to 88 back on the 4th.
>
>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
Cheers, Gene Heskett.
--
"There are four boxes to be used in defense of liberty:
soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author, 1940)
If we desire respect for the law, we must first make the law respectable.
- Louis D. Brandeis
Genes Web page <http://geneslinuxbox.net:6309/>
M
mikeonenine@web.de
Tue, Oct 18, 2022 4:10 AM
Mine were about that far back, I made it to 88 back on the 4th.
Congrats! I’m only somewhere between 71 and 72 (not quite sure where). Hope I’ll be able to keep up with things like OpenSCAD when I’m 88!
gene heskett wrote:
>
> Mine were about that far back, I made it to 88 back on the 4th.
Congrats! I’m only somewhere between 71 and 72 (not quite sure where). Hope I’ll be able to keep up with things like OpenSCAD when I’m 88!
HL
Hans L
Tue, Oct 18, 2022 5:44 AM
The trick to tile-able noise is to use a seed that incorporates a modulo.
To tile in one direction, something like:
rands(min,max,1, base_seed + mod(position, positions_until_repeat))
I have some sample code which creates a 2D tile-able noise (opposite edges
of heightmap match), in the following gist:
https://gist.github.com/thehans/35aa000d9a833c160a9f93bd3df25edf
(it also does bicubic interpolation between points, but that's another
topic ;) )
Hans
On Mon, Oct 17, 2022 at 11:11 PM mikeonenine@web.de wrote:
gene heskett wrote:
Mine were about that far back, I made it to 88 back on the 4th.
Congrats! I’m only somewhere between 71 and 72 (not quite sure where).
Hope I’ll be able to keep up with things like OpenSCAD when I’m 88!
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
The trick to tile-able noise is to use a seed that incorporates a modulo.
To tile in one direction, something like:
rands(min,max,1, base_seed + mod(position, positions_until_repeat))
I have some sample code which creates a 2D tile-able noise (opposite edges
of heightmap match), in the following gist:
https://gist.github.com/thehans/35aa000d9a833c160a9f93bd3df25edf
(it also does bicubic interpolation between points, but that's another
topic ;) )
Hans
On Mon, Oct 17, 2022 at 11:11 PM <mikeonenine@web.de> wrote:
> gene heskett wrote:
>
> Mine were about that far back, I made it to 88 back on the 4th.
>
> Congrats! I’m only somewhere between 71 and 72 (not quite sure where).
> Hope I’ll be able to keep up with things like OpenSCAD when I’m 88!
>
>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
>
RW
Ray West
Tue, Oct 18, 2022 12:13 PM
Thanks for the replies, I'll try and show a bit more explanation. I've
extracted the relevant code from my more complex overall solution
attempt, and I've attached it and a svg (the svg produced by the scad
code.)
Looking at the svg, the first block of strands have the end points set
equal, and when a number of blocks are created and joined, the fact that
the endpoints are equal is not apparent The scad script generates that
image. However, I've a suspicion that for certain values of sep, and
range of rands, in the construction of the connected blocks, then the
repeated constant ends would be visible across the group of blocks. I'm
aiming at a general solution, not one that works for certain values.
If you comment out the fixed ty and by, and uncomment the first pair,
(in the strand module) then the blocks have the random end points, but
they do not persist for each block, and gives 'steps' when the blocks
are aligned.
I may be wrong, but it appears that once a seed is generated for random
numbers, it applies to every instant of rands.
If the length of strands is increased to 1000, say, then it shows what I
would like to achieve by joining ten blocks of length 100.
I could generate a list of rands for ty and by, and increment through
when the block is created, but having a choice of random seeds would be
nice.
I may be missing the obvious. While I'm in winge mode, it's an
irritation that importing an svg that has just been exported it arrives
in a different location.
Thanks for the replies, I'll try and show a bit more explanation. I've
extracted the relevant code from my more complex overall solution
attempt, and I've attached it and a svg (the svg produced by the scad
code.)
Looking at the svg, the first block of strands have the end points set
equal, and when a number of blocks are created and joined, the fact that
the endpoints are equal is not apparent The scad script generates that
image. However, I've a suspicion that for certain values of sep, and
range of rands, in the construction of the connected blocks, then the
repeated constant ends would be visible across the group of blocks. I'm
aiming at a general solution, not one that works for certain values.
If you comment out the fixed ty and by, and uncomment the first pair,
(in the strand module) then the blocks have the random end points, but
they do not persist for each block, and gives 'steps' when the blocks
are aligned.
I may be wrong, but it appears that once a seed is generated for random
numbers, it applies to every instant of rands.
If the length of strands is increased to 1000, say, then it shows what I
would like to achieve by joining ten blocks of length 100.
I could generate a list of rands for ty and by, and increment through
when the block is created, but having a choice of random seeds would be
nice.
I may be missing the obvious. While I'm in winge mode, it's an
irritation that importing an svg that has just been exported it arrives
in a different location.
J
jon
Tue, Oct 18, 2022 12:29 PM
Ray:
I did not read your code, but when you say the "end points set equal",
is the thickness the same, or are both the thickness and the angle the
same? Are you seeing places where the two ends are in the same
location, but the trajectory of the two pieces are so different that the
joint is obvious? Do you need to get the two end points to go at the
same angle?
Jon
On 10/18/2022 8:13 AM, Ray West wrote:
Thanks for the replies, I'll try and show a bit more explanation. I've
extracted the relevant code from my more complex overall solution
attempt, and I've attached it and a svg (the svg produced by the scad
code.)
Looking at the svg, the first block of strands have the end points set
equal, and when a number of blocks are created and joined, the fact
that the endpoints are equal is not apparent The scad script
generates that image. However, I've a suspicion that for certain
values of sep, and range of rands, in the construction of the
connected blocks, then the repeated constant ends would be visible
across the group of blocks. I'm aiming at a general solution, not one
that works for certain values.
If you comment out the fixed ty and by, and uncomment the first pair,
(in the strand module) then the blocks have the random end points, but
they do not persist for each block, and gives 'steps' when the blocks
are aligned.
I may be wrong, but it appears that once a seed is generated for
random numbers, it applies to every instant of rands.
If the length of strands is increased to 1000, say, then it shows what
I would like to achieve by joining ten blocks of length 100.
I could generate a list of rands for ty and by, and increment through
when the block is created, but having a choice of random seeds would
be nice.
I may be missing the obvious. While I'm in winge mode, it's an
irritation that importing an svg that has just been exported it
arrives in a different location.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Ray:
I did not read your code, but when you say the "end points set equal",
is the thickness the same, or are both the thickness and the angle the
same? Are you seeing places where the two ends are in the same
location, but the trajectory of the two pieces are so different that the
joint is obvious? Do you need to get the two end points to go at the
same angle?
Jon
On 10/18/2022 8:13 AM, Ray West wrote:
> Thanks for the replies, I'll try and show a bit more explanation. I've
> extracted the relevant code from my more complex overall solution
> attempt, and I've attached it and a svg (the svg produced by the scad
> code.)
>
> Looking at the svg, the first block of strands have the end points set
> equal, and when a number of blocks are created and joined, the fact
> that the endpoints are equal is not apparent The scad script
> generates that image. However, I've a suspicion that for certain
> values of sep, and range of rands, in the construction of the
> connected blocks, then the repeated constant ends would be visible
> across the group of blocks. I'm aiming at a general solution, not one
> that works for certain values.
>
> If you comment out the fixed ty and by, and uncomment the first pair,
> (in the strand module) then the blocks have the random end points, but
> they do not persist for each block, and gives 'steps' when the blocks
> are aligned.
>
> I may be wrong, but it appears that once a seed is generated for
> random numbers, it applies to every instant of rands.
>
> If the length of strands is increased to 1000, say, then it shows what
> I would like to achieve by joining ten blocks of length 100.
>
> I could generate a list of rands for ty and by, and increment through
> when the block is created, but having a choice of random seeds would
> be nice.
>
> I may be missing the obvious. While I'm in winge mode, it's an
> irritation that importing an svg that has just been exported it
> arrives in a different location.
>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
RW
Raymond West
Tue, Oct 18, 2022 12:42 PM
Hi Jon,
The best way to understand what I am trying to explain, is probably to
run the code, and maybe zoom in, or alter the values. Exactly as it is,
I can not see any endpoint artefacts/vertical lines, etc., but I can
envisage that with different values, 'vertical lines/joins' would be
visible.
On 18/10/2022 13:29, jon wrote:
Ray:
I did not read your code, but when you say the "end points set equal",
is the thickness the same, or are both the thickness and the angle the
same? Are you seeing places where the two ends are in the same
location, but the trajectory of the two pieces are so different that
the joint is obvious? Do you need to get the two end points to go at
the same angle?
Jon
On 10/18/2022 8:13 AM, Ray West wrote:
Thanks for the replies, I'll try and show a bit more explanation.
I've extracted the relevant code from my more complex overall
solution attempt, and I've attached it and a svg (the svg produced by
the scad code.)
Looking at the svg, the first block of strands have the end points
set equal, and when a number of blocks are created and joined, the
fact that the endpoints are equal is not apparent The scad script
generates that image. However, I've a suspicion that for certain
values of sep, and range of rands, in the construction of the
connected blocks, then the repeated constant ends would be visible
across the group of blocks. I'm aiming at a general solution, not one
that works for certain values.
If you comment out the fixed ty and by, and uncomment the first pair,
(in the strand module) then the blocks have the random end points,
but they do not persist for each block, and gives 'steps' when the
blocks are aligned.
I may be wrong, but it appears that once a seed is generated for
random numbers, it applies to every instant of rands.
If the length of strands is increased to 1000, say, then it shows
what I would like to achieve by joining ten blocks of length 100.
I could generate a list of rands for ty and by, and increment through
when the block is created, but having a choice of random seeds would
be nice.
I may be missing the obvious. While I'm in winge mode, it's an
irritation that importing an svg that has just been exported it
arrives in a different location.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Hi Jon,
The best way to understand what I am trying to explain, is probably to
run the code, and maybe zoom in, or alter the values. Exactly as it is,
I can not see any endpoint artefacts/vertical lines, etc., but I can
envisage that with different values, 'vertical lines/joins' would be
visible.
On 18/10/2022 13:29, jon wrote:
> Ray:
>
> I did not read your code, but when you say the "end points set equal",
> is the thickness the same, or are both the thickness and the angle the
> same? Are you seeing places where the two ends are in the same
> location, but the trajectory of the two pieces are so different that
> the joint is obvious? Do you need to get the two end points to go at
> the same angle?
>
> Jon
>
>
> On 10/18/2022 8:13 AM, Ray West wrote:
>> Thanks for the replies, I'll try and show a bit more explanation.
>> I've extracted the relevant code from my more complex overall
>> solution attempt, and I've attached it and a svg (the svg produced by
>> the scad code.)
>>
>> Looking at the svg, the first block of strands have the end points
>> set equal, and when a number of blocks are created and joined, the
>> fact that the endpoints are equal is not apparent The scad script
>> generates that image. However, I've a suspicion that for certain
>> values of sep, and range of rands, in the construction of the
>> connected blocks, then the repeated constant ends would be visible
>> across the group of blocks. I'm aiming at a general solution, not one
>> that works for certain values.
>>
>> If you comment out the fixed ty and by, and uncomment the first pair,
>> (in the strand module) then the blocks have the random end points,
>> but they do not persist for each block, and gives 'steps' when the
>> blocks are aligned.
>>
>> I may be wrong, but it appears that once a seed is generated for
>> random numbers, it applies to every instant of rands.
>>
>> If the length of strands is increased to 1000, say, then it shows
>> what I would like to achieve by joining ten blocks of length 100.
>>
>> I could generate a list of rands for ty and by, and increment through
>> when the block is created, but having a choice of random seeds would
>> be nice.
>>
>> I may be missing the obvious. While I'm in winge mode, it's an
>> irritation that importing an svg that has just been exported it
>> arrives in a different location.
>>
>> _______________________________________________
>> OpenSCAD mailing list
>> To unsubscribe send an email to discuss-leave@lists.openscad.org
RW
Ray West
Tue, Oct 18, 2022 1:07 PM
Is this the way that random numbers should behave?
echo(rands(0,10,1)[0]);
echo(rands(20,30,1)[0]);
running the above a number of times, gives different random numbers -
as i would expect.
but seeding one, fixes both e.g.
echo(rands(0,10,1,0)[0]);
echo(rands(20,30,1)[0]);
running this a number of times gives the same pair each time. I would
expect the first one to be fixed, the second changing.
Is it possible to use a real time clock/timer as a seed?
Is this the way that random numbers should behave?
echo(rands(0,10,1)[0]);
echo(rands(20,30,1)[0]);
running the above a number of times, gives different random numbers -
as i would expect.
but seeding one, fixes both e.g.
echo(rands(0,10,1,0)[0]);
echo(rands(20,30,1)[0]);
running this a number of times gives the same pair each time. I would
expect the first one to be fixed, the second changing.
Is it possible to use a real time clock/timer as a seed?
JB
Jordan Brown
Tue, Oct 18, 2022 3:49 PM
I may be wrong, but it appears that once a seed is generated for
random numbers, it applies to every instant of rands.
The usual behavior of PRNG functions like this is that when you set the
seed, that seeds all further calls until you set it again.
So if you set the seed to a particular value, and you collect a thousand
values, you'll get a thousand values that look random. If you use the
same seed, you'll get the same thousand values. If you use a different
seed, you'll get a different thousand values.
Hans's scheme uses the PRNG differently, using a controlled and
predictable seed so that the "random" values are not at all random -
each one is precisely controlled and repeatable (without having to
restart the sequence).
> I may be wrong, but it appears that once a seed is generated for
> random numbers, it applies to every instant of rands.
The usual behavior of PRNG functions like this is that when you set the
seed, that seeds all further calls until you set it again.
So if you set the seed to a particular value, and you collect a thousand
values, you'll get a thousand values that look random. If you use the
same seed, you'll get the same thousand values. If you use a different
seed, you'll get a different thousand values.
Hans's scheme uses the PRNG differently, using a controlled and
predictable seed so that the "random" values are not at all random -
each one is precisely controlled and repeatable (without having to
restart the sequence).
JB
Jordan Brown
Tue, Oct 18, 2022 6:31 PM
On 10/18/2022 6:07 AM, Ray West wrote:
but seeding one, fixes both e.g.
echo(rands(0,10,1,0)[0]);
echo(rands(20,30,1)[0]);
running this a number of times gives the same pair each time. I would
expect the first one to be fixed, the second changing.
That's the way that it usually works. The seed controls all following
results. Many libraries in other languages have a separate "set seed"
function, but I think a few are like this where you can optionally
supply a seed to the random number function.
The idea is that (if you want repeatable random numbers) you set the
seed once, and then let the PNRG give you a stream of numbers. That
stream will be different for each original seed, but the same if the
seed is the same.
Is it possible to use a real time clock/timer as a seed?
OpenSCAD does not have such a function. I don't know what the default
seed is, but after you set the seed there's not much available in the
way of additional randomness.
Depending on the exact scenario, you might be able to grab a random
number, set the seed to something constant, grab however many random
numbers you need based off of that seed, then re-seed with the original
random number.
Here's a function that saves off a random number, sets a specified seed,
derives a number of random values, then re-seeds based on that saved
random number to re-establish an unpredictable stream.
function fixedrands(a, b, n, seed) =
let (old = rands(0,1,1)[0])
let (new = rands(a, b, n, seed))
let (junk = rands(0,1,1,old))
new;
echo(rands(0,10,1)[0]);
echo(fixedrands(0,10,10,1));
echo(rands(0,10,1)[0]);
Note that as you run it multiple times, the first and last numbers
change but the numbers in the middle stay the same.
I don't know whether this damages the randomness of the subsequent
values, but for most purposes it's probably OK. I wouldn't use it for
cryptography. But then again I don't think many people are doing
cryptography in OpenSCAD.
On 10/18/2022 6:07 AM, Ray West wrote:
> but seeding one, fixes both e.g.
>
> echo(rands(0,10,1,0)[0]);
> echo(rands(20,30,1)[0]);
>
> running this a number of times gives the same pair each time. I would
> expect the first one to be fixed, the second changing.
That's the way that it usually works. The seed controls all following
results. Many libraries in other languages have a separate "set seed"
function, but I think a few are like this where you can optionally
supply a seed to the random number function.
The idea is that (if you want repeatable random numbers) you set the
seed once, and then let the PNRG give you a stream of numbers. That
stream will be different for each original seed, but the same if the
seed is the same.
> Is it possible to use a real time clock/timer as a seed?
OpenSCAD does not have such a function. I don't know what the default
seed is, but after you set the seed there's not much available in the
way of additional randomness.
Depending on the exact scenario, you might be able to grab a random
number, set the seed to something constant, grab however many random
numbers you need based off of that seed, then re-seed with the original
random number.
Here's a function that saves off a random number, sets a specified seed,
derives a number of random values, then re-seeds based on that saved
random number to re-establish an unpredictable stream.
function fixedrands(a, b, n, seed) =
let (old = rands(0,1,1)[0])
let (new = rands(a, b, n, seed))
let (junk = rands(0,1,1,old))
new;
echo(rands(0,10,1)[0]);
echo(fixedrands(0,10,10,1));
echo(rands(0,10,1)[0]);
Note that as you run it multiple times, the first and last numbers
change but the numbers in the middle stay the same.
I don't know whether this damages the randomness of the subsequent
values, but for most purposes it's probably OK. I wouldn't use it for
cryptography. But then again I don't think many people are doing
cryptography in OpenSCAD.
JB
Jordan Brown
Tue, Oct 18, 2022 6:46 PM
I don't know if it's helpful here, but just for fun I tried playing with
generating random wavy lines.
function torect2(p) = [
p[0] * cos(p[1]),
p[0] * sin(p[1])
];
// Bezier functions from https://www.thingiverse.com/thing:8443
// but that yielded either single points or a raft of triangles;
// this yields a vector of points that you can then concatenate
// with other pieces to form a single polygon.
// If we were really clever, I think it would be possible to
// automatically space the output points based on how linear
// the curve is at that point. But right now I'm not that clever.
function BEZ03(u) = pow((1-u), 3);
function BEZ13(u) = 3*u*(pow((1-u),2));
function BEZ23(u) = 3*(pow(u,2))*(1-u);
function BEZ33(u) = pow(u,3);
function PointAlongBez4(p0, p1, p2, p3, u) = [
BEZ03(u)*p0[0]+BEZ13(u)*p1[0]+BEZ23(u)*p2[0]+BEZ33(u)*p3[0],
BEZ03(u)*p0[1]+BEZ13(u)*p1[1]+BEZ23(u)*p2[1]+BEZ33(u)*p3[1]];
// p0 - start point
// p1 - control point 1, line departs p0 headed this way
// p2 - control point 2, line arrives at p3 from this way
// p3 - end point
// segs - number of segments
function bez(p0, p1, p2, p3, segs) = [
for (i = [0:segs]) PointAlongBez4(p0, p1, p2, p3, i/segs)
];
function bezpolar(p0, p1, p2, p3, segs) =
bez(p0, p0+torect2(p1), p3+torect2(p2), p3, segs);
function rand1(a, b) = rands(a, b, 1)[0];
function point(maxy, maxa, minc, maxc) = [
rand1(0, maxy),
rand1(-maxa, maxa),
rand1(minc, maxc),
rand1(minc, maxc)
];
function steps(w, minstep, maxstep) = [
0,
for (x = rand1(minstep, maxstep);
x + minstep < w;
x = x + rand1(minstep, maxstep))
x,
w
];
function wavy(w, minstep, maxstep, maxy, maxa, minc, maxc) =
let (xvalues = steps(w, minstep, maxstep))
let (controls = [
for (i=[0:len(xvalues)-1])
let(p = point(maxy, maxa, minc, maxc))
[
[ xvalues[i], p[0] ], p[1], p[2], p[3]
]
])
[
for (i=[0:len(controls)-2])
let(c = controls[i], next = controls[i+1])
each bezpolar(
c[0],
[c[3], c[1]],
[next[2], 180+next[1]],
next[0],
10)
];
w = 100;
minstep = 10;
maxstep = 30;
maxy = 10;
maxa = 30;
minc = 3;
maxc = 5;
points = wavy(w, minstep, maxstep, maxy, maxa, minc, maxc);
polygon([
[0,0],
each points,
[w,0]
]);
The parameters to wavy() are:
- w - the width of the wavy line
- minstep - the minimum x distance between "reference points" where
the line curvature changes
- maxstep - the maximum x distance between reference points
- maxy - the maximum y position at a reference point (minimum is zero)
- maxa - the maximum angle that the line will have crossing the
reference point (minimum is the negative of this)
- minc - the minimum distance from the control point to the Bezier
control point
- maxc - the maximum distance from the control point to the Bezier
control point
Here's some sample outputs, with the parameters above:
What it does is to pick randomly spaced X values that total up to the
desired width[*]. For each X value, it picks a Y value and two Bezier
control points, at the same random angle but different random
distances. Then for each segment between two of those points, it
generates a Bezier curve using the first point and its right-side
control point and the second point and its left-side control point.
[*] When the next value would be less than the minimum from the end, it
stops, so the last step can be up to min+max long. There's probably a
better way to stop.
I don't know if it's helpful here, but just for fun I tried playing with
generating random wavy lines.
function torect2(p) = [
p[0] * cos(p[1]),
p[0] * sin(p[1])
];
// Bezier functions from https://www.thingiverse.com/thing:8443
// but that yielded either single points or a raft of triangles;
// this yields a vector of points that you can then concatenate
// with other pieces to form a single polygon.
// If we were really clever, I think it would be possible to
// automatically space the output points based on how linear
// the curve is at that point. But right now I'm not that clever.
function BEZ03(u) = pow((1-u), 3);
function BEZ13(u) = 3*u*(pow((1-u),2));
function BEZ23(u) = 3*(pow(u,2))*(1-u);
function BEZ33(u) = pow(u,3);
function PointAlongBez4(p0, p1, p2, p3, u) = [
BEZ03(u)*p0[0]+BEZ13(u)*p1[0]+BEZ23(u)*p2[0]+BEZ33(u)*p3[0],
BEZ03(u)*p0[1]+BEZ13(u)*p1[1]+BEZ23(u)*p2[1]+BEZ33(u)*p3[1]];
// p0 - start point
// p1 - control point 1, line departs p0 headed this way
// p2 - control point 2, line arrives at p3 from this way
// p3 - end point
// segs - number of segments
function bez(p0, p1, p2, p3, segs) = [
for (i = [0:segs]) PointAlongBez4(p0, p1, p2, p3, i/segs)
];
function bezpolar(p0, p1, p2, p3, segs) =
bez(p0, p0+torect2(p1), p3+torect2(p2), p3, segs);
function rand1(a, b) = rands(a, b, 1)[0];
function point(maxy, maxa, minc, maxc) = [
rand1(0, maxy),
rand1(-maxa, maxa),
rand1(minc, maxc),
rand1(minc, maxc)
];
function steps(w, minstep, maxstep) = [
0,
for (x = rand1(minstep, maxstep);
x + minstep < w;
x = x + rand1(minstep, maxstep))
x,
w
];
function wavy(w, minstep, maxstep, maxy, maxa, minc, maxc) =
let (xvalues = steps(w, minstep, maxstep))
let (controls = [
for (i=[0:len(xvalues)-1])
let(p = point(maxy, maxa, minc, maxc))
[
[ xvalues[i], p[0] ], p[1], p[2], p[3]
]
])
[
for (i=[0:len(controls)-2])
let(c = controls[i], next = controls[i+1])
each bezpolar(
c[0],
[c[3], c[1]],
[next[2], 180+next[1]],
next[0],
10)
];
w = 100;
minstep = 10;
maxstep = 30;
maxy = 10;
maxa = 30;
minc = 3;
maxc = 5;
points = wavy(w, minstep, maxstep, maxy, maxa, minc, maxc);
polygon([
[0,0],
each points,
[w,0]
]);
The parameters to wavy() are:
* w - the width of the wavy line
* minstep - the minimum x distance between "reference points" where
the line curvature changes
* maxstep - the maximum x distance between reference points
* maxy - the maximum y position at a reference point (minimum is zero)
* maxa - the maximum angle that the line will have crossing the
reference point (minimum is the negative of this)
* minc - the minimum distance from the control point to the Bezier
control point
* maxc - the maximum distance from the control point to the Bezier
control point
Here's some sample outputs, with the parameters above:
What it does is to pick randomly spaced X values that total up to the
desired width[*]. For each X value, it picks a Y value and two Bezier
control points, at the same random angle but different random
distances. Then for each segment between two of those points, it
generates a Bezier curve using the first point and its right-side
control point and the second point and its left-side control point.
[*] When the next value would be less than the minimum from the end, it
stops, so the last step can be up to min+max long. There's probably a
better way to stop.
RW
Rogier Wolff
Tue, Oct 18, 2022 7:22 PM
On Tue, Oct 18, 2022 at 11:31:35AM -0700, Jordan Brown wrote:
The idea is that (if you want repeatable random numbers) you set the
seed once, and then let the PNRG give you a stream of numbers. That
stream will be different for each original seed, but the same if the
seed is the same.
For SOME applications having the same stream of random numbers is
entirely unwanted. For example, when initializing a public key, the
first step is: Choose a random prime of about 1000 bits. If everybody
(or just a few!) used the same random number sequence they would end
up knowing eachothers keys.
But in other applications having a predictable "seems random" sequence
is useful. For example, if you are debugging a program and it crashes
after 50000 loops through the main program. Debugging it after the
crash shows that at some time in the past something went wrong. So you
can try to run it 40000 times around the loop and... find it crashes
after 35000 times through the loop. Now for the debugging you'd like
it to be determistic. Now you can watch it crash after N iterations
and then run it again to see the state of the program at half-N
iterations.
In OpenScad you might want to generate "grassleaves" in random
positions. But then to animate them "waving in the wind", you don't
want a new random position for every frame. You want the "random
positions" to come out the same as the first time.
I thought I'd explain the reason why random number generators have the
"set seed" function. Some people might understand better if they know
the WHY.
Roger.
--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
f equals m times a. When your f is steady, and your m is going down
your a is going up. -- Chris Hadfield about flying up the space shuttle.
On Tue, Oct 18, 2022 at 11:31:35AM -0700, Jordan Brown wrote:
> The idea is that (if you want repeatable random numbers) you set the
> seed once, and then let the PNRG give you a stream of numbers. That
> stream will be different for each original seed, but the same if the
> seed is the same.
For SOME applications having the same stream of random numbers is
entirely unwanted. For example, when initializing a public key, the
first step is: Choose a random prime of about 1000 bits. If everybody
(or just a few!) used the same random number sequence they would end
up knowing eachothers keys.
But in other applications having a predictable "seems random" sequence
is useful. For example, if you are debugging a program and it crashes
after 50000 loops through the main program. Debugging it after the
crash shows that at some time in the past something went wrong. So you
can try to run it 40000 times around the loop and... find it crashes
after 35000 times through the loop. Now for the debugging you'd like
it to be determistic. Now you can watch it crash after N iterations
and then run it again to see the state of the program at half-N
iterations.
In OpenScad you might want to generate "grassleaves" in random
positions. But then to animate them "waving in the wind", you don't
want a new random position for every frame. You want the "random
positions" to come out the same as the first time.
I thought I'd explain the reason why random number generators have the
"set seed" function. Some people might understand better if they know
the WHY.
Roger.
--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
f equals m times a. When your f is steady, and your m is going down
your a is going up. -- Chris Hadfield about flying up the space shuttle.
MM
Michael Marx
Wed, Oct 19, 2022 3:38 AM
rands() with no seed specified, uses Unix time + process ID as the seed.
So even if multiple processes (on one system) run at the same time they will have unique seeds.
For those interested
https://github.com/openscad/openscad/blob/master/src/core/builtin_functions.cc
It uses mt19937 (https://cplusplus.com/reference/random/mt19937/)
with a uniform_real_distribution.
I have a program to draw random 'art', I do the following so you can recreate something
as long as you note the key. You can echo() it, but I use text(key) on the output.
It is probably overkill to seed with random seeds...
// key changes to use different geometry each time
key=floor(rands(1000,999999,1)[0]); // a number easily formated
// add a previous key here to reproduce same output
//key=373710;
s=rands(-20,20,7,key); // seed
// Number of objects
n=ceil(rands(50000,99000,1,s[0])[0]); // random
// random position & size
rx=rands(-x,x,n,s[1]);
ry=rands(-y,y,n,s[2]);
rz=rands(-2,2,n,s[3]);
rs=rands(5,35,n,s[4]); // size
rt=rands(0,3.999,n,s[5]); // type
rr=rands(0,359,n,s[6]); // rotation
-----Original Message-----
Sent: Wed, 19 Oct 2022 00:07
To: OpenSCAD general discussion
Subject: [OpenSCAD] Re: how to randomness different loops?
Is this the way that random numbers should behave?
running the above a number of times, gives different random numbers -
but seeding one, fixes both e.g.
echo(rands(0,10,1,0)[0]);
running this a number of times gives the same pair each time. I would
expect the first one to be fixed, the second changing.
Is it possible to use a real time clock/timer as a seed?
--
This email has been checked for viruses by AVG antivirus software.
www.avg.com
rands() with no seed specified, uses Unix time + process ID as the seed.
So even if multiple processes (on one system) run at the same time they will have unique seeds.
For those interested
https://github.com/openscad/openscad/blob/master/src/core/builtin_functions.cc
It uses mt19937 (https://cplusplus.com/reference/random/mt19937/)
with a uniform_real_distribution.
I have a program to draw random 'art', I do the following so you can recreate something
as long as you note the key. You can echo() it, but I use text(key) on the output.
It is probably overkill to seed with random seeds...
// key changes to use different geometry each time
key=floor(rands(1000,999999,1)[0]); // a number easily formated
// add a previous key here to reproduce same output
//key=373710;
s=rands(-20,20,7,key); // seed
// Number of objects
n=ceil(rands(50000,99000,1,s[0])[0]); // random
// random position & size
rx=rands(-x,x,n,s[1]);
ry=rands(-y,y,n,s[2]);
rz=rands(-2,2,n,s[3]);
rs=rands(5,35,n,s[4]); // size
rt=rands(0,3.999,n,s[5]); // type
rr=rands(0,359,n,s[6]); // rotation
> -----Original Message-----
> From: Ray West [mailto:raywest@raywest.com]
> Sent: Wed, 19 Oct 2022 00:07
> To: OpenSCAD general discussion
> Subject: [OpenSCAD] Re: how to randomness different loops?
>
> Is this the way that random numbers should behave?
>
> echo(rands(0,10,1)[0]);
> echo(rands(20,30,1)[0]);
>
> running the above a number of times, gives different random numbers -
> as i would expect.
>
> but seeding one, fixes both e.g.
>
> echo(rands(0,10,1,0)[0]);
> echo(rands(20,30,1)[0]);
>
> running this a number of times gives the same pair each time. I would
> expect the first one to be fixed, the second changing.
>
> Is it possible to use a real time clock/timer as a seed?
>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
--
This email has been checked for viruses by AVG antivirus software.
www.avg.com
BL
Bryan Lee
Wed, Oct 19, 2022 4:10 PM
Thus Michael Marx hast written on Wed, Oct 19, 2022 at 02:38:02PM +1100, and, according to prophecy, it shall come to pass that:
rands() with no seed specified, uses Unix time + process ID as the seed.
So even if multiple processes (on one system) run at the same time they will
have unique seeds.
Awesome to know! Thanks Michael!
And it looks like a new time-based-seed is created each time a model is compiled:
cube(rands(1,10,1)[0]);
Thus Michael Marx hast written on Wed, Oct 19, 2022 at 02:38:02PM +1100, and, according to prophecy, it shall come to pass that:
> rands() with no seed specified, uses Unix time + process ID as the seed.
> So even if multiple processes (on one system) run at the same time they will
> have unique seeds.
Awesome to know! Thanks Michael!
And it looks like a new time-based-seed is created each time a model is compiled:
cube(rands(1,10,1)[0]);
RW
Raymond West
Wed, Oct 19, 2022 5:02 PM
Hi,
Any one with windows, try this - Those with linux try it to, see if you
have the same results.
echo(rands(0,1,1,1)[0]);
echo(rands(10,20,1)[0]);
echo(rands(20,30,1)[0]);
run it a few times, and you will each time it runs, all the random
numbers do not change. i would expect the first to be the same for each
run, and the second two to change.
If you comment out the first line, then every time it is run, they are
different, since they are using the timer, I guess. But, it seems, once
you've used a seed, the timer version is switched to using the seed.
if you use a seed, then all random numbers appear to use that seed,
whether specifically requested or not. I have not noticed this behaviour
for other random numbers in other languages in windows (Not saying they
are not the same, but that I've not noticed the problem, if seed is not
specified, the random number generator carries on using the clock seed.}
from free basic documentation, for example -
For any given seed, each algorithm will produce a specific,
deterministic sequence of numbers for that seed. If you want each call
toRandomizeto produce a different sequence of numbers, a seed that is
not quite predictable should be used - for example, the value returned
fromTimer https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgTimer.
Omitting the/seed/parameter will use a value based on this.
c#, c++, achieve similar results, but by a different method
This is not how it appears to work in Openscad on windows.
in effect it should be possible to have a random number seeded by the
clock,and one generated by a seed that you assign, and both work
concurrently. In Openscad it seems that once you've set a seed , then
the one that does not have your seed selected, appears to use it anyway.
On 19/10/2022 17:10, Bryan Lee wrote:
Thus Michael Marx hast written on Wed, Oct 19, 2022 at 02:38:02PM +1100, and, according to prophecy, it shall come to pass that:
rands() with no seed specified, uses Unix time + process ID as the seed.
So even if multiple processes (on one system) run at the same time they will
have unique seeds.
Awesome to know! Thanks Michael!
And it looks like a new time-based-seed is created each time a model is compiled:
cube(rands(1,10,1)[0]);
OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org
Hi,
Any one with windows, try this - Those with linux try it to, see if you
have the same results.
echo(rands(0,1,1,1)[0]);
echo(rands(10,20,1)[0]);
echo(rands(20,30,1)[0]);
run it a few times, and you will each time it runs, all the random
numbers do not change. i would expect the first to be the same for each
run, and the second two to change.
If you comment out the first line, then every time it is run, they are
different, since they are using the timer, I guess. But, it seems, once
you've used a seed, the timer version is switched to using the seed.
if you use a seed, then all random numbers appear to use that seed,
whether specifically requested or not. I have not noticed this behaviour
for other random numbers in other languages in windows (Not saying they
are not the same, but that I've not noticed the problem, if seed is not
specified, the random number generator carries on using the clock seed.}
from free basic documentation, for example -
For any given seed, each algorithm will produce a specific,
deterministic sequence of numbers for that seed. If you want each call
to*Randomize*to produce a different sequence of numbers, a seed that is
not quite predictable should be used - for example, the value returned
fromTimer <https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgTimer>.
Omitting the/seed/parameter will use a value based on this.
c#, c++, achieve similar results, but by a different method
This is not how it appears to work in Openscad on windows.
in effect it should be possible to have a random number seeded by the
clock,and one generated by a seed that you assign, and both work
concurrently. In Openscad it seems that once you've set a seed , then
the one that does not have your seed selected, appears to use it anyway.
On 19/10/2022 17:10, Bryan Lee wrote:
> Thus Michael Marx hast written on Wed, Oct 19, 2022 at 02:38:02PM +1100, and, according to prophecy, it shall come to pass that:
>> rands() with no seed specified, uses Unix time + process ID as the seed.
>> So even if multiple processes (on one system) run at the same time they will
>> have unique seeds.
>
> Awesome to know! Thanks Michael!
>
> And it looks like a new time-based-seed is created each time a model is compiled:
> cube(rands(1,10,1)[0]);
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email todiscuss-leave@lists.openscad.org
JB
Jordan Brown
Wed, Oct 19, 2022 7:08 PM
This is all expected behavior, and is how PRNGs usually work, and is
much simpler than you're implying. See the bottom of the message for
the five(!) lines that do all of the work.
One time, when OpenSCAD starts up, it gives the PRNG a seed that is the
sum of the current time (in seconds since the start of 1970) and the
process ID. After that, you get a stream of numbers, all based on that
original seed.
If you give it a new seed, then all further random numbers are based on
that seed.
This is pretty normal PRNG behavior. Calling rands() with a fourth
parameter is exactly equivalent to calling BASIC's RANDOMIZE with a
parameter, and then pulling some number of random numbers.
What is unusual about OpenSCAD is that you set the seed using the "get a
random number" function, rather than using a separate operation. The
expected usage pattern is that if you want repeatable random numbers you
call rands() once, at the top of the program, with a seed, and you
discard the random number that it generates. (Or you ask it for zero
numbers, and discard the empty array that results.)
There are interesting tricks that you can do by using a controlled seed
to produce repeatable sequences, but at any time there's only one
sequence, based on the most recent seed.
Bryan said:
And it looks like a new time-based-seed is created each time a model is compiled:
No, actually not. It's seeded once at startup.
Subsequent runs get new results because the random-number generator is
not reseeded for each run of the model. It continues to produce new
random numbers based on that original seed.
Here's a test case. Run this program:
echo(rands(0,1,1,0));
echo(rands(0,1,1));
Note the results. They might well be 0.592845 and 0.844266. (Not clear
to me whether the whole PRNG chain is platform-independent.)
Now comment out the second line:
echo(rands(0,1,1,0));
//echo(rands(0,1,1));
to nobody's surprise, you get the same value as the first value from the
first run, 0.592845 for me.
Restore that second line, and comment out the first line:
//echo(rands(0,1,1,0));
echo(rands(0,1,1));
Run that. You should get the second value from the original run,
0.844266 for me.
You seeded the PRNG with zero, and pulled two numbers from it. Then you
seeded it with zero again, and again pulled two numbers from it. The
fact that the second two numbers were from different runs of the model
does not matter.
Maybe it should re-seed on every run, but it doesn't.
The implementation is quite simple, and doesn't require any specialized
knowledge to understand. Knowledge of C++ isn't even really required to
understand the gist.
https://github.com/openscad/openscad/blob/484f3c670bc9a2a35351af915fbe2f3b68462166/src/core/builtin_functions.cc#L55
through line 64 establishes the original seed. This is run one time,
when OpenSCAD starts.
https://github.com/openscad/openscad/blob/484f3c670bc9a2a35351af915fbe2f3b68462166/src/core/builtin_functions.cc#L161
through 164 reseeds when you specify a new seed.
That's the entirety of the seed management, those fourteen lines. And
only five do the real work:
std::mt19937 deterministic_rng(std::time(nullptr) + process_id);
initializes the PRNG. Then in the handling for the rands() function:
if (arguments.size() > 3) {
uint32_t seed = static_cast<uint32_t>(hash_floating_point(arguments[3]->toDouble() ));
deterministic_rng.seed(seed);
}
If you supply a fourth argument, it reseeds the PRNG with that argument.
This is all expected behavior, and is how PRNGs usually work, and is
much simpler than you're implying. See the bottom of the message for
the five(!) lines that do all of the work.
One time, when OpenSCAD starts up, it gives the PRNG a seed that is the
sum of the current time (in seconds since the start of 1970) and the
process ID. After that, you get a stream of numbers, all based on that
original seed.
If you give it a new seed, then all further random numbers are based on
*that* seed.
This is pretty normal PRNG behavior. Calling rands() with a fourth
parameter is exactly equivalent to calling BASIC's RANDOMIZE with a
parameter, and then pulling some number of random numbers.
What is unusual about OpenSCAD is that you set the seed using the "get a
random number" function, rather than using a separate operation. The
expected usage pattern is that if you want repeatable random numbers you
call rands() once, at the top of the program, with a seed, and you
discard the random number that it generates. (Or you ask it for zero
numbers, and discard the empty array that results.)
There are interesting tricks that you can do by using a controlled seed
to produce repeatable sequences, but at any time there's only one
sequence, based on the most recent seed.
Bryan said:
> And it looks like a new time-based-seed is created each time a model is compiled:
No, actually not. It's seeded once at startup.
Subsequent runs get new results because the random-number generator is
*not* reseeded for each run of the model. It continues to produce new
random numbers based on that original seed.
Here's a test case. Run this program:
echo(rands(0,1,1,0));
echo(rands(0,1,1));
Note the results. They might well be 0.592845 and 0.844266. (Not clear
to me whether the whole PRNG chain is platform-independent.)
Now comment out the second line:
echo(rands(0,1,1,0));
//echo(rands(0,1,1));
to nobody's surprise, you get the same value as the first value from the
first run, 0.592845 for me.
Restore that second line, and comment out the first line:
//echo(rands(0,1,1,0));
echo(rands(0,1,1));
Run that. You should get the second value from the original run,
0.844266 for me.
You seeded the PRNG with zero, and pulled two numbers from it. Then you
seeded it with zero again, and again pulled two numbers from it. The
fact that the second two numbers were from different runs of the model
does not matter.
Maybe it *should* re-seed on every run, but it doesn't.
---
The implementation is quite simple, and doesn't require any specialized
knowledge to understand. Knowledge of C++ isn't even really required to
understand the gist.
https://github.com/openscad/openscad/blob/484f3c670bc9a2a35351af915fbe2f3b68462166/src/core/builtin_functions.cc#L55
through line 64 establishes the original seed. This is run one time,
when OpenSCAD starts.
https://github.com/openscad/openscad/blob/484f3c670bc9a2a35351af915fbe2f3b68462166/src/core/builtin_functions.cc#L161
through 164 reseeds when you specify a new seed.
That's the entirety of the seed management, those fourteen lines. And
only five do the real work:
std::mt19937 deterministic_rng(std::time(nullptr) + process_id);
initializes the PRNG. Then in the handling for the rands() function:
if (arguments.size() > 3) {
uint32_t seed = static_cast<uint32_t>(hash_floating_point(arguments[3]->toDouble() ));
deterministic_rng.seed(seed);
}
If you supply a fourth argument, it reseeds the PRNG with that argument.
JB
Jordan Brown
Wed, Oct 19, 2022 7:12 PM
And of course there's the ultimate random number generator, with all
results determined by the roll of a die: https://xkcd.com/221/
And of course there's the ultimate random number generator, with all
results determined by the roll of a die: https://xkcd.com/221/