Based on a Java program ( http://tinyurl.com/57smz ) I've implemented a
Lisp program for showing the Mandelbrot set:
(loop for y from -1 to 1.1 by 0.1 do
(loop for x from -2 to 1 by 0.04 do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (< (abs
(setq z (+ (* z z) a)))
2)
while (> (decf c) 32))
(princ (code-char c))))
(format t "~%"))
I tried to make it as short as possible and it is some chars shorter than
the Java program, if written in one line without much spaces. With CLISP,
the program is only 4 times slower than the Java program. Nice result, I
didn't expect this with my unoptimized program and using complex variables.
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Frank Buss wrote:
> Based on a Java program ( http://tinyurl.com/57smz ) I've implemented a
> Lisp program for showing the Mandelbrot set:
>
> (loop for y from -1 to 1.1 by 0.1 do
> (loop for x from -2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> while (> (decf c) 32))
> (princ (code-char c))))
> (format t "~%"))
> ...
And a scheme version:
(define (mandel)
(do ((y -1 (+ y 0.1))) ((> y 1))
(do ((x -2 (+ x 0.04))) ((> x 1))
(let ((a (make-rectangular x y)))
(let loop ((z a) (c 126))
(let ((q (+ a (* z z))))
(if (and (< (magnitude q) 2) (> c 32))
(loop q (sub1 c))
(display (integer->char c)))))))
(newline)))
Aziz,,,
Abdulaziz Ghuloum <········@c-s-remove-dashes.indiana.edu> wrote in message news:<············@hood.uits.indiana.edu>...
> And a scheme version:
>
> (define (mandel)
> (do ((y -1 (+ y 0.1))) ((> y 1))
> (do ((x -2 (+ x 0.04))) ((> x 1))
> (let ((a (make-rectangular x y)))
> (let loop ((z a) (c 126))
> (let ((q (+ a (* z z))))
> (if (and (< (magnitude q) 2) (> c 32))
> (loop q (sub1 c))
> (display (integer->char c)))))))
> (newline)))
I really should get back to my CL version that does images. My movie
is still on my website. But that was done with a combination of Perl
and C.
http://www.david-steuber.com/~david/fractal-movie/
On Fri, 30 Jul 2004 21:39:05 +0000 (UTC), Frank Buss <··@frank-buss.de> wrote:
> Based on a Java program ( http://tinyurl.com/57smz ) I've
> implemented a Lisp program for showing the Mandelbrot set:
>
> (loop for y from -1 to 1.1 by 0.1 do
> (loop for x from -2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> while (> (decf c) 32))
> (princ (code-char c))))
> (format t "~%"))
>
> I tried to make it as short as possible and it is some chars shorter
> than the Java program, if written in one line without much
> spaces. With CLISP, the program is only 4 times slower than the Java
> program. Nice result, I didn't expect this with my unoptimized
> program and using complex variables.
If I change it a little bit
(defun mandel ()
(loop for y from -1 to 1.1 by 0.1 do
(loop for x from -2 to 1 by 0.04 do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (code-char c))))
(princ #\Newline)))
and compile it with CMUCL (19a-pre3) then it's actually faster by a
factor of 1.3 than the Java (1.5.0-beta2) version on my
laptop. Cool... :)
--
"Lisp doesn't look any deader than usual to me."
(David Thornley, reply to a question older than most languages)
Real email: (replace (subseq ·········@agharta.de" 5) "edi")
Edi Weitz <········@agharta.de> writes:
> On Fri, 30 Jul 2004 21:39:05 +0000 (UTC), Frank Buss <··@frank-buss.de> wrote:
>
>> Based on a Java program ( http://tinyurl.com/57smz ) I've
>> implemented a Lisp program for showing the Mandelbrot set:
>>
>> (loop for y from -1 to 1.1 by 0.1 do
>> (loop for x from -2 to 1 by 0.04 do
>> (let* ((c 126)
>> (z (complex x y))
>> (a z))
>> (loop while (< (abs
>> (setq z (+ (* z z) a)))
>> 2)
>> while (> (decf c) 32))
>> (princ (code-char c))))
>> (format t "~%"))
>>
>> I tried to make it as short as possible and it is some chars shorter
>> than the Java program, if written in one line without much
>> spaces. With CLISP, the program is only 4 times slower than the Java
>> program. Nice result, I didn't expect this with my unoptimized
>> program and using complex variables.
>
> If I change it a little bit
>
> (defun mandel ()
> (loop for y from -1 to 1.1 by 0.1 do
> (loop for x from -2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (and (< (abs
> (setq z (+ (* z z) a)))
> 2)
> (> (decf c) 32)))
> (princ (code-char c))))
> (princ #\Newline)))
>
> and compile it with CMUCL (19a-pre3) then it's actually faster by a
> factor of 1.3 than the Java (1.5.0-beta2) version on my
> laptop. Cool... :)
Man, that's rad! Just pasted that puppy in my REPL and boom! ASCII art
Mandlebrot. Nice.
-Peter
--
Peter Seibel ·····@javamonkey.com
Lisp is the red pill. -- John Fraser, comp.lang.lisp
Peter Seibel <·····@javamonkey.com> wrote in message news:<··············@javamonkey.com>...
> Edi Weitz <········@agharta.de> writes:
>
> > On Fri, 30 Jul 2004 21:39:05 +0000 (UTC), Frank Buss <··@frank-buss.de> wrote:
> >
> >> Based on a Java program ( http://tinyurl.com/57smz ) I've
> >> implemented a Lisp program for showing the Mandelbrot set:
> >>
> >> (loop for y from -1 to 1.1 by 0.1 do
> >> (loop for x from -2 to 1 by 0.04 do
> >> (let* ((c 126)
> >> (z (complex x y))
> >> (a z))
> >> (loop while (< (abs
> >> (setq z (+ (* z z) a)))
> >> 2)
> >> while (> (decf c) 32))
> >> (princ (code-char c))))
> >> (format t "~%"))
> >>
> >> I tried to make it as short as possible and it is some chars shorter
> >> than the Java program, if written in one line without much
> >> spaces. With CLISP, the program is only 4 times slower than the Java
> >> program. Nice result, I didn't expect this with my unoptimized
> >> program and using complex variables.
> >
> > If I change it a little bit
> >
> > (defun mandel ()
> > (loop for y from -1 to 1.1 by 0.1 do
> > (loop for x from -2 to 1 by 0.04 do
> > (let* ((c 126)
> > (z (complex x y))
> > (a z))
> > (loop while (and (< (abs
> > (setq z (+ (* z z) a)))
> > 2)
> > (> (decf c) 32)))
> > (princ (code-char c))))
> > (princ #\Newline)))
> >
> > and compile it with CMUCL (19a-pre3) then it's actually faster by a
> > factor of 1.3 than the Java (1.5.0-beta2) version on my
> > laptop. Cool... :)
>
> Man, that's rad! Just pasted that puppy in my REPL and boom! ASCII art
> Mandlebrot. Nice.
>
> -Peter
Very cool. How did you get the ascii characters though? I don't see
them anywhere in the code. All I see that might even have something to
do with it is
(princ (code-char c))))
--
May the Source be with you.
neo88 (Philip Haddad)
······@truevine.net (neo88) wrote in message news:<····························@posting.google.com>...
> Peter Seibel <·····@javamonkey.com> wrote in message news:<··············@javamonkey.com>...
> > Edi Weitz <········@agharta.de> writes:
[...]
> > > If I change it a little bit
> > >
> > > (defun mandel ()
> > > (loop for y from -1 to 1.1 by 0.1 do
> > > (loop for x from -2 to 1 by 0.04 do
> > > (let* ((c 126)
> > > (z (complex x y))
> > > (a z))
> > > (loop while (and (< (abs
> > > (setq z (+ (* z z) a)))
> > > 2)
> > > (> (decf c) 32)))
> > > (princ (code-char c))))
> > > (princ #\Newline)))
> > >
> > > and compile it with CMUCL (19a-pre3) then it's actually faster by a
> > > factor of 1.3 than the Java (1.5.0-beta2) version on my
> > > laptop. Cool... :)
> >
> > Man, that's rad! Just pasted that puppy in my REPL and boom! ASCII art
> > Mandlebrot. Nice.
> >
> > -Peter
>
> Very cool. How did you get the ascii characters though? I don't see
> them anywhere in the code. All I see that might even have something to
> do with it is
> (princ (code-char c))))
Yes. code-char/char-code is not specified to have anything to do with
ASCII, but i guess you can assume it does in most non-brain-damaged
implementations.
··········@pvk.ca (pkhuong) writes:
> > Very cool. How did you get the ascii characters though? I don't see
> > them anywhere in the code. All I see that might even have something to
> > do with it is
> > (princ (code-char c))))
> Yes. code-char/char-code is not specified to have anything to do with
> ASCII, but i guess you can assume it does in most non-brain-damaged
> implementations.
The first ASCII art were done in EBCDIC!
--
__Pascal Bourguignon__ http://www.informatimago.com/
There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein
neo88 asked:
> Very cool. How did you get the ascii characters though? I
> don't see them anywhere in the code. All I see that might
> even have something to do with it is
>
> (princ (code-char c))
Spot the magic numbers 32 and 126
(char-code #\space) => 32
(char-code #\~) => 126
the code commits itself to the ASCII character set.
--
Alan Crowe
Edinburgh
Scotland
i'm not sure how the algorithm is supposed to be
selecting the character to display, but it does not
seem very adapatable if i try to zoom in on the
boundary of the mandelbrot set.
Here is my attempt to allow the user to zoom
in on various parts of the picture.
After each drawing you can select a quadrant to
zoom into
|
2 | 1
|
------+------
|
3 | 4
|
However, as you zoom it does not seem to show
any extra detail. Is there something wrong with
my function?
(defun mandel ()
(let (( x0 -2.0)
( y0 -1.0)
( x1 1.0)
( y1 1.1)
midx
midy
)
(loop while t do
(window x0 y0 x1 y1)
(setf midx (/ (+ x1 x0) 2.0)
midy (/ (+ y1 y0) 2.0))
(format t "quadrant: ")
(multiple-value-setq ( x0 y0 x1 y1 )
(case (read)
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))))
(defun window ( x0 y0 x1 y1)
(let (( dx (/ (- x1 x0) 30.0))
( dy (/ (- y1 y0) 30.0)))
(format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
x0 y0 x1 y1 dx dy)
(loop for y from y0 to y1 by dy do
(loop for x from x0 to x1 by dx do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (code-char c))))
(princ #\Newline))))
Jim Newton <·····@rdrop.com> wrote:
> i'm not sure how the algorithm is supposed to be
> selecting the character to display, but it does not
> seem very adapatable if i try to zoom in on the
> boundary of the mandelbrot set.
>
> Here is my attempt to allow the user to zoom
> in on various parts of the picture.
>
> After each drawing you can select a quadrant to
> zoom into
>
> |
> 2 | 1
> |
> ------+------
> |
> 3 | 4
> |
>
> However, as you zoom it does not seem to show
> any extra detail. Is there something wrong with
> my function?
works well on my computer. But the quadrants are mirrored at the y-axis,
because you test at negative y coordinates first. Try this:
4322321221121243141341
This zooms 1 : 4,000,000, but after the last '1' the program ended in an
endless loop, because looks like my floating point precision is limited
to 8 significant digits with your program.
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
you can now call (mandel...) with the zoom
quadrants
e.g., (mandel 2 4 1 1)
after the zooming, it goes into interactive mode.
Yes there seems to be a limitation around dx=1e-8...
curious.
-jim
(defun mandel ( &rest quadrants)
(let (( x0 -2.0)
( y0 -2.0)
( x1 2.0)
( y1 2.0))
(dolist ( q quadrants)
(multiple-value-setq ( x0 y0 x1 y1 )
(select-quadrant q x0 y0 x1 y1 )))
(loop while t do
(draw-quadrant x0 y0 x1 y1)
(format t "quadrant: ")
(multiple-value-setq ( x0 y0 x1 y1 )
(select-quadrant (read) x0 y0 x1 y1)))))
(defun select-quadrant ( q x0 y0 x1 y1)
(let (( midx (/ (+ x1 x0) 2.0))
( midy (/ (+ y1 y0) 2.0)))
(case q
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))
(defun draw-quadrant ( x0 y0 x1 y1)
(let (( dx (/ (- x1 x0) 30.0))
( dy (/ (- y1 y0) 30.0)))
(format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
x0 y0 x1 y1 dx dy)
(princ "2")
(loop for x from x0 to x1 by dx do
(princ "-"))
(princ "1")
(princ #\Newline)
(loop for y from y1 downto y0 by dy do
(princ "|")
(loop for x from x0 to x1 by dx do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (code-char c))))
(princ "|")
(princ #\Newline))
(princ "3")
(loop for x from x0 to x1 by dx do
(princ "-"))
(princ "4")
(princ #\Newline)))
(compile 'mandel)
(compile 'select-quadrant)
(compile 'draw-quadrant)
(mandel)
Frank Buss wrote:
> Jim Newton <·····@rdrop.com> wrote:
>
>
>>i'm not sure how the algorithm is supposed to be
>>selecting the character to display, but it does not
>>seem very adapatable if i try to zoom in on the
>>boundary of the mandelbrot set.
>>
>>Here is my attempt to allow the user to zoom
>>in on various parts of the picture.
>>
>>After each drawing you can select a quadrant to
>>zoom into
>>
>> |
>> 2 | 1
>> |
>>------+------
>> |
>> 3 | 4
>> |
>>
>>However, as you zoom it does not seem to show
>>any extra detail. Is there something wrong with
>>my function?
>
>
> works well on my computer. But the quadrants are mirrored at the y-axis,
> because you test at negative y coordinates first. Try this:
>
> 4322321221121243141341
>
> This zooms 1 : 4,000,000, but after the last '1' the program ended in an
> endless loop, because looks like my floating point precision is limited
> to 8 significant digits with your program.
>
Jim Newton <·····@rdrop.com> wrote:
> you can now call (mandel...) with the zoom
> quadrants
>
> e.g., (mandel 2 4 1 1)
>
> after the zooming, it goes into interactive mode.
> Yes there seems to be a limitation around dx=1e-8...
> curious.
you can replace all numbers with double-floats, then you can go until
dx= double-float-epsilon (something around 1d-16 on my computer) and then
this works:
(mandel 1 3 2 3 2 3 3 4 1 1 4 4 1 3 3 1 3 3 3 1 4 4 4 1 3 4 4 4 3 3 3 4 3
4 2 3 4 4 1 1 2 4 3)
Zooming 1:8796093022208. That's like zooming from the earth fullscreen to
a flake of one hair of a person fullscreen :-)
(defun mandel ( &rest quadrants)
(let (( x0 -2d0)
( y0 -2d0)
( x1 2d0)
( y1 2d0))
(dolist ( q quadrants)
(multiple-value-setq ( x0 y0 x1 y1 )
(select-quadrant q x0 y0 x1 y1 )))
(loop while t do
(draw-quadrant x0 y0 x1 y1)
(format t "quadrant: ")
(multiple-value-setq ( x0 y0 x1 y1 )
(select-quadrant (read) x0 y0 x1 y1)))))
(defun select-quadrant ( q x0 y0 x1 y1)
(let (( midx (/ (+ x1 x0) 2d0))
( midy (/ (+ y1 y0) 2d0)))
(case q
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))
(defun draw-quadrant ( x0 y0 x1 y1)
(let (( dx (/ (- x1 x0) 30d0))
( dy (/ (- y1 y0) 30d0)))
(format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
x0 y0 x1 y1 dx dy)
(princ "2")
(loop for x from x0 to x1 by dx do
(princ "-"))
(princ "1")
(princ #\Newline)
(loop for y from y1 downto y0 by dy do
(princ "|")
(loop for x from x0 to x1 by dx do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (code-char c))))
(princ "|")
(princ #\Newline))
(princ "3")
(loop for x from x0 to x1 by dx do
(princ "-"))
(princ "4")
(princ #\Newline)))
(compile 'mandel)
(compile 'select-quadrant)
(compile 'draw-quadrant)
(mandel)
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Jim Newton <·····@rdrop.com> wrote:
> does complex do something different if you
> give it two double floats? i.e., is there a
> difference between (complex 1.0 1.0) and (complex 1d0 1d0)
yes. If I'm doing this in CLISP:
(expt (/ (complex 1 1) 1e30) 2)
I got a SIMPLE-FLOATING-POINT-UNDERFLOW error, but if I do this:
(expt (/ (complex 1d0 1d0) 1e30) 2)
I got #C(0.0d0 1.9999999398101364d-60) (and a warning, which is not
generated if I use 1d30 instead of 1e30).
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
ahh i see the problem... the current implementation
draws the quadrants with the y axis inverted.
|
3 | 4
|
------+------
|
2 | 1
|
i've modified the code to decrement y instead of increment.
and it seems to work well... except that
when dx or dy becomes in the range of dx=1.5894572e-8 dy=1.5894572e-8
very strange things happen... i wonder is this a problem with
percision on the x86?
x0=-0.04844904 y0=0.80464506 x1=-0.048448563 y1=0.80464554
dx=1.5894572e-8 dy=1.5894572e-8
give it a try...
(defun mandel ()
(let (( x0 -2.0) ;;( x0 -2.0)
( y0 -2.0) ;;( y0 -1.0)
( x1 2.0) ;;( x1 1.0)
( y1 2.0) ;;( y1 1.1)
midx
midy
)
(loop while t do
(window x0 y0 x1 y1)
(setf midx (/ (+ x1 x0) 2.0)
midy (/ (+ y1 y0) 2.0))
(format t "quadrant: ")
(multiple-value-setq ( x0 y0 x1 y1 )
(case (read)
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))))
(defun window ( x0 y0 x1 y1)
(let (( dx (/ (- x1 x0) 30.0))
( dy (/ (- y1 y0) 30.0)))
(format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
x0 y0 x1 y1 dx dy)
(princ "2")
(loop for x from x0 to x1 by dx do
(princ "-"))
(princ "1")
(princ #\Newline)
(loop for y from y1 downto y0 by dy do
(princ "|")
(loop for x from x0 to x1 by dx do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (code-char c))))
(princ "|")
(princ #\Newline))
(princ "3")
(loop for x from x0 to x1 by dx do
(princ "-"))
(princ "4")
(princ #\Newline)))
(compile 'mandel)
(compile 'window)
(mandel)
-jim
Jim Newton wrote:
> i'm not sure how the algorithm is supposed to be
> selecting the character to display, but it does not
> seem very adapatable if i try to zoom in on the
> boundary of the mandelbrot set.
>
> Here is my attempt to allow the user to zoom
> in on various parts of the picture.
>
> After each drawing you can select a quadrant to
> zoom into
>
> |
> 2 | 1
> |
> ------+------
> |
> 3 | 4
> |
>
> However, as you zoom it does not seem to show
> any extra detail. Is there something wrong with
> my function?
>
> (defun mandel ()
> (let (( x0 -2.0)
> ( y0 -1.0)
> ( x1 1.0)
> ( y1 1.1)
> midx
> midy
> )
> (loop while t do
> (window x0 y0 x1 y1)
> (setf midx (/ (+ x1 x0) 2.0)
> midy (/ (+ y1 y0) 2.0))
> (format t "quadrant: ")
> (multiple-value-setq ( x0 y0 x1 y1 )
> (case (read)
> ( 1 (values midx midy x1 y1))
> ( 2 (values x0 midy midx y1))
> ( 3 (values x0 y0 midx midy))
> ( 4 (values midx y0 x1 midy))
> ( t (values x0 y0 x1 y1)))))))
>
> (defun window ( x0 y0 x1 y1)
> (let (( dx (/ (- x1 x0) 30.0))
> ( dy (/ (- y1 y0) 30.0)))
> (format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
> x0 y0 x1 y1 dx dy)
>
> (loop for y from y0 to y1 by dy do
> (loop for x from x0 to x1 by dx do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (and (< (abs
> (setq z (+ (* z z) a)))
> 2)
> (> (decf c) 32)))
> (princ (code-char c))))
> (princ #\Newline))))
>
On Sat, 31 Jul 2004 00:08:54 +0200, Edi Weitz <········@agharta.de> wrote:
> If I change it a little bit
>
> (defun mandel ()
> (loop for y from -1 to 1.1 by 0.1 do
> (loop for x from -2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (and (< (abs
> (setq z (+ (* z z) a)))
> 2)
> (> (decf c) 32)))
> (princ (code-char c))))
> (princ #\Newline)))
>
> and compile it with CMUCL (19a-pre3) then it's actually faster by a
> factor of 1.3 than the Java (1.5.0-beta2) version on my
> laptop. Cool... :)
Faster even if you start cheating a little:
(defun mandel ()
(loop for y from -1 to 1.1 by 0.1 do
(loop for x from -2 to 1 by 0.04 do
(let* ((z (complex x y))
(a z))
(loop for c in '#.(loop for c downfrom 126 above 32
collect (code-char c))
while (< (abs
(setq z (+ (* z z) a)))
2)
finally (princ c))))
(princ #\Newline)))
But I'll stop now... :)
--
"Lisp doesn't look any deader than usual to me."
(David Thornley, reply to a question older than most languages)
Real email: (replace (subseq ·········@agharta.de" 5) "edi")
Edi Weitz <········@agharta.de> wrote:
> (loop for c in '#.(loop for c downfrom 126 above 32
> collect (code-char c))
this is really nice, I didn't know the reader macros before.
Ok, and now with TGA output, in the size of my screen for a new wallpaper
(see http://www.frank-buss.de/tmp/mandelbrot.jpg for a quality reduced
version). The program finished in 346 seconds run time, but that's mainly
because the algorithm is not optimized. There is a recursive algorithm
which calculates only 4 border points of a rectangle and fills it, if it
has the same color, which should reduce the running time to less than 10
seconds, I think, because most time the algorithm is spending in the
black area.
(defun mandelbrot ()
(let* ((width 1600)
(height 1024)
(x0 0.25)
(y0 0.5)
(x1 0.43)
(y1 0.71)
(image
(make-array (list width height 3)
:element-type '(unsigned-byte 8)
:initial-element 0)))
(loop for y from 0 to (1- height) do
(loop for x from 0 to (1- width) do
(let* ((c 60)
(z (complex
(float (+ (* (- x1 x0) (/ x width)) x0))
(float (+ (* (- y1 y0) (/ y height)) y0))))
(a z))
(loop while (and (< (square
(setq z (+ (* z z) a)))
4)
(> (decf c) 0)))
(if (> c 0) (progn
(setf (aref image x y 0)
(mod (* 4 c) 256))
(setf (aref image x y 1)
(mod (* 8 c) 256))
(setf (aref image x y 2)
(mod (* 13 c) 256)))))))
(write-tga image "mandelbrot.tga")))
(defun square (z)
(+ (* (realpart z) (realpart z)) (* (imagpart z) (imagpart z))))
(defun write-tga (image filename)
(let* ((dimension (array-dimensions image))
(width (nth 0 dimension))
(height (nth 1 dimension)))
(with-open-file
(tga filename
:direction :output
:if-exists :supersede
:element-type 'unsigned-byte)
(dolist (byte (list 0 0 2 0 0 0 0 0 0 0 0 0
(mod width 256) (floor width 256)
(mod height 256) (floor height 256) 24 0))
(write-byte byte tga))
(loop for y from 0 to (1- height) do
(loop for x from 0 to (1- width) do
(write-byte (aref image x y 0) tga)
(write-byte (aref image x y 1) tga)
(write-byte (aref image x y 2) tga))))))
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Frank Buss <··@frank-buss.de> wrote in message news:<············@newsreader2.netcologne.de>...
> Edi Weitz <········@agharta.de> wrote:
>
> > (loop for c in '#.(loop for c downfrom 126 above 32
> > collect (code-char c))
>
> this is really nice, I didn't know the reader macros before.
>
> Ok, and now with TGA output, in the size of my screen for a new wallpaper
> (see http://www.frank-buss.de/tmp/mandelbrot.jpg for a quality reduced
> version). The program finished in 346 seconds run time, but that's mainly
> because the algorithm is not optimized.
346 seconds = 5 min 46 seconds. I ran this program for about seven
minutes I'd say, on CMUCL 18e, and all it did was call the GC
endlessly until I intruppted it from Emacs. I also tried it in Allegro
CL Trial, and it instantly overflowed the allowed GC allocation.
There is a recursive algorithm
> which calculates only 4 border points of a rectangle and fills it, if it
> has the same color, which should reduce the running time to less than 10
> seconds, I think, because most time the algorithm is spending in the
> black area.
>
> (defun mandelbrot ()
> (let* ((width 1600)
> (height 1024)
> (x0 0.25)
> (y0 0.5)
> (x1 0.43)
> (y1 0.71)
> (image
> (make-array (list width height 3)
> :element-type '(unsigned-byte 8)
> :initial-element 0)))
> (loop for y from 0 to (1- height) do
> (loop for x from 0 to (1- width) do
> (let* ((c 60)
> (z (complex
> (float (+ (* (- x1 x0) (/ x width)) x0))
> (float (+ (* (- y1 y0) (/ y height)) y0))))
> (a z))
> (loop while (and (< (square
> (setq z (+ (* z z) a)))
> 4)
> (> (decf c) 0)))
> (if (> c 0) (progn
> (setf (aref image x y 0)
> (mod (* 4 c) 256))
> (setf (aref image x y 1)
> (mod (* 8 c) 256))
> (setf (aref image x y 2)
> (mod (* 13 c) 256)))))))
> (write-tga image "mandelbrot.tga")))
>
> (defun square (z)
> (+ (* (realpart z) (realpart z)) (* (imagpart z) (imagpart z))))
>
> (defun write-tga (image filename)
> (let* ((dimension (array-dimensions image))
> (width (nth 0 dimension))
> (height (nth 1 dimension)))
> (with-open-file
> (tga filename
> :direction :output
> :if-exists :supersede
> :element-type 'unsigned-byte)
> (dolist (byte (list 0 0 2 0 0 0 0 0 0 0 0 0
> (mod width 256) (floor width 256)
> (mod height 256) (floor height 256) 24 0))
> (write-byte byte tga))
> (loop for y from 0 to (1- height) do
> (loop for x from 0 to (1- width) do
> (write-byte (aref image x y 0) tga)
> (write-byte (aref image x y 1) tga)
> (write-byte (aref image x y 2) tga))))))
So does this write a tga file to the directory that the program is in,
so that you can open it later, or does it write the file directly to
the screen?
--
May the Source be with you.
neo88 (Philip Haddad)
······@truevine.net (neo88) wrote:
> 346 seconds = 5 min 46 seconds. I ran this program for about seven
> minutes I'd say, on CMUCL 18e, and all it did was call the GC
> endlessly until I intruppted it from Emacs. I also tried it in Allegro
> CL Trial, and it instantly overflowed the allowed GC allocation.
in CMUCL you should try (compile 'mandelbrot) and (compile 'square) first,
it greatly enhances the speed. And you can reduce the output size by
reducing the 1600x1024 size.
> So does this write a tga file to the directory that the program is in,
> so that you can open it later, or does it write the file directly to
> the screen?
it writes it in the current working directory. Perhaps you should write
somthing like "/tmp/mandelbrot.tga" to write it to a place you know where
it is.
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
On 1 Aug 2004 06:15:10 -0700, ······@truevine.net (neo88) wrote:
> 346 seconds = 5 min 46 seconds. I ran this program for about seven
> minutes I'd say, on CMUCL 18e, and all it did was call the GC
> endlessly until I intruppted it from Emacs.
Did you compile it?
--
"Lisp doesn't look any deader than usual to me."
(David Thornley, reply to a question older than most languages)
Real email: (replace (subseq ·········@agharta.de" 5) "edi")
Edi Weitz:
> (defun mandel ()
> (loop for y from -1 to 1.1 by 0.1 do
> (loop for x from -2 to 1 by 0.04 do
> (let* ((z (complex x y))
> (a z))
> (loop for c in '#.(loop for c downfrom 126 above 32
> collect (code-char c))
> while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> finally (princ c))))
> (princ #\Newline)))
>
Not the final iteration:
(loop for y from -1 to 1.1 by 0.1 do
(loop for x from -2 to 1 by 0.04 do
(loop with a = (complex x y)
for z = a then (+ (* z z) a)
for c in '#.(loop for c downfrom 126 downto 32
collect (code-char c))
while (< (* z (conjugate z) 4)
finally (princ c)))
(princ #\Newline))
> But I'll stop now... :)
--
"Brown the leaves, gray the sky, the horizont - white."
-- Unknown
Frank Buss <··@frank-buss.de> writes:
> Based on a Java program ( http://tinyurl.com/57smz ) I've implemented a
> Lisp program for showing the Mandelbrot set:
>
> (loop for y from -1 to 1.1 by 0.1 do
> (loop for x from -2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> while (> (decf c) 32))
> (princ (code-char c))))
> (format t "~%"))
(...)
... and an Emacs Lisp version:
(require 'cl)
(defun comp-mult (a b) ; a and b are lists (x y) corresponding to x + yi
(list (- (* (car a) (car b))
(* (cadr a) (cadr b)))
(+ (* (car a) (cadr b))
(* (cadr a) (car b)))))
(defun comp-add (z1 z2)
(list (+ (car z1) (car z2))
(+ (cadr z1) (cadr z2))))
(defun comp-abs (z)
(sqrt (+ (* (car z) (car z))
(* (cadr z) (cadr z)))))
(let* ((buffer-name (get-buffer-create "*Mandelbrot*")))
(switch-to-buffer buffer-name)
(erase-buffer)
(loop for y from -1 to 1.1 by 0.1 do
(loop for x from -2 to 1 by 0.04 do
(let* ((c 126)
(z (list x y))
(a z))
(loop while (< (comp-abs
(setq z (comp-add (comp-mult z z) a)))
2)
while (> (decf c) 32))
(insert (princ (make-char 'ascii c)))))
(newline)))
I had to create some helper functions for handling the complex
values. I guess I could've used the calc package's functions
concerning complex numbers, but they looked awkward to use without
running the calculator as far as I could see. Besides, not all use
the calc package anyway.
Eivind L. Rygge
Oslo, Norway
PS! First post in comp.lang.lisp :-)
Hello to all who attended the Lisp & Scheme Workshop here in Oslo this summer.
······@hotmail.com (Eivind L. Rygge) writes:
> ... and an Emacs Lisp version:
>
> (require 'cl)
>
> ; a and b are lists (x y) corresponding to x + yi
Why not mere cons cells?
(defun realpart (c) (car c))
(defun imagpart (c) (cdr c))
(defun complex (r &optional (i 0)) (cons r i))
Or, slightly less COMMON-LISP, but slightly more efficient:
(defmacro realpart (c) `(car ,c))
(defmacro imagpart (c) `(cdr ,c))
(defmacro complex (r &optional (i 0)) `(cons ,r ,i))
> (defun comp-mult (a b)
> (list (- (* (car a) (car b))
> (* (cadr a) (cadr b)))
> (+ (* (car a) (cadr b))
> (* (cadr a) (car b)))))
(defun c* (&rest args)
(reduce (lambda (a b)
(complex (- (* (realpart a)(realpart b))
(* (imagpart a)(imagpart b)))
(+ (* (realpart a)(imagpart b))
(* (imagpart a)(realpart b)))))
args
:inital-value (complex 1 0)))
> (defun comp-add (z1 z2)
> (list (+ (car z1) (car z2))
> (+ (cadr z1) (cadr z2))))
(defun c+ (&rest args)
(reduce (lambda (a b)
(complex (+ (realpart a)(realpart b))
(+ (imagpart a)(imagpart b))))
args
:inital-value (complex 0 0)))
> (defun comp-abs (z)
> (sqrt (+ (* (car z) (car z))
> (* (cadr z) (cadr z)))))
(defun cabs (c)
(sqrt (+ (* (realpart c)(realpart c))
(* (imagpart c)(imagpart c)))))
> (let* ((buffer-name (get-buffer-create "*Mandelbrot*")))
> (switch-to-buffer buffer-name)
> (erase-buffer)
> (loop for y from -1 to 1.1 by 0.1 do
> (loop for x from -2 to 1 by 0.04 do
> (let* ((c 126)
> (z (list x y))
> (a z))
> (loop while (< (comp-abs
> (setq z (comp-add (comp-mult z z) a)))
> 2)
> while (> (decf c) 32))
> (insert (princ (make-char 'ascii c)))))
> (newline)))
>
>
> I had to create some helper functions for handling the complex
> values. I guess I could've used the calc package's functions
> concerning complex numbers, but they looked awkward to use without
> running the calculator as far as I could see. Besides, not all use
> the calc package anyway.
>
> Eivind L. Rygge
> Oslo, Norway
>
> PS! First post in comp.lang.lisp :-)
> Hello to all who attended the Lisp & Scheme Workshop here in Oslo this summer.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.
* Eivind L. Rygge <······@hotmail.com>:
> ... and an Emacs Lisp version:
<URL:http://www.gnusoftware.com/Emacs/Lisp/mandel.el> might be of interest.
--
Dave Pearson
http://www.davep.org/lisp/
Eivind L. Rygge wrote:
> PS! First post in comp.lang.lisp :-)
> Hello to all who attended the Lisp & Scheme Workshop here in Oslo this summer.
Hi. ;)
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."