Re: L-system rules with PicoLisp
Thanks Alex, I appreciate the suggestions. As ever, I learn something from them ;) /Lindsay On Fri, Mar 3, 2017 at 10:10 PM, Alexander Burger wrote: > Hi Lindsay, > > > The code below is the recursive Gosper implementation I came up with that > > uses very little stack. This version just emits states. > > ... > > Picolisp continues to impress me with its expressiveness and power. > > As ever, I can't resist to suggest some optimizations :) > > > > (de Plot (L) > >(map '((X) (prin (car X))) L) ) > > (mapc prin L) would be enough. > > > > (de Fn (L) > >(let R > > (fish > > atom > > (mapcar > > '((X) > >(cond > > ((= X "A") A) > > ((= X "B") B) > > (T X) ) ) > > L ) ) > > R ) ) > > The 'let' is not necessary, as R is never used. And 'fish' is for nested > structures, a flat list can be handled directly e.g. with 'filter' or > 'extract' > >(extract '((X) (cond ((pair X)) ((=X "A") A) ..)) L) > > As 'A' and 'B' are free variables here, 'Fn' should be named differently, > starting with an underscrore (see doc/ref.html#conv)). You coud try 'lint' > or > 'lintAll' to see what it complains. > > The PicoLisp naming conventions also recommend upper case first letters for > locally bound variables. Functions defined globally like 'Plot' or 'Fn' > should > better start in lower case. > > > > (de L-Run (L D) > >(cond > > ((>= D MaxDepth) (Plot L)) > > (T > > Here an 'if' is shorter than a 'cond'. > > ♪♫ Alex > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe >
Re: L-system rules with PicoLisp
Hi Lindsay, > The code below is the recursive Gosper implementation I came up with that > uses very little stack. This version just emits states. > ... > Picolisp continues to impress me with its expressiveness and power. As ever, I can't resist to suggest some optimizations :) > (de Plot (L) >(map '((X) (prin (car X))) L) ) (mapc prin L) would be enough. > (de Fn (L) >(let R > (fish > atom > (mapcar > '((X) >(cond > ((= X "A") A) > ((= X "B") B) > (T X) ) ) > L ) ) > R ) ) The 'let' is not necessary, as R is never used. And 'fish' is for nested structures, a flat list can be handled directly e.g. with 'filter' or 'extract' (extract '((X) (cond ((pair X)) ((=X "A") A) ..)) L) As 'A' and 'B' are free variables here, 'Fn' should be named differently, starting with an underscrore (see doc/ref.html#conv)). You coud try 'lint' or 'lintAll' to see what it complains. The PicoLisp naming conventions also recommend upper case first letters for locally bound variables. Functions defined globally like 'Plot' or 'Fn' should better start in lower case. > (de L-Run (L D) >(cond > ((>= D MaxDepth) (Plot L)) > (T Here an 'if' is shorter than a 'cond'. ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: L-system rules with PicoLisp
Thanks Alex, Your explanation was the motivation I needed to attempt the recursive version... /Lindsay > Yes and no. It is correct that the garbage collector does not run at each > release. Instead, it runs when a new cell is needed and the current heap is > found to be full. > > So garbage collection is indeed "immediate", in that as long as there is > free > memory no collection is needed, and if not, the collector runs (typically > just a > few milliseconds). > > If after a collection still no cells are available, the heap is increased. > Therefore, if a program slowly allocates more and more memory, it helps > intially > to allocate a bigger heap, e.g. (gc 800) or whatever size is needed in the > long > run. >
Re: L-system rules with PicoLisp
Hi Alex, Joh-Tob, A 'co may be exactly what I am looking for in this case. Thanks! Generating all the states at once was nice in one sense as I could immediately scale the view when rendering the results. Picolisp easily supported lists of ~2M elements on the 4GB, single-core virtual box I am currently using. The code below is the recursive Gosper implementation I came up with that uses very little stack. This version just emits states. It should be easy to adapt to other L-systems, but doesn't yet have the state management needed to 'grow' fractal plants. If you want to "space-fill" ( https://en.wikipedia.org/wiki/Space-filling_curve) your hard drive with a Gosper, or similar, curve... This will do it for you ;) : (out "test.dat" (nil (GosperR 10))) : (call 'ls "-l") -rw-r--r-- 1 llawrence llawrence 659108913 Mar 3 14:58 test.dat Just counting the state changes emitted... : (bench (nil (GosperR 10)) (msg (text "EmitCount: @1" EmitCount))) "EmitCount: 659108913" 50.547 sec : (bench (nil (GosperR 11)) (msg (text "EmitCount: @1" EmitCount))) "EmitCount: 4613762399" 348.925 sec Picolisp continues to impress me with its expressiveness and power. /Lindsay # ## # Recursive L-system emitter (de Plot (L) (map '((X) (prin (car X))) L) ) (de Fn (L) (let R (fish atom (mapcar '((X) (cond ((= X "A") A) ((= X "B") B) (T X) ) ) L ) ) R ) ) (de L-Run (L D) (cond ((>= D MaxDepth) (Plot L)) (T (map '((X) (L-Run (Fn (list (car X))) (inc D)) ) L ) ) ) ) (de GosperR (MaxDepth) (let (A (chop "A-B--B+A++AA+B-") B (chop "+A-BB--B-A++A+B")) (default MaxDepth 2) (L-Run A 1) ) ) On Fri, Mar 3, 2017 at 11:04 AM, Alexander Burger wrote: > On Fri, Mar 03, 2017 at 01:39:25PM +0100, Joh-Tob Schäg wrote: > > I haven't figured out how to do it yet, but I think, in this case, a > > 'recursive' solution that renders as points are created would use a lot > > less resources, assuming that processed replacement rules are garbage > > collected as the stack unwinds and elements are traversed over. > > > > This sound like a case for 'co > > Makes sense probably. > > ♪♫ Alex > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe >
Re: L-system rules with PicoLisp
Makes sense probably. The greatest compliment i received in months. 2017-03-03 20:04 GMT+01:00 Alexander Burger : > On Fri, Mar 03, 2017 at 01:39:25PM +0100, Joh-Tob Schäg wrote: > > I haven't figured out how to do it yet, but I think, in this case, a > > 'recursive' solution that renders as points are created would use a lot > > less resources, assuming that processed replacement rules are garbage > > collected as the stack unwinds and elements are traversed over. > > > > This sound like a case for 'co > > Makes sense probably. > > ♪♫ Alex > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe >
Re: L-system rules with PicoLisp
On Fri, Mar 03, 2017 at 01:39:25PM +0100, Joh-Tob Schäg wrote: > I haven't figured out how to do it yet, but I think, in this case, a > 'recursive' solution that renders as points are created would use a lot > less resources, assuming that processed replacement rules are garbage > collected as the stack unwinds and elements are traversed over. > > This sound like a case for 'co Makes sense probably. ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: L-system rules with PicoLisp
Hi Lindsay, Joh-Tob, On Fri, Mar 03, 2017 at 12:47:12PM +0100, Joh-Tob Schäg wrote: > > Is the garbage collection in picolisp immediate if the resource can be > > released? > > No, picolisp uses a mark and sweep halt the world garage collector. During > sweep phase the complete allocated RAM is checked. If that would happen > after each release of a resource picolisp would be very slow. Yes and no. It is correct that the garbage collector does not run at each release. Instead, it runs when a new cell is needed and the current heap is found to be full. So garbage collection is indeed "immediate", in that as long as there is free memory no collection is needed, and if not, the collector runs (typically just a few milliseconds). If after a collection still no cells are available, the heap is increased. Therefore, if a program slowly allocates more and more memory, it helps intially to allocate a bigger heap, e.g. (gc 800) or whatever size is needed in the long run. ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: L-system rules with PicoLisp
Mhh it seems that my answer is not relevant to your question. I haven't figured out how to do it yet, but I think, in this case, a 'recursive' solution that renders as points are created would use a lot less resources, assuming that processed replacement rules are garbage collected as the stack unwinds and elements are traversed over. This sound like a case for 'co 2017-03-03 13:32 GMT+01:00 Joh-Tob Schäg : > > The initial iterative replacement solution I came up with (below) quickly > runs out of resources as it has to build the entire list before starting to > draw. > > What error did you get? > How much resources does picolisp use? > Do you call ulimit before? > > > I think you may have some fundamental problems with garabarage allocation
Re: L-system rules with PicoLisp
The initial iterative replacement solution I came up with (below) quickly runs out of resources as it has to build the entire list before starting to draw. What error did you get? How much resources does picolisp use? Do you call ulimit before? I think you may have some fundamental problems with garabarage allocation. Please see if you understand that code. (de expensive-list-increaser (A N) (default N 1) (prinl "call: " N) (if A (cons (+ 1 (car A)) (expensive-list-increaser (copy (prinl (cdr A))) (inc N (prinl "A of " N " is no no longer refernced after the function number " N " returns") @@) (de compreku (D) (expensive-list-increaser (range 1 D)) Picolisp can not garbage collect A of the first call until all other are finished since the first A could be needed inside first call at a later point. This is related to PicoLisp not having tail recursion. You also need to understand that 'mapcar and 'map returns a new list not the old one modified. This means you create a copy of the list with each mapcar the longest of which is only cleared after the first recursive call is finished. (de compiter (D) (for ( N . A) (range 1 D) (prinl "call: " N) (prinl (copy A)) (prinl "The copy of A is no longer accessible so it can be deallocated"))) # : (compreku 5) call: 1 2345 call: 2 345 call: 3 45 call: 4 5 call: 5 call: 6 A of 6 is no no longer refernced after the function number 6 returns A of 5 is no no longer refernced after the function number 5 returns A of 4 is no no longer refernced after the function number 4 returns A of 3 is no no longer refernced after the function number 3 returns A of 2 is no no longer refernced after the function number 2 returns Y A of 1 is no no longer refernced after the function number 1 returns #: (compiter 5) call: 1 1 The copy of A is no longer accessible so it can be deallocated call: 2 2 The copy of A is no longer accessible so it can be deallocated call: 3 3 The copy of A is no longer accessible so it can be deallocated call: 4 4 The copy of A is no longer accessible so it can be deallocated call: 5 5 The copy of A is no longer accessible so it can be deallocated 2017-03-03 12:47 GMT+01:00 Joh-Tob Schäg : > Is the garbage collection in picolisp immediate if the resource can be > released? > > No, picolisp uses a mark and sweep halt the world garage collector. During > sweep phase the complete allocated RAM is checked. If that would happen > after each release of a resource picolisp would be very slow. > Furthermore in Picolisp it is not possible to decide whether a resource > can be released or not with out doing mark and sweep. This is because of > cyclic list and the fact that you could always have a symbol pointing to > that cell. > > > > 2017-03-03 12:04 GMT+01:00 Lindsay John Lawrence < > lawrence.lindsayj...@gmail.com>: > >> >> Is the garbage collection in picolisp immediate if the resource can be >> released? >> >> The initial iterative replacement solution I came up with (below) quickly >> runs out of resources as it has to build the entire list before starting to >> draw. >> >> I haven't figured out how to do it yet, but I think, in this case, a >> 'recursive' solution that renders as points are created would use a lot >> less resources, assuming that processed replacement rules are garbage >> collected as the stack unwinds and elements are traversed over. >> >> It would be a nice accomplishment to be able to render the more complex >> fractal plants expressed here: https://en.wikipedia.org/wiki/L-system >> >> /Lindsay >> >> >> # https://en.wikipedia.org/wiki/Gosper_curve >> # Angle 60 degrees = PI/3 >> # Axiom A >> # Replacement Rules >> # A :--> A - B - - B + A + + A A + B - >> # B :--> + A - B B - - B - A + + A + B >> >> # C (initially = A) grows...very quickly. >> #: n=0 (length C) -> 15 >> #: n=1 (length (setq C (F C))) -> 113 >> #: n=2 -> 799, n=3 -> 5601, n=4 -> 39215, n=5 -> 274513, n=6 -> 1921599, >> n=7 . >> >> # For n=6... >> : (bench (nil (Draw-Gosper-Curve))) >> -> 1.370 sec >> >> Which works out to: >> >> XY Cnt: 823543 coordinates to plot >> Min-XY: -66,432.00 -42,345.11 >> Max-XY: 2,048.00 23,611.35" >> >> ...about 900K of serialized canvas instructions. >> >> >> Full-code at: https://github.com/thinknlive/picolisp-gosper >> >> (de Gosper-Curve (Length Angle N) >>(let >> (A (chop "A-B--B+A++AA+B-") >> B (chop "+A-BB--B-A++A+B") >> C A >> F '((L) (fish atom >> (mapcar '((X) >> (cond >> ((= X "A") A) >> ((= X "B") B) >> (T X))) L))) ) >> >> >> # Generate points >> (do N (setq C (F C))) >> >> # Plot points >> (map '((R) >> (case (car R) >> (("A" "B") (Plot-Line Length Angle)) >> ("+" (setq Angle (+ Angle PI/3))) >> ("-" (setq Angle (- Angle PI/3))) >> (T (ms
Re: L-system rules with PicoLisp
Is the garbage collection in picolisp immediate if the resource can be released? No, picolisp uses a mark and sweep halt the world garage collector. During sweep phase the complete allocated RAM is checked. If that would happen after each release of a resource picolisp would be very slow. Furthermore in Picolisp it is not possible to decide whether a resource can be released or not with out doing mark and sweep. This is because of cyclic list and the fact that you could always have a symbol pointing to that cell. 2017-03-03 12:04 GMT+01:00 Lindsay John Lawrence < lawrence.lindsayj...@gmail.com>: > > Is the garbage collection in picolisp immediate if the resource can be > released? > > The initial iterative replacement solution I came up with (below) quickly > runs out of resources as it has to build the entire list before starting to > draw. > > I haven't figured out how to do it yet, but I think, in this case, a > 'recursive' solution that renders as points are created would use a lot > less resources, assuming that processed replacement rules are garbage > collected as the stack unwinds and elements are traversed over. > > It would be a nice accomplishment to be able to render the more complex > fractal plants expressed here: https://en.wikipedia.org/wiki/L-system > > /Lindsay > > > # https://en.wikipedia.org/wiki/Gosper_curve > # Angle 60 degrees = PI/3 > # Axiom A > # Replacement Rules > # A :--> A - B - - B + A + + A A + B - > # B :--> + A - B B - - B - A + + A + B > > # C (initially = A) grows...very quickly. > #: n=0 (length C) -> 15 > #: n=1 (length (setq C (F C))) -> 113 > #: n=2 -> 799, n=3 -> 5601, n=4 -> 39215, n=5 -> 274513, n=6 -> 1921599, > n=7 . > > # For n=6... > : (bench (nil (Draw-Gosper-Curve))) > -> 1.370 sec > > Which works out to: > > XY Cnt: 823543 coordinates to plot > Min-XY: -66,432.00 -42,345.11 > Max-XY: 2,048.00 23,611.35" > > ...about 900K of serialized canvas instructions. > > > Full-code at: https://github.com/thinknlive/picolisp-gosper > > (de Gosper-Curve (Length Angle N) >(let > (A (chop "A-B--B+A++AA+B-") > B (chop "+A-BB--B-A++A+B") > C A > F '((L) (fish atom > (mapcar '((X) > (cond > ((= X "A") A) > ((= X "B") B) > (T X))) L))) ) > > > # Generate points > (do N (setq C (F C))) > > # Plot points > (map '((R) > (case (car R) > (("A" "B") (Plot-Line Length Angle)) > ("+" (setq Angle (+ Angle PI/3))) > ("-" (setq Angle (- Angle PI/3))) > (T (msg (text "?Gosper-Curve: No-match: @1" @))) )) C ) > >) ) > > >