discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

children() and extra unwanted evaluations

N
Neon22
Sat, Mar 5, 2016 11:01 AM

I'm trying to convert some procedural spacecraft code and I've run into a
problem.

Here's an abstract:
Imagine you want to make a symmetrical object by:

  • making an asymmetrical one,
  • intersecting it with a cube (on one side of the origin)
  • and then mirroring the result onto the other side.
    Result - symmetrical object.

like this maybe:

module m_mirror() {
children(0);
mirror([1,0,0])
children(0);
}
module cut_in_half(size)  {
intersection() {
translate([0, -size/2.0, -size/2.0])
cube(size=size, center=false);
children(0);
}
}

module randcyl() {
// use of rands in here shows this object being called twice
echo("randcyl called");
rotate([rands(0,77,1)[0],45,0])
cylinder(h=4, d = 2, center=true);
}

m_mirror() cut_in_half(100) randcyl();

which unfortunately (for me) reports the echo twice and gives us variations
that look like this:
http://forum.openscad.org/file/n16291/n44sh.jpg

SO:
Even though it looks to me like randcyl() should be evaluated only once
(when children passed in) - its called twice.
You can skip the cut_in_half(100) and still get the same result.

  • in m_mirror() its used twice and is called twice.

This isn't a problem if there is no random value as the result will be the
same.
But I'm using a lot of random calls in the actual code this simple example
is derived from.

The only way I can see around it now is to pass in a seed and propogate it
through every function. But its a load of error prone(for me) work :)

  • Actually I'd need a long string of premade rands()  to cycle through and
    remake from a master seed.

The code would look like this:

module m_mirror() {
children(0);
mirror([1,0,0])
children(0);
}
module cut_in_half(size)  {
intersection() {
translate([0, -size/2.0, -size/2.0])
cube(size=size, center=false);
children(0);
}
}

module randcyl(seed) {
// use of rands in here shows this object being called twice
echo("randcyl called");
rotate([rands(0,77,1,seed)[0],45,0])
cylinder(h=4, d = 2, center=true);
}
m_mirror() cut_in_half(100) randcyl(221);
http://forum.openscad.org/file/n16291/5l5lz4.jpg
Can anyone see another way to cut and mirror an object but only invoke its
construcion once ?

Here's what I'm really up to:
http://forum.openscad.org/file/n16291/99p4zm.jpg

Actually rendering it also recreates it. I need to find a good way to
control the seeds...

--
View this message in context: http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

I'm trying to convert some procedural spacecraft code and I've run into a problem. Here's an abstract: Imagine you want to make a symmetrical object by: - making an asymmetrical one, - intersecting it with a cube (on one side of the origin) - and then mirroring the result onto the other side. Result - symmetrical object. like this maybe: module m_mirror() { children(0); mirror([1,0,0]) children(0); } module cut_in_half(size) { intersection() { translate([0, -size/2.0, -size/2.0]) cube(size=size, center=false); children(0); } } module randcyl() { // use of rands in here shows this object being called twice echo("randcyl called"); rotate([rands(0,77,1)[0],45,0]) cylinder(h=4, d = 2, center=true); } m_mirror() cut_in_half(100) randcyl(); which unfortunately (for me) reports the echo twice and gives us variations that look like this: <http://forum.openscad.org/file/n16291/n44sh.jpg> SO: Even though it looks to me like randcyl() should be evaluated only once (when children passed in) - its called twice. You can skip the cut_in_half(100) and still get the same result. - in m_mirror() its used twice and is called twice. This isn't a problem if there is no random value as the result will be the same. But I'm using a lot of random calls in the actual code this simple example is derived from. The only way I can see around it now is to pass in a seed and propogate it through every function. But its a load of error prone(for me) work :) - Actually I'd need a long string of premade rands() to cycle through and remake from a master seed. The code would look like this: module m_mirror() { children(0); mirror([1,0,0]) children(0); } module cut_in_half(size) { intersection() { translate([0, -size/2.0, -size/2.0]) cube(size=size, center=false); children(0); } } module randcyl(seed) { // use of rands in here shows this object being called twice echo("randcyl called"); rotate([rands(0,77,1,seed)[0],45,0]) cylinder(h=4, d = 2, center=true); } m_mirror() cut_in_half(100) randcyl(221); <http://forum.openscad.org/file/n16291/5l5lz4.jpg> Can anyone see another way to cut and mirror an object but only invoke its construcion once ? Here's what I'm really up to: <http://forum.openscad.org/file/n16291/99p4zm.jpg> Actually rendering it also recreates it. I need to find a good way to control the seeds... -- View this message in context: http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291.html Sent from the OpenSCAD mailing list archive at Nabble.com.
NH
nop head
Sat, Mar 5, 2016 2:45 PM

Interesting problem. If this issue gets fixed
https://github.com/openscad/openscad/issues/1594 then you could make the
random number a default parameter to randcyl.

In the meantime you could set a global variable with rand and pass it to
randcyl() or just reference it in randcyl().

F5 doesn't work with this code on my system. It shows only half of the
result and when I rotate it flips to the other half.

On 5 March 2016 at 11:01, Neon22 mschafer@wireframe.biz wrote:

I'm trying to convert some procedural spacecraft code and I've run into a
problem.

Here's an abstract:
Imagine you want to make a symmetrical object by:

  • making an asymmetrical one,
  • intersecting it with a cube (on one side of the origin)
  • and then mirroring the result onto the other side.
    Result - symmetrical object.

like this maybe:

module m_mirror() {
children(0);
mirror([1,0,0])
children(0);
}
module cut_in_half(size)  {
intersection() {
translate([0, -size/2.0, -size/2.0])
cube(size=size, center=false);
children(0);
}
}

module randcyl() {
// use of rands in here shows this object being called twice
echo("randcyl called");
rotate([rands(0,77,1)[0],45,0])
cylinder(h=4, d = 2, center=true);
}

m_mirror() cut_in_half(100) randcyl();

which unfortunately (for me) reports the echo twice and gives us variations
that look like this:
http://forum.openscad.org/file/n16291/n44sh.jpg

SO:
Even though it looks to me like randcyl() should be evaluated only once
(when children passed in) - its called twice.
You can skip the cut_in_half(100) and still get the same result.

  • in m_mirror() its used twice and is called twice.

This isn't a problem if there is no random value as the result will be the
same.
But I'm using a lot of random calls in the actual code this simple example
is derived from.

The only way I can see around it now is to pass in a seed and propogate it
through every function. But its a load of error prone(for me) work :)

  • Actually I'd need a long string of premade rands()  to cycle through and
    remake from a master seed.

The code would look like this:

module m_mirror() {
children(0);
mirror([1,0,0])
children(0);
}
module cut_in_half(size)  {
intersection() {
translate([0, -size/2.0, -size/2.0])
cube(size=size, center=false);
children(0);
}
}

module randcyl(seed) {
// use of rands in here shows this object being called twice
echo("randcyl called");
rotate([rands(0,77,1,seed)[0],45,0])
cylinder(h=4, d = 2, center=true);
}
m_mirror() cut_in_half(100) randcyl(221);
http://forum.openscad.org/file/n16291/5l5lz4.jpg
Can anyone see another way to cut and mirror an object but only invoke its
construcion once ?

Here's what I'm really up to:
http://forum.openscad.org/file/n16291/99p4zm.jpg

Actually rendering it also recreates it. I need to find a good way to
control the seeds...

--
View this message in context:
http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291.html
Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Interesting problem. If this issue gets fixed https://github.com/openscad/openscad/issues/1594 then you could make the random number a default parameter to randcyl. In the meantime you could set a global variable with rand and pass it to randcyl() or just reference it in randcyl(). F5 doesn't work with this code on my system. It shows only half of the result and when I rotate it flips to the other half. On 5 March 2016 at 11:01, Neon22 <mschafer@wireframe.biz> wrote: > I'm trying to convert some procedural spacecraft code and I've run into a > problem. > > Here's an abstract: > Imagine you want to make a symmetrical object by: > - making an asymmetrical one, > - intersecting it with a cube (on one side of the origin) > - and then mirroring the result onto the other side. > Result - symmetrical object. > > like this maybe: > > module m_mirror() { > children(0); > mirror([1,0,0]) > children(0); > } > module cut_in_half(size) { > intersection() { > translate([0, -size/2.0, -size/2.0]) > cube(size=size, center=false); > children(0); > } > } > > module randcyl() { > // use of rands in here shows this object being called twice > echo("randcyl called"); > rotate([rands(0,77,1)[0],45,0]) > cylinder(h=4, d = 2, center=true); > } > > m_mirror() cut_in_half(100) randcyl(); > > which unfortunately (for me) reports the echo twice and gives us variations > that look like this: > <http://forum.openscad.org/file/n16291/n44sh.jpg> > > SO: > Even though it looks to me like randcyl() should be evaluated only once > (when children passed in) - its called twice. > You can skip the cut_in_half(100) and still get the same result. > - in m_mirror() its used twice and is called twice. > > This isn't a problem if there is no random value as the result will be the > same. > But I'm using a lot of random calls in the actual code this simple example > is derived from. > > The only way I can see around it now is to pass in a seed and propogate it > through every function. But its a load of error prone(for me) work :) > - Actually I'd need a long string of premade rands() to cycle through and > remake from a master seed. > > The code would look like this: > > module m_mirror() { > children(0); > mirror([1,0,0]) > children(0); > } > module cut_in_half(size) { > intersection() { > translate([0, -size/2.0, -size/2.0]) > cube(size=size, center=false); > children(0); > } > } > > module randcyl(seed) { > // use of rands in here shows this object being called twice > echo("randcyl called"); > rotate([rands(0,77,1,seed)[0],45,0]) > cylinder(h=4, d = 2, center=true); > } > m_mirror() cut_in_half(100) randcyl(221); > <http://forum.openscad.org/file/n16291/5l5lz4.jpg> > Can anyone see another way to cut and mirror an object but only invoke its > construcion once ? > > Here's what I'm really up to: > <http://forum.openscad.org/file/n16291/99p4zm.jpg> > > Actually rendering it also recreates it. I need to find a good way to > control the seeds... > > > > -- > View this message in context: > http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
N
Neon22
Sat, Mar 5, 2016 9:39 PM

Thanks nophead.
I suspect what I'm really suggesting/asking is that children(0) would be
evaluated once and then that csg tree would be copied each time it was
referenced.

Ideally as both an efficiency improvement and to solve my specific rands()
problem.
Not sure what the approach is in openSCAD2 to this ?

As for me - looks like I need to make a long list of random numbers from a
seed (yay rands())
and then cycle through that list in my own random function which gets called
many times in many places.

--
View this message in context: http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16296.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Thanks nophead. I suspect what I'm really suggesting/asking is that children(0) would be evaluated once and then that csg tree would be copied each time it was referenced. Ideally as both an efficiency improvement and to solve my specific rands() problem. Not sure what the approach is in openSCAD2 to this ? As for me - looks like I need to make a long list of random numbers from a seed (yay rands()) and then cycle through that list in my own random function which gets called many times in many places. -- View this message in context: http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16296.html Sent from the OpenSCAD mailing list archive at Nabble.com.
MK
Marius Kintel
Sun, Mar 6, 2016 7:06 PM

On Mar 5, 2016, at 06:01 AM, Neon22 mschafer@wireframe.biz wrote:

Even though it looks to me like randcyl() should be evaluated only once
(when children passed in) - its called twice.

From the top of my head, this sounds like a bug. I’ll have to look into it in more detail, and I’ve opened an issue for this: https://github.com/openscad/openscad/issues/1596

-Marius

> On Mar 5, 2016, at 06:01 AM, Neon22 <mschafer@wireframe.biz> wrote: > > Even though it looks to me like randcyl() should be evaluated only once > (when children passed in) - its called twice. From the top of my head, this sounds like a bug. I’ll have to look into it in more detail, and I’ve opened an issue for this: https://github.com/openscad/openscad/issues/1596 -Marius
RP
Ronaldo Persiano
Sun, Mar 6, 2016 10:06 PM

Neon22, I think you misunderstood the way rands operates with seeds. I had
the same misunderstanding the first time I tried to use it.

If you run the code:

echo(randn(n=1000, myseed=10));
echo(randn(n=1000, myseed=10));

the console will show two identical echos. That is: each time you run
rands(0,1,1, myseed)[0] you will receive the exact same number for each
myseed. The seed in rands is useful just in a random series of numbers: the
series will be the same for each seed.

So, to be useful, generate the entire random number series at once (or as
many series you need) and access a random number by the list indexing. If a
seed is provided in the series generation, it will be repeated in the next
run. Otherwise, a new random series will be generated.

2016-03-06 16:06 GMT-03:00 Marius Kintel marius@kintel.net:

On Mar 5, 2016, at 06:01 AM, Neon22 mschafer@wireframe.biz wrote:

Even though it looks to me like randcyl() should be evaluated only once
(when children passed in) - its called twice.

From the top of my head, this sounds like a bug. I’ll have to look into it
in more detail, and I’ve opened an issue for this:
https://github.com/openscad/openscad/issues/1596

-Marius


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Neon22, I think you misunderstood the way rands operates with seeds. I had the same misunderstanding the first time I tried to use it. If you run the code: echo(randn(n=1000, myseed=10)); echo(randn(n=1000, myseed=10)); the console will show two identical echos. That is: each time you run rands(0,1,1, myseed)[0] you will receive the exact same number for each myseed. The seed in rands is useful just in a random series of numbers: the series will be the same for each seed. So, to be useful, generate the entire random number series at once (or as many series you need) and access a random number by the list indexing. If a seed is provided in the series generation, it will be repeated in the next run. Otherwise, a new random series will be generated. 2016-03-06 16:06 GMT-03:00 Marius Kintel <marius@kintel.net>: > > On Mar 5, 2016, at 06:01 AM, Neon22 <mschafer@wireframe.biz> wrote: > > > > Even though it looks to me like randcyl() should be evaluated only once > > (when children passed in) - its called twice. > > From the top of my head, this sounds like a bug. I’ll have to look into it > in more detail, and I’ve opened an issue for this: > https://github.com/openscad/openscad/issues/1596 > > -Marius > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
N
Neon22
Sun, Mar 6, 2016 11:08 PM

Actually I'm counting on the rands being generated the same with the same
seed.

  • This is standard behaviour for seeds and why they exist.

Once again - I am not showing ALL of the code just a snippet. If I post all
the code people wil get bored and not read it let alone understand all of
it.

The seed controlling mechanism dispayed in the second snippet is
specifically so I can override the default behaviour (new rand everytime) to
only get one value.
I use it to force symmetry in a model - see the very first post as to what
that's about.
However this "solution" is poor on many levels and NoGood.

What I need is:

  • a function which consumes a value from a list of presupplied (global)
    values.
  • One from list each time it is called.
    E.g.
    master_seed = 42;
    seeds = rands(0, 65535, rand_seq_length, master_seed);
    function rand(range) = ...;
  • which returns the 'next' value from the list called seeds each time it is
    called.

Does anyone know how to do this within a function or in any other way ??

--
View this message in context: http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Actually I'm counting on the rands being generated the same with the same seed. - This is standard behaviour for seeds and why they exist. Once again - I am not showing ALL of the code just a snippet. If I post all the code people wil get bored and not read it let alone understand all of it. The seed controlling mechanism dispayed in the second snippet is specifically so I can override the default behaviour (new rand everytime) to only get one value. I use it to force symmetry in a model - see the very first post as to what that's about. However this "solution" is poor on many levels and NoGood. What I need is: - a function which consumes a value from a list of presupplied (global) values. - One from list each time it is called. E.g. master_seed = 42; seeds = rands(0, 65535, rand_seq_length, master_seed); function rand(range) = ...; - which returns the 'next' value from the list called seeds each time it is called. Does anyone know how to do this within a function or in any other way ?? -- View this message in context: http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html Sent from the OpenSCAD mailing list archive at Nabble.com.
NH
nop head
Sun, Mar 6, 2016 11:47 PM

I don't believe you can define a function that returns different results
each time (other than with rands) as that would require it to hold some
mutable state that isn't allowed.

Really I don't think rand should be allowed in OpenScad. It should always
produce the same results each run.

Is the problem you have just with the m_mirror module or do you have other
cases where you need to repeat a call to rands? You could define $seed =
rands(...) in m_mirror() and then use $seed in the children to create
identical results. e.g.

module m_mirror() {
$seed = rands(0,1000000,1)[0];
children(0);
mirror([1,0,0])
children(0);
}
module cut_in_half(size)  {
intersection() {
translate([0, -size/2.0, -size/2.0])
cube(size=size, center=false);
children(0);
}
}

module randcyl() {
// use of rands in here shows this object being called twice
echo("randcyl called");
rotate([rands(0,77,1, $seed)[0],45,0])
cylinder(h=rands(4,8,1, $seed)[0], d = 2, center=true);
}

m_mirror() cut_in_half(100) render() randcyl();

This creates random angles and lengths that are the same in each child but
they are probably related to each other.

On 6 March 2016 at 23:08, Neon22 mschafer@wireframe.biz wrote:

Actually I'm counting on the rands being generated the same with the same
seed.

  • This is standard behaviour for seeds and why they exist.

Once again - I am not showing ALL of the code just a snippet. If I post all
the code people wil get bored and not read it let alone understand all of
it.

The seed controlling mechanism dispayed in the second snippet is
specifically so I can override the default behaviour (new rand everytime)
to
only get one value.
I use it to force symmetry in a model - see the very first post as to what
that's about.
However this "solution" is poor on many levels and NoGood.

What I need is:

  • a function which consumes a value from a list of presupplied (global)
    values.
  • One from list each time it is called.
    E.g.
    master_seed = 42;
    seeds = rands(0, 65535, rand_seq_length, master_seed);
    function rand(range) = ...;
  • which returns the 'next' value from the list called seeds each time it is
    called.

Does anyone know how to do this within a function or in any other way ??

--
View this message in context:
http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html
Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

I don't believe you can define a function that returns different results each time (other than with rands) as that would require it to hold some mutable state that isn't allowed. Really I don't think rand should be allowed in OpenScad. It should always produce the same results each run. Is the problem you have just with the m_mirror module or do you have other cases where you need to repeat a call to rands? You could define $seed = rands(...) in m_mirror() and then use $seed in the children to create identical results. e.g. module m_mirror() { $seed = rands(0,1000000,1)[0]; children(0); mirror([1,0,0]) children(0); } module cut_in_half(size) { intersection() { translate([0, -size/2.0, -size/2.0]) cube(size=size, center=false); children(0); } } module randcyl() { // use of rands in here shows this object being called twice echo("randcyl called"); rotate([rands(0,77,1, $seed)[0],45,0]) cylinder(h=rands(4,8,1, $seed)[0], d = 2, center=true); } m_mirror() cut_in_half(100) render() randcyl(); This creates random angles and lengths that are the same in each child but they are probably related to each other. On 6 March 2016 at 23:08, Neon22 <mschafer@wireframe.biz> wrote: > Actually I'm counting on the rands being generated the same with the same > seed. > - This is standard behaviour for seeds and why they exist. > > Once again - I am not showing ALL of the code just a snippet. If I post all > the code people wil get bored and not read it let alone understand all of > it. > > The seed controlling mechanism dispayed in the second snippet is > specifically so I can override the default behaviour (new rand everytime) > to > only get one value. > I use it to force symmetry in a model - see the very first post as to what > that's about. > However this "solution" is poor on many levels and NoGood. > > > What I need is: > - a function which consumes a value from a list of presupplied (global) > values. > - One from list each time it is called. > E.g. > master_seed = 42; > seeds = rands(0, 65535, rand_seq_length, master_seed); > function rand(range) = ...; > - which returns the 'next' value from the list called seeds each time it is > called. > > > Does anyone know how to do this within a function or in any other way ?? > > > > -- > View this message in context: > http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RP
Ronaldo Persiano
Sun, Mar 6, 2016 11:48 PM

I don't think there is any way to do it. All functions in OpenSCAD, except
rands or anything using rands, return the same value for the same given
parameters. This is the heart of no side effects. And the function you are
looking for doesn't use rands.

2016-03-06 20:08 GMT-03:00 Neon22 mschafer@wireframe.biz:

Actually I'm counting on the rands being generated the same with the same
seed.

  • This is standard behaviour for seeds and why they exist.

Once again - I am not showing ALL of the code just a snippet. If I post all
the code people wil get bored and not read it let alone understand all of
it.

The seed controlling mechanism dispayed in the second snippet is
specifically so I can override the default behaviour (new rand everytime)
to
only get one value.
I use it to force symmetry in a model - see the very first post as to what
that's about.
However this "solution" is poor on many levels and NoGood.

What I need is:

  • a function which consumes a value from a list of presupplied (global)
    values.
  • One from list each time it is called.
    E.g.
    master_seed = 42;
    seeds = rands(0, 65535, rand_seq_length, master_seed);
    function rand(range) = ...;
  • which returns the 'next' value from the list called seeds each time it is
    called.

Does anyone know how to do this within a function or in any other way ??

--
View this message in context:
http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html
Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

I don't think there is any way to do it. All functions in OpenSCAD, except rands or anything using rands, return the same value for the same given parameters. This is the heart of no side effects. And the function you are looking for doesn't use rands. 2016-03-06 20:08 GMT-03:00 Neon22 <mschafer@wireframe.biz>: > Actually I'm counting on the rands being generated the same with the same > seed. > - This is standard behaviour for seeds and why they exist. > > Once again - I am not showing ALL of the code just a snippet. If I post all > the code people wil get bored and not read it let alone understand all of > it. > > The seed controlling mechanism dispayed in the second snippet is > specifically so I can override the default behaviour (new rand everytime) > to > only get one value. > I use it to force symmetry in a model - see the very first post as to what > that's about. > However this "solution" is poor on many levels and NoGood. > > > What I need is: > - a function which consumes a value from a list of presupplied (global) > values. > - One from list each time it is called. > E.g. > master_seed = 42; > seeds = rands(0, 65535, rand_seq_length, master_seed); > function rand(range) = ...; > - which returns the 'next' value from the list called seeds each time it is > called. > > > Does anyone know how to do this within a function or in any other way ?? > > > > -- > View this message in context: > http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
NH
nop head
Sun, Mar 6, 2016 11:52 PM

module randcyl() {
// use of rands in here shows this object being called twice
echo("randcyl called");
rotate([rands(0,77,1, $seed)[0],45,0])
cylinder(h=rands(4,8,1, $seed + 1)[0], d = 2, center=true);
}

Seems to work better.

On 6 March 2016 at 23:48, Ronaldo Persiano rcmpersiano@gmail.com wrote:

I don't think there is any way to do it. All functions in OpenSCAD, except
rands or anything using rands, return the same value for the same given
parameters. This is the heart of no side effects. And the function you are
looking for doesn't use rands.

2016-03-06 20:08 GMT-03:00 Neon22 mschafer@wireframe.biz:

Actually I'm counting on the rands being generated the same with the same
seed.

  • This is standard behaviour for seeds and why they exist.

Once again - I am not showing ALL of the code just a snippet. If I post
all
the code people wil get bored and not read it let alone understand all of
it.

The seed controlling mechanism dispayed in the second snippet is
specifically so I can override the default behaviour (new rand everytime)
to
only get one value.
I use it to force symmetry in a model - see the very first post as to what
that's about.
However this "solution" is poor on many levels and NoGood.

What I need is:

  • a function which consumes a value from a list of presupplied (global)
    values.
  • One from list each time it is called.
    E.g.
    master_seed = 42;
    seeds = rands(0, 65535, rand_seq_length, master_seed);
    function rand(range) = ...;
  • which returns the 'next' value from the list called seeds each time it
    is
    called.

Does anyone know how to do this within a function or in any other way ??

--
View this message in context:
http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html
Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

module randcyl() { // use of rands in here shows this object being called twice echo("randcyl called"); rotate([rands(0,77,1, $seed)[0],45,0]) cylinder(h=rands(4,8,1, $seed + 1)[0], d = 2, center=true); } Seems to work better. On 6 March 2016 at 23:48, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > I don't think there is any way to do it. All functions in OpenSCAD, except > rands or anything using rands, return the same value for the same given > parameters. This is the heart of no side effects. And the function you are > looking for doesn't use rands. > > 2016-03-06 20:08 GMT-03:00 Neon22 <mschafer@wireframe.biz>: > >> Actually I'm counting on the rands being generated the same with the same >> seed. >> - This is standard behaviour for seeds and why they exist. >> >> Once again - I am not showing ALL of the code just a snippet. If I post >> all >> the code people wil get bored and not read it let alone understand all of >> it. >> >> The seed controlling mechanism dispayed in the second snippet is >> specifically so I can override the default behaviour (new rand everytime) >> to >> only get one value. >> I use it to force symmetry in a model - see the very first post as to what >> that's about. >> However this "solution" is poor on many levels and NoGood. >> >> >> What I need is: >> - a function which consumes a value from a list of presupplied (global) >> values. >> - One from list each time it is called. >> E.g. >> master_seed = 42; >> seeds = rands(0, 65535, rand_seq_length, master_seed); >> function rand(range) = ...; >> - which returns the 'next' value from the list called seeds each time it >> is >> called. >> >> >> Does anyone know how to do this within a function or in any other way ?? >> >> >> >> -- >> View this message in context: >> http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html >> Sent from the OpenSCAD mailing list archive at Nabble.com. >> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
DM
doug moen
Mon, Mar 7, 2016 12:56 AM

The problem I see is that OpenSCAD is designed to be a pure declarative
language, but rands() is designed with an interface that only works
properly in an imperative language. To resolve the mismatch, we either need
to turn OpenSCAD into an imperative language, which is essentially where
Neon22 is going with his questions, or we need to deprecate rands(), and
provide a declarative interface for generating random numbers.

In a declarative language, function and module calls are referentially
transparent: they are guaranteed to return the same value or shape if the
arguments are the same. Users don't worry about how many times a function
or module call is evaluated, and they don't worry about the order of
evaluation, because these things can't have any effect on the final
rendered shape. (Okay, these things might have an impact on performance,
but not on correctness.) This results in two benefits:

  1. It's easier for users to reason about the meaning of a program, and
    there are more ways that you can rearrange code without changing its
    meaning. Algebraic properties like the commutative and associate law are
    more useful in a declarative language. You can use algebraic reasoning on
    OpenSCAD scripts.
  2. The implementation has more latitude to optimize the code, by
    rearranging the evaluation order, caching values, merging common
    subexpressions, and evaluating things in parallel.

To get these benefits, we need a declarative interface for generating
random numbers, which I will call 'random()'.

Here's my design:

  • Each time the script is evaluated, a new random seed is generated.
    This is a global value, which has the name '$seed'. This is what happens
    today; what's new is that I've introduced the name '$seed'.
  • The first argument to random() is a list of numbers and strings, which
    acts as a 'signature' for the random number to be generated. The strings
    and numbers in the signature are hashed together with $seed, to produce a
    random number in the range [0...1], which is returned.
  • If you want a random number in the range 0...M, then you use
    random(sig)*M.
    • If you want N random numbers, then you include an index value in
      the signature list, which varies from 0 to N-1, and call random() N times.
  • You can optionally pass $seed as a dynamically scoped argument to
    random(), which overrides the default global value of $seed.

The signature argument is the key idea that makes this interface
declarative. If random() is called multiple times with the same signature
and seed, then the same value is returned.

In a typical use of random(), the signature array will contain a unique
string that identifies this particular use of random(), plus one (or maybe
more) numbers, if the calling function needs more than one random number.

Neon22's randcyl() module would be written like this:

module randcyl() {
rotate([random(["randcyl"])*77,45,0])
cylinder(h=4, d = 2, center=true);
}

With just this code, every call to randcyl() within a given script
evaluation will return the same shape, unless randcyl() is called with a
$seed argument, in which case different values of $seed will produce
different shapes.

If your script uses random(), then each time you hit F5 you'll get a
different shape. If you add
echo(seed=$seed);
to your script, then you'll see the the seed value used for this particular
evaluation. If you get a result that you want to preserve, then you can
copy the seed value into your script by writing
$seed = <desired seed value>;
at the top level of your script, and now the script will always produce the
same shape.

On 6 March 2016 at 18:08, Neon22 mschafer@wireframe.biz wrote:

Actually I'm counting on the rands being generated the same with the same
seed.

  • This is standard behaviour for seeds and why they exist.

Once again - I am not showing ALL of the code just a snippet. If I post all
the code people wil get bored and not read it let alone understand all of
it.

The seed controlling mechanism dispayed in the second snippet is
specifically so I can override the default behaviour (new rand everytime)
to
only get one value.
I use it to force symmetry in a model - see the very first post as to what
that's about.
However this "solution" is poor on many levels and NoGood.

What I need is:

  • a function which consumes a value from a list of presupplied (global)
    values.
  • One from list each time it is called.
    E.g.
    master_seed = 42;
    seeds = rands(0, 65535, rand_seq_length, master_seed);
    function rand(range) = ...;
  • which returns the 'next' value from the list called seeds each time it is
    called.

Does anyone know how to do this within a function or in any other way ??

--
View this message in context:
http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html
Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

The problem I see is that OpenSCAD is designed to be a pure declarative language, but rands() is designed with an interface that only works properly in an imperative language. To resolve the mismatch, we either need to turn OpenSCAD into an imperative language, which is essentially where Neon22 is going with his questions, or we need to deprecate rands(), and provide a declarative interface for generating random numbers. In a declarative language, function and module calls are referentially transparent: they are guaranteed to return the same value or shape if the arguments are the same. Users don't worry about how many times a function or module call is evaluated, and they don't worry about the order of evaluation, because these things can't have any effect on the final rendered shape. (Okay, these things might have an impact on performance, but not on correctness.) This results in two benefits: 1. It's easier for users to reason about the meaning of a program, and there are more ways that you can rearrange code without changing its meaning. Algebraic properties like the commutative and associate law are more useful in a declarative language. You can use algebraic reasoning on OpenSCAD scripts. 2. The implementation has more latitude to optimize the code, by rearranging the evaluation order, caching values, merging common subexpressions, and evaluating things in parallel. To get these benefits, we need a declarative interface for generating random numbers, which I will call 'random()'. Here's my design: - Each time the script is evaluated, a new random seed is generated. This is a global value, which has the name '$seed'. This is what happens today; what's new is that I've introduced the name '$seed'. - The first argument to random() is a list of numbers and strings, which acts as a 'signature' for the random number to be generated. The strings and numbers in the signature are hashed together with $seed, to produce a random number in the range [0...1], which is returned. - If you want a random number in the range 0...M, then you use random(sig)*M. - If you want N random numbers, then you include an index value in the signature list, which varies from 0 to N-1, and call random() N times. - You can optionally pass $seed as a dynamically scoped argument to random(), which overrides the default global value of $seed. The signature argument is the key idea that makes this interface declarative. If random() is called multiple times with the same signature and seed, then the same value is returned. In a typical use of random(), the signature array will contain a unique string that identifies this particular use of random(), plus one (or maybe more) numbers, if the calling function needs more than one random number. Neon22's randcyl() module would be written like this: module randcyl() { rotate([random(["randcyl"])*77,45,0]) cylinder(h=4, d = 2, center=true); } With just this code, every call to randcyl() within a given script evaluation will return the same shape, unless randcyl() is called with a $seed argument, in which case different values of $seed will produce different shapes. If your script uses random(), then each time you hit F5 you'll get a different shape. If you add echo(seed=$seed); to your script, then you'll see the the seed value used for this particular evaluation. If you get a result that you want to preserve, then you can copy the seed value into your script by writing $seed = <desired seed value>; at the top level of your script, and now the script will always produce the same shape. On 6 March 2016 at 18:08, Neon22 <mschafer@wireframe.biz> wrote: > Actually I'm counting on the rands being generated the same with the same > seed. > - This is standard behaviour for seeds and why they exist. > > Once again - I am not showing ALL of the code just a snippet. If I post all > the code people wil get bored and not read it let alone understand all of > it. > > The seed controlling mechanism dispayed in the second snippet is > specifically so I can override the default behaviour (new rand everytime) > to > only get one value. > I use it to force symmetry in a model - see the very first post as to what > that's about. > However this "solution" is poor on many levels and NoGood. > > > What I need is: > - a function which consumes a value from a list of presupplied (global) > values. > - One from list each time it is called. > E.g. > master_seed = 42; > seeds = rands(0, 65535, rand_seq_length, master_seed); > function rand(range) = ...; > - which returns the 'next' value from the list called seeds each time it is > called. > > > Does anyone know how to do this within a function or in any other way ?? > > > > -- > View this message in context: > http://forum.openscad.org/children-and-extra-unwanted-evaluations-tp16291p16306.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > >