discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Programming in Functional OpenSCAD

DM
doug moen
Tue, Jan 30, 2018 11:29 PM

It may be possible to use some purely functional data structures in
OpenSCAD. Unlike the 2-3 tree, these data structures are designed to be
efficient in a language with only immutable objects.

https://en.wikipedia.org/wiki/Purely_functional_data_structure

OpenSCAD is missing some language features needed by some functional data
structures, but maybe this is a starting point.

On 30 January 2018 at 18:22, Ronaldo Persiano rcmpersiano@gmail.com wrote:

The question is how to build things like Delaunay triangulation when
needed. You can't do it without the support of a complex data structure.

2018-01-30 21:16 GMT-02:00 doug moen doug@moens.org:

OpenSCAD uses references to reference-counted, immutable values. Multiple
variables can point to the same immutable list object. There is no need for
OpenSCAD to make copies of lists, since there are no operations for
mutating a list. AFAIK; I haven't read all the code in the interpreter.

I don't think there's much point in worrying about this, though. Like
Ronaldo says, just use the simplest possible data structure. If this leads
to a performance problem, and you want to use a more complicated data
structure, you should measure the performance to ensure that the more
complicated code is actually faster. OpenSCAD doesn't have the same
performance characteristics as conventional languages, so your complicated
code might be slower.

It may be possible to use some purely functional data structures in OpenSCAD. Unlike the 2-3 tree, these data structures are designed to be efficient in a language with only immutable objects. https://en.wikipedia.org/wiki/Purely_functional_data_structure OpenSCAD is missing some language features needed by some functional data structures, but maybe this is a starting point. On 30 January 2018 at 18:22, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > The question is how to build things like Delaunay triangulation when > needed. You can't do it without the support of a complex data structure. > > 2018-01-30 21:16 GMT-02:00 doug moen <doug@moens.org>: > >> OpenSCAD uses references to reference-counted, immutable values. Multiple >> variables can point to the same immutable list object. There is no need for >> OpenSCAD to make copies of lists, since there are no operations for >> mutating a list. AFAIK; I haven't read all the code in the interpreter. >> >> I don't think there's much point in worrying about this, though. Like >> Ronaldo says, just use the simplest possible data structure. If this leads >> to a performance problem, and you want to use a more complicated data >> structure, you should measure the performance to ensure that the more >> complicated code is actually faster. OpenSCAD doesn't have the same >> performance characteristics as conventional languages, so your complicated >> code might be slower. >> > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
N
NateTG
Tue, Jan 30, 2018 11:59 PM

OpenSCAD uses references to reference-counted, immutable values. Multiple

variables can point to the same immutable list object. There is no need for
OpenSCAD to make copies of lists, since there are no operations for mutating
a list. AFAIK; I haven't read all the code in the interpreter.

The 2-3 tree implementation should only replace the nodes on the insertion
or removal path which should individually take a fixed amount of time.  I
don't understand how it will take O( N^2 ) time and would really like to
understand.  (Even if OpenSCAD is copying the lists every time, it seems
like it should be at worst O(N (log N)^2).)

--
Sent from: http://forum.openscad.org/

> OpenSCAD uses references to reference-counted, immutable values. Multiple variables can point to the same immutable list object. There is no need for OpenSCAD to make copies of lists, since there are no operations for mutating a list. AFAIK; I haven't read all the code in the interpreter. The 2-3 tree implementation should only replace the nodes on the insertion or removal path which should individually take a fixed amount of time. I don't understand how it will take O( N^2 ) time and would really like to understand. (Even if OpenSCAD is copying the lists every time, it seems like it should be at worst O(N (log N)^2).) -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Wed, Jan 31, 2018 10:46 AM

Under my initial hyphotesis that copies are made, an insertion or deletion
from a 2-3 tree with N element would be O(N). And to build a tree from
scratch the time would be O(N^2). It is hard to get good time estimates
with the OpenSCAD system but I got worst than linear time building trees by
insertion of 2500-30000 elements.

To minimize stack overflows I have used the tail recursive versions:

function treeinsert(tree,value)=
(0==len(tree))?
[value]  :
(treeinsertiterate(tree,value))[1] ;

function treeinsertlisti(tr,list,i)=
(i==0)?
treeinsert(tr,list[0]) :
treeinsertlisti(treeinsert(tr,list[i]),list,i-1)  ;

BTW, your insertion code does not deal well with some sequences having
repeated values.

ECHO: foo = [40, 57, 65, 14, 65, 80, 82, 65]

ECHO: bar = [[14, 40], 57, [65], 80, [65]]

2018-01-30 21:59 GMT-02:00 NateTG nate-openscadforum@pedantic.org:

OpenSCAD uses references to reference-counted, immutable values. Multiple

variables can point to the same immutable list object. There is no need for
OpenSCAD to make copies of lists, since there are no operations for
mutating
a list. AFAIK; I haven't read all the code in the interpreter.

The 2-3 tree implementation should only replace the nodes on the insertion
or removal path which should individually take a fixed amount of time.  I
don't understand how it will take O( N^2 ) time and would really like to
understand.  (Even if OpenSCAD is copying the lists every time, it seems
like it should be at worst O(N (log N)^2).)

--
Sent from: http://forum.openscad.org/


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

Under my initial hyphotesis that copies are made, an insertion or deletion from a 2-3 tree with N element would be O(N). And to build a tree from scratch the time would be O(N^2). It is hard to get good time estimates with the OpenSCAD system but I got worst than linear time building trees by insertion of 2500-30000 elements. To minimize stack overflows I have used the tail recursive versions: function treeinsert(tree,value)= (0==len(tree))? [value] : (treeinsertiterate(tree,value))[1] ; function treeinsertlisti(tr,list,i)= (i==0)? treeinsert(tr,list[0]) : treeinsertlisti(treeinsert(tr,list[i]),list,i-1) ; BTW, your insertion code does not deal well with some sequences having repeated values. ECHO: foo = [40, 57, 65, 14, 65, 80, 82, 65] ECHO: bar = [[14, 40], 57, [65], 80, [65]] 2018-01-30 21:59 GMT-02:00 NateTG <nate-openscadforum@pedantic.org>: > > OpenSCAD uses references to reference-counted, immutable values. Multiple > variables can point to the same immutable list object. There is no need for > OpenSCAD to make copies of lists, since there are no operations for > mutating > a list. AFAIK; I haven't read all the code in the interpreter. > > The 2-3 tree implementation should only replace the nodes on the insertion > or removal path which should individually take a fixed amount of time. I > don't understand how it will take O( N^2 ) time and would really like to > understand. (Even if OpenSCAD is copying the lists every time, it seems > like it should be at worst O(N (log N)^2).) > > > > > > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
N
NateTG
Wed, Jan 31, 2018 2:30 PM

Under my initial hyphotesis that copies are made, an insertion or deletion

from a 2-3 tree with N element would be O(N). And to build a tree from
scratch the time would be O(N^2).

Those are both totally plausible to me.  I may have misunderstood this:

For instance, the element insertion and re​moving from  2-3 trees have
order O(log n). However, an analysis of your implementation in OpenSCAD
will show that its order of complexity is O(n2) or worst due to the
repeated structure copies required by  any change in it.

Where I thought the claim was that a single insertion was O(N^2).

I got worst than linear time building trees by insertion of 2500-30000
elements.

Building a tree from N elements is expected to take O(N log N) time - which
is worse than linear.

To minimize stack overflows I have used the tail recursive versions:
...
BTW, your insertion code does not deal well with some sequences having
repeated values.

Thanks for that info.  I still don't really understand the "this tail
recurses" thing.

--
Sent from: http://forum.openscad.org/

> Under my initial hyphotesis that copies are made, an insertion or deletion from a 2-3 tree with N element would be O(N). And to build a tree from scratch the time would be O(N^2). Those are both totally plausible to me. I may have misunderstood this: > For instance, the element insertion and re​moving from 2-3 trees have > order O(log n). However, an analysis of your implementation in OpenSCAD > will show that its order of complexity is O(n2) or worst due to the > repeated structure copies required by any change in it. Where I thought the claim was that a single insertion was O(N^2). > I got worst than linear time building trees by insertion of 2500-30000 > elements. Building a tree from N elements is expected to take O(N log N) time - which is worse than linear. > To minimize stack overflows I have used the tail recursive versions: > ... > BTW, your insertion code does not deal well with some sequences having > repeated values. Thanks for that info. I still don't really understand the "this tail recurses" thing. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Wed, Jan 31, 2018 3:31 PM

​ Where I thought the claim was that a single insertion was O(N^2).


​Yes, I mixed things up.​

I still don't really understand the "this tail

​ ​
recurses" thing.

> > ​ Where I thought the claim was that a single insertion was O(N^2). ​ ​Yes, I mixed things up.​ I still don't really understand the "this tail > ​ ​ > recurses" thing. > <goog_634797904> ​ https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/User-Defined_Functions_and_Modules#Recursive_functions ​ *http://forum.openscad.org/Tail-recursion-td17040.html* <http://forum.openscad.org/Tail-recursion-td17040.html> ​
TG
Tony Godshall
Wed, Jan 31, 2018 6:09 PM

I still don't really understand the "this tail
recurses" thing.

From a language user point of view, it can be ignored.

From an optimization point of view, conventional calls

and returns stack up and grow the stack, but a tail return
can avoid putting a redundant return on the stack.

Another way to think about it is a recursive call can be
a goto, and not grow the stack.

--

Best Regards.
This is unedited.
This message came out of me
via a suboptimal keyboard.

>> I still don't really understand the "this tail >> recurses" thing. >From a language user point of view, it can be ignored. >From an optimization point of view, conventional calls and returns stack up and grow the stack, but a tail return can avoid putting a redundant return on the stack. Another way to think about it is a recursive call can be a goto, and not grow the stack. -- -- Best Regards. This is unedited. This message came out of me via a suboptimal keyboard.
N
NateTG
Wed, Jan 31, 2018 6:22 PM

I understand what tail recursion is. I'm just not confident about when or how
it gets applied in OpenSCAD.

From a language user point of view, it can be ignored.

It would be nice if that were true, but the nature of OpenSCAD means that
things can easily get stack constrained. even when they are working
properly.  For example, Ronaldo didn't modify the tree insertion function
for some aesthetic reason but rather because stack overflows were a
practical issue.

--
Sent from: http://forum.openscad.org/

I understand what tail recursion is. I'm just not confident about when or how it gets applied in OpenSCAD. > From a language user point of view, it can be ignored. It would be nice if that were true, but the nature of OpenSCAD means that things can easily get stack constrained. even when they are working properly. For example, Ronaldo didn't modify the tree insertion function for some aesthetic reason but rather because stack overflows were a practical issue. -- Sent from: http://forum.openscad.org/
DM
doug moen
Wed, Jan 31, 2018 6:33 PM

"I understand what tail recursion is. I'm just not confident about when or
how
it gets applied in OpenSCAD."

The tail recursion optimization is only applied in two very specific
circumstances. It is not implemented in a general way.

The first case:

function f(x) = shouldExit ? result : f(...);

Note that there is a tail recursive function call after the :

The second case:

function f(x) = keepGoing ? f(...) : result;

Note that there is a tail recursive function call between ? and :

The body of the function must match one of the two patterns. If you change
these patterns in any way (eg, add a 'let' to define local variables), then
the pattern no longer matches, and tail recursion optimization is not
applied.

On 31 January 2018 at 13:22, NateTG nate-openscadforum@pedantic.org wrote:

I understand what tail recursion is. I'm just not confident about when or
how
it gets applied in OpenSCAD.

From a language user point of view, it can be ignored.

It would be nice if that were true, but the nature of OpenSCAD means that
things can easily get stack constrained. even when they are working
properly.  For example, Ronaldo didn't modify the tree insertion function
for some aesthetic reason but rather because stack overflows were a
practical issue.

--
Sent from: http://forum.openscad.org/


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

"I understand what tail recursion is. I'm just not confident about when or how it gets applied in OpenSCAD." The tail recursion optimization is only applied in two very specific circumstances. It is not implemented in a general way. The first case: function f(x) = shouldExit ? result : f(...); Note that there is a tail recursive function call after the : The second case: function f(x) = keepGoing ? f(...) : result; Note that there is a tail recursive function call between ? and : The body of the function must match one of the two patterns. If you change these patterns in any way (eg, add a 'let' to define local variables), then the pattern no longer matches, and tail recursion optimization is not applied. On 31 January 2018 at 13:22, NateTG <nate-openscadforum@pedantic.org> wrote: > I understand what tail recursion is. I'm just not confident about when or > how > it gets applied in OpenSCAD. > > > From a language user point of view, it can be ignored. > > It would be nice if that were true, but the nature of OpenSCAD means that > things can easily get stack constrained. even when they are working > properly. For example, Ronaldo didn't modify the tree insertion function > for some aesthetic reason but rather because stack overflows were a > practical issue. > > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RP
Ronaldo Persiano
Wed, Jan 31, 2018 7:56 PM

Not always it is easy to write a tail recursion qualified to elimination.
And  sometimes it is possible to avoid the recursion at all using a C-like
for enabled in a snapshot version. The treeinsertlist(() function, for
instance, may be rewritten iteractively as:

function treeinsertlist(tree,list) =
[for(i=len(list), tr=tree; i>=0; i=i-1, tr = treeinsert(tr,list[i]) )
if(i==0) tr ][0];

I am not an advocate of this form that is not easily grasped, but a complex
tail recursion elimination form may be also hard to read.

2018-01-31 16:33 GMT-02:00 doug moen doug@moens.org:

"I understand what tail recursion is. I'm just not confident about when
or how
it gets applied in OpenSCAD."

The tail recursion optimization is only applied in two very specific
circumstances. It is not implemented in a general way.

The first case:

 function f(x) = shouldExit ? result : f(...);

Note that there is a tail recursive function call after the :

The second case:

 function f(x) = keepGoing ? f(...) : result;

Note that there is a tail recursive function call between ? and :

The body of the function must match one of the two patterns. If you change
these patterns in any way (eg, add a 'let' to define local variables), then
the pattern no longer matches, and tail recursion optimization is not
applied.

On 31 January 2018 at 13:22, NateTG nate-openscadforum@pedantic.org
wrote:

I understand what tail recursion is. I'm just not confident about when or
how
it gets applied in OpenSCAD.

From a language user point of view, it can be ignored.

It would be nice if that were true, but the nature of OpenSCAD means that
things can easily get stack constrained. even when they are working
properly.  For example, Ronaldo didn't modify the tree insertion function
for some aesthetic reason but rather because stack overflows were a
practical issue.

--
Sent from: http://forum.openscad.org/


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

Not always it is easy to write a tail recursion qualified to elimination. And sometimes it is possible to avoid the recursion at all using a C-like *for* enabled in a snapshot version. The treeinsertlist(() function, for instance, may be rewritten iteractively as: function treeinsertlist(tree,list) = [for(i=len(list), tr=tree; i>=0; i=i-1, tr = treeinsert(tr,list[i]) ) if(i==0) tr ][0]; I am not an advocate of this form that is not easily grasped, but a complex tail recursion elimination form may be also hard to read. 2018-01-31 16:33 GMT-02:00 doug moen <doug@moens.org>: > "I understand what tail recursion is. I'm just not confident about when > or how > it gets applied in OpenSCAD." > > The tail recursion optimization is only applied in two very specific > circumstances. It is not implemented in a general way. > > The first case: > > function f(x) = shouldExit ? result : f(...); > > Note that there is a tail recursive function call after the : > > The second case: > > function f(x) = keepGoing ? f(...) : result; > > Note that there is a tail recursive function call between ? and : > > The body of the function must match one of the two patterns. If you change > these patterns in any way (eg, add a 'let' to define local variables), then > the pattern no longer matches, and tail recursion optimization is not > applied. > > On 31 January 2018 at 13:22, NateTG <nate-openscadforum@pedantic.org> > wrote: > >> I understand what tail recursion is. I'm just not confident about when or >> how >> it gets applied in OpenSCAD. >> >> > From a language user point of view, it can be ignored. >> >> It would be nice if that were true, but the nature of OpenSCAD means that >> things can easily get stack constrained. even when they are working >> properly. For example, Ronaldo didn't modify the tree insertion function >> for some aesthetic reason but rather because stack overflows were a >> practical issue. >> >> >> >> >> >> -- >> Sent from: http://forum.openscad.org/ >> >> _______________________________________________ >> 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 > >
TP
Torsten Paul
Wed, Jan 31, 2018 7:57 PM

The tail recursion optimization is only applied in two very specific
circumstances. It is not implemented in a general way.

Do you have any pointers to documentation about how to implement tail
recursion or how it's implemented in some language?

I was searching for that some time ago and there's lots of discussion
about how to use tail recursion but not so much about how to actually
implement it.

ciao,
Torsten.

> The tail recursion optimization is only applied in two very specific > circumstances. It is not implemented in a general way. > Do you have any pointers to documentation about how to implement tail recursion or how it's implemented in some language? I was searching for that some time ago and there's lots of discussion about how to use tail recursion but not so much about how to actually implement it. ciao, Torsten.