Re: L-system rules with PicoLisp

2017-03-04 Thread Lindsay John Lawrence
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

2017-03-03 Thread Alexander Burger
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

2017-03-03 Thread Lindsay John Lawrence
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

2017-03-03 Thread Lindsay John Lawrence
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

2017-03-03 Thread Joh-Tob Schäg
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

2017-03-03 Thread 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

2017-03-03 Thread Alexander Burger
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

2017-03-03 Thread 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.
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)))

Re: L-system rules with PicoLisp

2017-03-03 Thread 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 (msg (text "?Gosper-Curve: No-match: @1" @))) )) C )
>
>) )
>
>
>