For Programmers: Free Programming Magazines  


Home > Archive > Scheme > August 2005 > Ray tracer









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Ray tracer
Jon Harrop

2005-08-04, 10:02 pm


Hi!

I am interested in Scheme and was wondering if anyone here would be kind
enough to port my ray tracer from one of its other languages (C++, Java,
SML and OCaml) to Scheme:

http://www.ffconsultancy.com/free/r.../languages.html

I am interested in short or fast implementations. In particular, I would
like to see how well Scheme does compared to the other languages. Also, I'm
using Linux so I'd like code than I can compile with a free compiler for
benchmarking.

Here is the shortest implementation that I have come up with so far (42
lines of OCaml):

open List
let ( *| ) s = map (( *. ) s) and ( +| ) = map2 ( +. ) and ( -| ) = map2
( -. )
let ( *|. ) a b = fold_left ( +. ) 0. (map2 ( *. ) a b)
let unitise r = 1. /. sqrt (r *|. r) *| r
let ray_sphere orig dir center radius =
let v = center -| orig in
let b = v *|. dir in
let disc = b *. b -. v *|. v +. radius *. radius in
if disc < 0. then infinity else
(fun t2 -> if t2 < 0. then infinity else
((fun t1 -> if t1>0. then t1 else t2) (b -. sqrt disc))) (b +. sqrt
disc)
let rec intersect orig dir ((l, _) as hit) = function
`Sphere (center, radius) ->
let l' = ray_sphere orig dir center radius in
if l' >= l then hit else l', unitise (orig +| l' *| dir -| center)
| `Group (center, radius, scenes) ->
let l' = ray_sphere orig dir center radius in
if l' >= l then hit else fold_left (intersect orig dir) hit scenes
let intersect orig dir = intersect orig dir (infinity, [0.; 0.; 0.])
let neg_light = unitise [1.; 3.; -2.] and orig = [0.; 0.; -4.]
let trace dir scene =
let lambda, normal = intersect orig dir scene in
if lambda = infinity then 0. else
let g = max 0. (normal *|. neg_light) in
let p = orig +| lambda *| dir +| sqrt epsilon_float *| normal in
if fst (intersect p neg_light scene) < infinity then 0. else g
let rec create level c r =
let obj = `Sphere (c, r) and a = 3. *. r /. sqrt 12. in
if level = 1 then obj else
let aux x' z' = create (level - 1) (c +| [x'; a; z']) (0.5 *. r) in
`Group (c, 3.*.r, [obj; aux (-.a) (-.a); aux a (-.a); aux (-.a) a; aux a
a])
let level = 6 and n = int_of_string Sys.argv.(1) and ss = 4
let scene = create level [0.; -1.; 0.] 1. and ss2 = float (ss * ss);;
Printf.printf "P5\n%d %d\n255\n" n n;;
let rec range f accu l u = if l>=u then accu else range f (f accu l) (l+1)
u;;
let ray x y dx g dy =
let aux x d = float x -. float n /. 2. +. float d /. float ss in
g +. (trace (unitise [aux x dx; aux y dy; float n]) scene);;
let g x y = range (fun g dx -> range (ray x (n-1-y) dx) g 0 ss) 0. 0 ss
let pixel y () x =
Printf.printf "%c" (char_of_int (int_of_float (0.5 +. 255. *. g x y /.
ss2)));;
range (fun () y -> range (pixel y) () 0 n) () 0 n;;

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Joe Marshall

2005-08-05, 9:02 am

Jon Harrop <usenet@jdh30.plus.com> writes:

> Hi!
>
> I am interested in Scheme and was wondering if anyone here would be kind
> enough to port my ray tracer from one of its other languages (C++, Java,
> SML and OCaml) to Scheme:
>
> http://www.ffconsultancy.com/free/r.../languages.html
>
> I am interested in short or fast implementations. In particular, I would
> like to see how well Scheme does compared to the other languages. Also, I'm
> using Linux so I'd like code than I can compile with a free compiler for
> benchmarking.


Somehow, I suspect you want this done for free.

I'm mildly curious, but not curious enough to spend the time to do the
whole thing. I'd be willing to give advice and help *you* port it,
though.

> Here is the shortest implementation that I have come up with so far (42
> lines of OCaml):
>
> open List
> let ( *| ) s = map (( *. ) s) and ( +| ) = map2 ( +. ) and ( -| ) = map2
> ( -. )
> let ( *|. ) a b = fold_left ( +. ) 0. (map2 ( *. ) a b)
> let unitise r = 1. /. sqrt (r *|. r) *| r
> let ray_sphere orig dir center radius =
> let v = center -| orig in
> let b = v *|. dir in
> let disc = b *. b -. v *|. v +. radius *. radius in
> if disc < 0. then infinity else
> (fun t2 -> if t2 < 0. then infinity else
> ((fun t1 -> if t1>0. then t1 else t2) (b -. sqrt disc))) (b +. sqrt
> disc)
> let rec intersect orig dir ((l, _) as hit) = function
> `Sphere (center, radius) ->
> let l' = ray_sphere orig dir center radius in
> if l' >= l then hit else l', unitise (orig +| l' *| dir -| center)
> | `Group (center, radius, scenes) ->
> let l' = ray_sphere orig dir center radius in
> if l' >= l then hit else fold_left (intersect orig dir) hit scenes
> let intersect orig dir = intersect orig dir (infinity, [0.; 0.; 0.])
> let neg_light = unitise [1.; 3.; -2.] and orig = [0.; 0.; -4.]
> let trace dir scene =
> let lambda, normal = intersect orig dir scene in
> if lambda = infinity then 0. else
> let g = max 0. (normal *|. neg_light) in
> let p = orig +| lambda *| dir +| sqrt epsilon_float *| normal in
> if fst (intersect p neg_light scene) < infinity then 0. else g
> let rec create level c r =
> let obj = `Sphere (c, r) and a = 3. *. r /. sqrt 12. in
> if level = 1 then obj else
> let aux x' z' = create (level - 1) (c +| [x'; a; z']) (0.5 *. r) in
> `Group (c, 3.*.r, [obj; aux (-.a) (-.a); aux a (-.a); aux (-.a) a; aux a
> a])
> let level = 6 and n = int_of_string Sys.argv.(1) and ss = 4
> let scene = create level [0.; -1.; 0.] 1. and ss2 = float (ss * ss);;
> Printf.printf "P5\n%d %d\n255\n" n n;;
> let rec range f accu l u = if l>=u then accu else range f (f accu l) (l+1)
> u;;
> let ray x y dx g dy =
> let aux x d = float x -. float n /. 2. +. float d /. float ss in
> g +. (trace (unitise [aux x dx; aux y dy; float n]) scene);;
> let g x y = range (fun g dx -> range (ray x (n-1-y) dx) g 0 ss) 0. 0 ss
> let pixel y () x =
> Printf.printf "%c" (char_of_int (int_of_float (0.5 +. 255. *. g x y /.
> ss2)));;
> range (fun () y -> range (pixel y) () 0 n) () 0 n;;
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy
> http://www.ffconsultancy.com

Jens Axel Søgaard

2005-08-05, 9:02 am

Joe Marshall wrote:
> Jon Harrop <usenet@jdh30.plus.com> writes:


>
>
> Somehow, I suspect you want this done for free.
>
> I'm mildly curious, but not curious enough to spend the time to do the
> whole thing. I'd be willing to give advice and help *you* port it,
> though.


It would also be relevant to know whether the port should be fast,
short or portable.

--
Jens Axel Søgaard
Jon Harrop

2005-08-05, 5:04 pm

Joe Marshall wrote:
> Somehow, I suspect you want this done for free.


Yes.

> I'm mildly curious, but not curious enough to spend the time to do the
> whole thing. I'd be willing to give advice and help *you* port it,
> though.


Ok. It'll take me some time to learn the basics of Lisp but I'll have a go.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-05, 5:04 pm

Jens Axel Søgaard wrote:
> It would also be relevant to know whether the port should be fast,
> short or portable.


Ideally, I'd like direct translations of the four versions given on that web
page. These go from concise but slow to longer and faster and I've plotted
them on verbosity vs performance graphs for the other languages. I'd like
to include Lisp. However, it will be pointless for me to do the translation
myself as the code is likely to be very slow and unidiomatic.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Neelakantan Krishnaswami

2005-08-05, 5:04 pm

In article <42f36845$0$650$edfadb0f@dread12.news.tele.dk>, Jens Axel Søgaard
wrote:
>
> It would also be relevant to know whether the port should be fast,
> short or portable.


His code is fairly typical Ocaml, but very perversely formatted. I'd
suggest writing an idiomatic Scheme program and then radically
uglifying it to make it short. Here's the same Ocaml code, formatted
more sanely:

open List

let ( *| ) s = map (( *. ) s)

let ( +| ) = map2 ( +. )

let ( -| ) = map2 ( -. )

let ( *|. ) a b = fold_left ( +. ) 0. (map2 ( *. ) a b)

let unitise r = 1. /. sqrt (r *|. r) *| r

let ray_sphere orig dir center radius =
let v = center -| orig in
let b = v *|. dir in
let disc = b *. b -. v *|. v +. radius *. radius
in
if disc < 0. then
infinity
else
let t2 = b +. sqrt disc in
if t2 < 0.0 then
infinity
else
let t1 = (b -. sqrt disc) in
if t1 > 0.0 then
t1
else
t2

let rec intersect orig dir ((l, _) as hit) = function
| `Sphere (center, radius) ->
let l' = ray_sphere orig dir center radius in
if l' >= l then
hit
else
(l', unitise (orig +| l' *| dir -| center))
| `Group (center, radius, scenes) ->
let l' = ray_sphere orig dir center radius in
if l' >= l then
hit
else
fold_left (intersect orig dir) hit scenes

let intersect orig dir = intersect orig dir (infinity, [0.; 0.; 0.])

let neg_light = unitise [1.; 3.; -2.] and orig = [0.; 0.; -4.]

let trace dir scene =
let lambda, normal = intersect orig dir scene in
if lambda = infinity then
0.0
else
let g = max 0. (normal *|. neg_light) in
let p = orig +| lambda *| dir +| sqrt epsilon_float *| normal in
if fst (intersect p neg_light scene) < infinity then
0.0
else
g

let rec create level c r =
let obj = `Sphere (c, r) and a = 3. *. r /. sqrt 12. in
if level = 1 then
obj
else
let aux x' z' =
create (level - 1) (c +| [x'; a; z']) (0.5 *. r)
in
`Group (c,
3.*.r,
[obj;
aux (-.a) (-.a);
aux a (-.a);
aux (-.a) a;
aux a a])

let level = 6

let n = int_of_string Sys.argv.(1)

let ss = 4

let scene = create level [0.0; -1.0; 0.0] 1.0

let ss2 = float (ss * ss)

let _ = Printf.printf "P5\n%d %d\n255\n" n n

let rec range f accu l u =
if l>=u then
accu
else
range f (f accu l) (l+1) u

let ray x y dx g dy =
let aux x d =
float x -. float n /. 2. +. float d /. float ss
in
g +. (trace (unitise [aux x dx; aux y dy; float n]) scene)

let g x y = range (fun g dx -> range (ray x (n-1-y) dx) g 0 ss) 0.0 0 ss

let pixel y () x =
Printf.printf "%c" (char_of_int
(int_of_float (0.5 +. 255. *. g x y /. ss2)))

let _ = range (fun () y -> range (pixel y) () 0 n) () 0 n


--
Neel Krishnaswami
neelk@cs.cmu.edu
Jan Van lent

2005-08-05, 5:04 pm

Jon Harrop wrote:
> Hi!
>
> I am interested in Scheme and was wondering if anyone here would be kind
> enough to port my ray tracer from one of its other languages (C++, Java,
> SML and OCaml) to Scheme:
>
> http://www.ffconsultancy.com/free/r.../languages.html
>
> I am interested in short or fast implementations. In particular, I would
> like to see how well Scheme does compared to the other languages. Also, I'm
> using Linux so I'd like code than I can compile with a free compiler for
> benchmarking.
>
> Here is the shortest implementation that I have come up with so far (42
> lines of OCaml):


<snip ocaml code>

I translated your implementation to scheme. It is an almost line by line
translation. I am fairly sure both implementations do exactly the same
operations.

Some differences:

- spread some things over more lines
- "let" instead of anonymous functions in "ray-sphere"
- "named let" inside "intersect" instead of two "intersect" functions
- everything is done with lists
- sphere is (c r), group is (c r obj1 obj2 ...)
- nested loops over pixels and subsamples use srfi-42,
this could be done in exactly the same way is in the ocaml version or
with "named let" or "do".

I have tested the implementation with Gauche 0.8.5 (an interpreter). It
should be straightforward to run it with other systems that have srfi-42
such as Chicken, MzScheme, SISC and Scheme48 [1]. With a bit more work
it should work with any R5RS system.

jan

[1] http://www.shiro.dreamhost.com/sche...ref.cgi?SRFI-42

;;;;;;
(use srfi-1)
(use srfi-42)

(define infinity 1e300)
(define epsilon 1e-15)
(define (s*v s b) (map (lambda (t) (* s t)) b))
(define (v+v a b) (map + a b))
(define (v-v a b) (map - a b))
(define (dot a b) (apply + (map * a b)))
(define (unitise r) (s*v (/ (sqrt (dot r r))) r))

(define (ray-sphere orig dir center radius)
(let* ((v (v-v center orig))
(b (dot v dir))
(disc (+ (- (* b b) (dot v v)) (* radius radius))))
(if (< disc 0) infinity
(let ((t2 (+ b (sqrt disc))))
(if (< t2 0) infinity
(let ((t1 (- b (sqrt disc))))
(if (> t1 0) t1 t2)))))))

(define (intersect orig dir obj)
(let lp ((obj obj) (hit (list infinity '(0 0 0))))
(let ((l (ray-sphere orig dir (car obj) (cadr obj))))
(if (>= l (car hit)) hit
(if (null? (cddr obj))
(list l (unitise (v+v orig (v-v (s*v l dir) (car obj)))))
(fold lp hit (cddr obj)))))))

(define neg_light (unitise '(1 3 -2)))
(define orig '(0 0 -4))

(define (trace dir scene)
(let* ((hit (intersect orig dir scene))
(lam (car hit))
(normal (cadr hit)))
(if (>= lam infinity) 0
(let ((g (max 0 (dot normal neg_light)))
(p (v+v orig (v+v (s*v lam dir) (s*v (sqrt epsilon)
normal)))))
(if (< (car (intersect p neg_light scene)) infinity) 0 g)))))

(define (create level c r)
(let ((obj (list c r))
(a (* 3 (/ r (sqrt 12)))))
(if (= level 1) obj
(let ((aux (lambda (x z)
(create (- level 1) (v+v c (list x a z)) (* 0.5 r)))))
(list c (* 3 r)
obj (aux (- a) (- a)) (aux a (- a)) (aux (- a) a) (aux
a a))))))

(define level 6)
(define n (string->number (car *argv*)))
(define ss 4)
(define scene (create level '(0 -1 0) 1))
(define ss2 (* ss ss))
(for-each display (list "P5" #\newline n #\space n #\newline 255
#\newline))
(define (aux x d) (+ (- x (/ n 2)) (/ d ss)))
(define (g x y)
(sum-ec (: dx ss) (: dy ss)
(trace (unitise (list (aux x dx) (aux (- (- n 1) y) dy) n)) scene)))
(define (pixel x y)
(write-byte (inexact->exact (+ 0.5 (* 255 (/ (g x y) ss2))))))

(do-ec (: y n) (: x n) (pixel x y))
Jan Van lent

2005-08-05, 5:04 pm

Jan Van lent wrote:

> (write-byte (inexact->exact (+ 0.5 (* 255 (/ (g x y) ss2))))))


For systems with rationals this should probably be

(write-byte (inexact->exact (truncate (+ 0.5 (* 255 (/ (g x y) ss2)))))))

jan
Joe Marshall

2005-08-05, 5:04 pm

Jon Harrop <usenet@jdh30.plus.com> writes:

> Joe Marshall wrote:
>
> Yes.
>
>
> Ok. It'll take me some time to learn the basics of Lisp but I'll have a go.


What's the output format?
Jon Harrop

2005-08-05, 10:01 pm

Joe Marshall wrote:
> What's the output format?


PGM

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-05, 10:01 pm

Neelakantan Krishnaswami wrote:

> In article <42f36845$0$650$edfadb0f@dread12.news.tele.dk>, Jens Axel
> Søgaard wrote:
>
> His code is fairly typical Ocaml, but very perversely formatted.


Yes, the code I posted was deliberately rewritten to be concise. The web
pages contain more conventionally formatted code:

http://www.ffconsultancy.com/free/r.../languages.html

> I'd
> suggest writing an idiomatic Scheme program and then radically
> uglifying it to make it short.


Performance seems to be more important in the Lisp implementations. Of the
implementations I have gotten working, none are within an order of
magnitude of the performance of the least optimised OCaml on the site.

> Here's the same Ocaml code, formatted more sanely:


Yours is unconventionally verbose. For example, few people would spread "if
t1 > 0.0 then t1 else t2" across four lines as you have.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Joe Marshall

2005-08-05, 10:01 pm

Jan Van lent <jan.vanlent+news@cs.kuleuven.ac.be> writes:

> I translated your implementation to scheme. It is an almost line by
> line translation. I am fairly sure both implementations do exactly the
> same operations.


I've got this code running on MIT Scheme (I replaced the srfi-42 stuff
with the obvious loop). It appears to work; the output picture is
similar to the one on Jon Harrop's web page.

I'm gonna play with it over the wend and see if I can't get better
performance.

--
~jrm
Mike Austin

2005-08-06, 4:02 am

Jon Harrop wrote:
> Neelakantan Krishnaswami wrote:
>
> Yours is unconventionally verbose. For example, few people would spread "if
> t1 > 0.0 then t1 else t2" across four lines as you have.


As a non Ocaml programmer, I can understand most of your program with his
'verbose' formatting. Your version, even the one on your web site, reminds
me of (modem) line noise. Good formatting goes a long way.


Mike
Joe Marshall

2005-08-06, 5:01 pm

Jon Harrop <usenet@jdh30.plus.com> writes:

> Performance seems to be more important in the Lisp implementations. Of the
> implementations I have gotten working, none are within an order of
> magnitude of the performance of the least optimised OCaml on the site.


That's not surprising. Without the right tuning, Lisp (and Scheme)
will use the most general arithmetic and the most general data
structures.

--
~jrm
alex.gman@gmail.com

2005-08-06, 5:01 pm

Jon Harrop wrote:

> Performance seems to be more important in the Lisp implementations. Of the
> implementations I have gotten working, none are within an order of
> magnitude of the performance of the least optimised OCaml on the site.


In the right hands, Bigloo is about as fast as, or faster than OCaml,
as a general rule.

I'd help you, however, I noticed that you've been soliciting code,
fixes and improvements from mailing lists and newsgroups for a while,
but on your web site, you don't even acknowledge the help you got so
far.

Jon Harrop

2005-08-06, 5:01 pm

alex.gman@gmail.com wrote:
> Jon Harrop wrote:
>
> In the right hands, Bigloo is about as fast as, or faster than OCaml,
> as a general rule.


Can you point me to some evidence of that? On the shootout, OCaml is faster
than Bigloo at 9/11 of the tests. Unfortunately, most of the interesting
tests have yet to be implemented in Bigloo.

> I'd help you, however, I noticed that you've been soliciting code,
> fixes and improvements from mailing lists and newsgroups for a while,
> but on your web site, you don't even acknowledge the help you got so
> far.


If I use other people's code and they ask for an attribution then I will
definitely put one up. Nobody has asked for an attribution so far, which
isn't surprising because I wrote virtually all of the code myself.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
alex.gman@gmail.com

2005-08-06, 5:01 pm

Jon Harrop wrote:
> alex.gman@gmail.com wrote:
>
> Can you point me to some evidence of that? On the shootout, OCaml is faster
> than Bigloo at 9/11 of the tests. Unfortunately, most of the interesting
> tests have yet to be implemented in Bigloo.


I don't feel like looking for evidence (see below); but I use(d) both,
so I know the score.

>
> If I use other people's code and they ask for an attribution then I will
> definitely put one up. Nobody has asked for an attribution so far, which
> isn't surprising because I wrote virtually all of the code myself.


Your code's been ported to other languages by people; and your !@@ has
been saved from publicizing completely incorrect claims by people who
found errors on your web site. It's not the relative number of lines.
What good are they if you reach the embarrassingly wrong conclusion? (I
remember our caml-list conversation)

It's just common sense to acknowledge outside help. They shouldn't have
to ask for attribution, just like they shouldn't have to ask not to
have their car broken into. If they were your employees (not even
students) then you could get to decide whether to acknowledge them.
Still, it would seem rather shitty not to.

Anton van Straaten

2005-08-06, 5:01 pm

Jon Harrop wrote:
> alex.gman@gmail.com wrote:
>
> If I use other people's code and they ask for an attribution then I will
> definitely put one up.


You have this backwards. You should attribute by default. Ask people
who contribute how they'd like to be attributed -- that gives them the
option to refuse attribution.

Anton
Jon Harrop

2005-08-06, 10:01 pm

alex.gman@gmail.com wrote:
> Jon Harrop wrote:
>
> Your code's been ported to other languages by people;


Yes, on the shootout.

> and your !@@ has been saved from publicizing completely incorrect claims
> by people who found errors on your web site.


Well, one person (Oleg, IIRC) found a serious error in my SML that made that
language look much faster than it should have done. I corrected it and
thanked him.

> It's not the relative number of lines.


Yes, it is.

> What good are they if you reach the embarrassingly wrong conclusion? (I
> remember our caml-list conversation)


I don't remember our caml-list conversion and neither does my computer.

> It's just common sense to acknowledge outside help. They shouldn't have
> to ask for attribution, just like they shouldn't have to ask not to
> have their car broken into. If they were your employees (not even
> students) then you could get to decide whether to acknowledge them.
> Still, it would seem rather shitty not to.


Who is "they"?

I am unhappy that, after all the effort I have put into helping you
personally, I get a non-specific accusation of plagiarism in return. :-(

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-06, 10:01 pm

Anton van Straaten wrote:
> Jon Harrop wrote:
>
> You have this backwards. You should attribute by default. Ask people
> who contribute how they'd like to be attributed -- that gives them the
> option to refuse attribution.


It depends how much code I use. If someone contributed a port of my ray
tracer to a new language then of course I would properly attribute it to
them. If someone tells me the SML for mach_eps then I won't attribute it to
them.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
alex.gman@gmail.com

2005-08-06, 10:01 pm

Jon Harrop wrote:

> I don't remember our caml-list conversion and neither does my computer.


I expected you to be more computer-savvy.

>
> Who is "they"?
>
> I am unhappy that, after all the effort I have put into helping you
> personally, I get a non-specific accusation of plagiarism in return. :-(


Pardon? On caml-list, I pointed out that your results looked
"interesting" (With the benefit of hindsight, "fishy" would be a better
word to use):

http://groups.google.com/group/fa.c...061e90d8b46f58b

Matthias Blume translated your Caml version to SML:

http://groups.google.com/group/comp...444fa5523d9486f

Oleg Trott found an error on your web site that explained the problem:

http://groups.google.com/group/comp...6e3d4132fb6065a

Initially, you blamed the error on Matthias, but then half-heartedly
retracted. The list goes on. Acknowledgements on your web site: 0

Jon Harrop

2005-08-06, 10:01 pm

alex.gman@gmail.com wrote:
> Pardon? On caml-list, I pointed out that your results looked
> "interesting" (With the benefit of hindsight, "fishy" would be a better
> word to use):
>
> http://groups.google.com/group/fa.c...061e90d8b46f58b


What exactly is it about our 1 post "conversation" that you would like an
attribution for?

> Matthias Blume translated your Caml version to SML:
>
> http://groups.google.com/group/comp...444fa5523d9486f


Yes, may people have translated my code (e.g. Stephen Ws, Simon Geard and
José Bollo). I have put none of them on my site (so far).

> Oleg Trott found an error on your web site that explained the problem:
>
> http://groups.google.com/group/comp...6e3d4132fb6065a


Yes, and I thanked him for pointing it out and corrected it.

> Initially, you blamed the error on Matthias, but then half-heartedly
> retracted.


Yes, Matthias pointed out that the code on my site wasn't his, it was mine.

> The list goes on.


Does it?

> Acknowledgements on your web site: 0


Yes.

As I have said, if anyone who has actually contributed anything would like
an attribution then I'll put one up.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-06, 10:01 pm

> Jan Van lent <jan.vanlent+news@cs.kuleuven.ac.be> writes:

Joe Marshall wrote:[color=darkred]
> I'm gonna play with it over the wend and see if I can't get better
> performance.


Fantastic, thank you. :-)

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
alex.gman@gmail.com

2005-08-07, 4:01 am

Jon Harrop wrote:
> alex.gman@gmail.com wrote:
>
> What exactly is it about our 1 post "conversation" that you would like an
> attribution for?


Now you are putting words in my mouth. I'm not asking for an
attribution for that post, even though you would have been better off
paying attention to it. You said you couldn't find it, so I posted a
link.

>
> Yes, Matthias pointed out that the code on my site wasn't his, it was mine.
>
>
> Does it?
>
>
> Yes.
>
> As I have said, if anyone who has actually contributed anything would like
> an attribution then I'll put one up.


Here we go again. You blame people for your own errors by default, and
if they complain, you SORT OF retract the blame [1]. But you don't
attribute by default.

I know that no amount of bitching will turn an ingrate into a gracious
person, at best it will make him /act/ graciously, but this needs to be
said:

You should always acknowledge others' help in the same media you
publicize any results using it. If you film a movie, the credits are
there for a reason. If you write a paper, you include a special section
in it.

[1] "Matthias is denying all knowledge of this so I guess I'll have to
take responsibility myself. " -- oooh, how nice of you!

Förster vom Silberwald

2005-08-07, 9:01 am

Jon Harrop wrote:

> Can you point me to some evidence of that? On the shootout, OCaml is faster
> than Bigloo at 9/11 of the tests. Unfortunately, most of the interesting
> tests have yet to be implemented in Bigloo.


What a coincidence. I always wanted to port your ray-tracer (which you
first posted on comp.lang.functional) code to Bigloo and see how it
will turn out. However, my OCaml knowledge is tiny. Hopefully others
will do it.

How do you submit code for the language shootout page? A couple of
months ago I happend to submit the "mandelbrot-test" in Bigloo. But
haven't found it yet on any of the language shootout pages.

Concerning the OCaml vs. Bigloo race: it often depends on the kind of
problem itself. Sometimes OCaml will perform better and sometimes
Bigloo will do.

However, the language shootout page does not necessarily display real
world problems. Surely, Python for example will never ascend and
becoming faster in the real world. The language shootout page can be
consulted for some propositions but that's all.

Jon, I have seen you are a very active participant on
comp.lang.functional and you are pleased with OCaml and functional
programming. However, may be learning Bigloo will pay off for you since
Bigloo has a lot to offer. There was a time were they (Bigloo/OCaml)
had a compatibility module.

Have you never encountered any hurdles when dealing with the
nit-picking OCaml static devilish compiler? Yes other will call it a
feature and first aid help tool. Bigloo and Scheme in general will and
can offer you some new feeling when programming.

Regards,
Uhr_100m_Wasserdicht

Förster vom Silberwald

2005-08-07, 9:01 am


Joe Marshall wrote:

> I'm gonna play with it over the wend and see if I can't get better
> performance.


I hope it is not too much to ask you whether it will be possible that
you post your version without srfi-42.

I would liket to tailor it for Bigloo (adding types and native
operators) if possible.

Thanks,
Schneewittchen

Förster vom Silberwald

2005-08-07, 9:01 am

Jon Harrop wrote:

> If I use other people's code and they ask for an attribution then I will
> definitely put one up. Nobody has asked for an attribution so far, which
> isn't surprising because I wrote virtually all of the code myself.


Forgot to mention: you should always give evidence of the source code.
If you use others code in the public you should start giving credence
to it from the very start on. This would be only fair.

Citing code and algorithms is just like as you would citing references
in a scientific paper.

Schneewittchen

Förster vom Silberwald

2005-08-07, 9:01 am


Jon Harrop wrote:

> As I have said, if anyone who has actually contributed anything would like
> an attribution then I'll put one up.


Alex sounds sometimes a bit direct or harsh. However, he is right that
you must give attribution whether they ask you or not.

One should see algorithmic code as a kind of scientific reference.

However, my opinion does not count and never will.

Schneewittchen

Jon Harrop

2005-08-07, 9:01 am

alex.gman@gmail.com wrote:
> Now you are putting words in my mouth. I'm not asking for an
> attribution for that post, even though you would have been better off
> paying attention to it. You said you couldn't find it, so I posted a
> link.


No, I said I couldn't find the "conversation" that you referred to. I
ignored that single post because it doesn't constitute a conversation.

> Here we go again. You blame people for your own errors by default, and
> if they complain, you SORT OF retract the blame [1]. But you don't
> attribute by default.


Apparently you can't tell when a post is tongue in ch.

> I know that no amount of bitching will turn an ingrate into a gracious
> person, at best it will make him /act/ graciously, but this needs to be
> said:
>
> You should always acknowledge others' help in the same media you
> publicize any results using it. If you film a movie, the credits are
> there for a reason. If you write a paper, you include a special section
> in it.


No. You've got to draw a line somewhere.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-07, 9:01 am

Förster vom Silberwald wrote:
> Jon Harrop wrote:
>
>
> Alex sounds sometimes a bit direct or harsh. However, he is right that
> you must give attribution whether they ask you or not.
>
> One should see algorithmic code as a kind of scientific reference.


Absolutely, but we're not talking about algorithms or scientific work, we're
talking about tiny changes.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Vesa Karvonen

2005-08-07, 9:01 am

Jon Harrop <usenet@jdh30.plus.com> wrote:
> alex.gman@gmail.com wrote:

[...]
[color=darkred]
> No. You've got to draw a line somewhere.


In the Boost community, for instance, even something like participation in
a discussion is generally acknowledged in the documentation of libraries.

Take a moment to ponder why no one is eager to defend your position.

Observations: You come to a newsgroup. Ask others to do work for you. You
use the fruits of their work to publish advocacy of a certain language
based on highly subjective metrics. You don't give credit to others. You
don't even provide a single link to the newsgroup/mailing list discussions
on your web-site when explicitly hinted to do so.

-Vesa Karvonen
Sven.Hartrumpf@FernUni-Hagen.de

2005-08-07, 9:01 am

"Förster vom Silberwald" asked:

> How do you submit code for the language shootout page?


http://shootout.alioth.debian.org/f...lcpu#contribute

> A couple of
> months ago I happened to submit the "mandelbrot-test" in Bigloo. But I
> haven't found it yet on any of the language shootout pages.


Maybe resubmit following the procedure described in the given URL.

Greetings
Sven
Jens Axel Søgaard

2005-08-07, 9:01 am

Jon Harrop wrote:
> alex.gman@gmail.com wrote:


>
> If I use other people's code and they ask for an attribution then I will
> definitely put one up. Nobody has asked for an attribution so far, which
> isn't surprising because I wrote virtually all of the code myself.


It would be natural to put a link on

<http://www.ffconsultancy.com/free/r.../languages.html>

to the news group discussions, e.g. to

<http://groups-beta.google.com/group...c678a5566414792>

--
Jens Axel Søgaard


Vesa Karvonen

2005-08-07, 9:01 am

Jon Harrop <usenet@jdh30.plus.com> wrote:
[...]
> Absolutely, but we're not talking about algorithms or scientific work, we're
> talking about tiny changes.


Let me see if I understand your opinion correctly: If something isn't
"scientific" in your opinion, then it doesn't deserve any mention
whatsoever.

-Vesa Karvonen
Jon Harrop

2005-08-07, 9:01 am

Jens Axel Søgaard wrote:
> It would be natural to put a link on
>
> <http://www.ffconsultancy.com/free/r.../languages.html>
>
> to the news group discussions, e.g. to
>
>

<http://groups-beta.google.com/group...c678a5566414792>

Good idea. I'll put links to the discussions in all of the newsgroups.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-07, 9:02 am

Vesa Karvonen wrote:
> Jon Harrop <usenet@jdh30.plus.com> wrote:
>
> In the Boost community, for instance, even something like participation in
> a discussion is generally acknowledged in the documentation of libraries.


Ok.

> Take a moment to ponder why no one is eager to defend your position.


None of the people complaining have made significant contributions to my
work.

> Observations: You come to a newsgroup. Ask others to do work for you. You
> use the fruits of their work to publish advocacy of a certain language
> based on highly subjective metrics. You don't give credit to others. You
> don't even provide a single link to the newsgroup/mailing list discussions
> on your web-site when explicitly hinted to do so.


As I've said, only my code has appeared on our site so far. I hope this will
change, perhaps someone here will make a decent Bigloo version that I can
put up. If they do, I'll cite them.

Following Jens Axel Søgaard's advice, I shall put up links to the relevant
discussions on various news groups.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Vesa Karvonen

2005-08-07, 9:02 am

Jon Harrop <usenet@jdh30.plus.com> wrote:
> Jens Axel Søgaard wrote:
> <http://groups-beta.google.com/group...c678a5566414792>


> Good idea. I'll put links to the discussions in all of the newsgroups.


Jens originally proposed this almost two months ago:

http://groups.google.fi/group/comp....03f8523cd31145f

Based on your past behavior, I would guess that you now blame him for not
being explicit enough, rather than take the blame for not asking for
clarification.

-Vesa Karvonen
Jon Harrop

2005-08-07, 9:02 am

Vesa Karvonen wrote:
> Jon Harrop <usenet@jdh30.plus.com> wrote:
>
> Jens originally proposed this almost two months ago:
>
>

http://groups.google.fi/group/comp....03f8523cd31145f
>
> Based on your past behavior, I would guess that you now blame him for not
> being explicit enough, rather than take the blame for not asking for
> clarification.


No, I just misunderstood what Jens was saying (I thought he wanted the URL
of our site). Sorry, Jens.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Vesa Karvonen

2005-08-07, 9:02 am

Jon Harrop <usenet@jdh30.plus.com> wrote:
> Vesa Karvonen wrote:


[color=darkred]
> None of the people complaining have made significant contributions to my
> work.


I'm not talking about the people who complain. I'm talking about the
absense of people to defend your position. During the discussion of your
ray tracer in comp.lang.functional two months ago, it was obvious to me
that your arrogant Ocaml advocacy irritated more than a few people.

Also, regarding contributions, I think that it would be appropriate to put
a link to the page

http://www.mlton.org/ForLoops

in conjunction with the comment that SML has "Only while loops" in the
"Conclusions" section of the page

http://www.ffconsultancy.com/free/r.../languages.html .

I must admit that I find it unpleasant to need to explicitly ask.

> As I've said, only my code has appeared on our site so far.

^^^

You mean, on *your* site. The site whose admin *you* are.

More to the point, as several people have advised you to do, you should
*acknowledge all kinds of contributions* . Not just code.

-Vesa Karvonen
Joe Marshall

2005-08-07, 9:02 am

"Förster vom Silberwald" <chain_lube@hotmail.com> writes:

> Joe Marshall wrote:
>
>
> I hope it is not too much to ask you whether it will be possible that
> you post your version without srfi-42.


Here is the unoptimized original code minus srfi-42 and with a couple
of tweaks for MIT Scheme.

;; A bare-bones ray tracer
;;
;; Original code by Jon Harrop http://www.ffconsultancy.com/
;; Ported to Scheme by Jan Van lent http://www.cs.kuleuven.be/~jvl/
;; Minor changes for MIT Scheme by jrm

;; Notes:

;; Kudos to Jan Van lent for taking the time to port this to Scheme.

;; The constant infinity is generated by dividing by zero. This may
;; not work in other implementations. Replace it by as large a
;; float as possible.

;; The value of N (image width in pixels) is hard wired at 100 rather
;; than being taken from the command line.

;; No optimization at all has been done in this version, so it will
;; be *DOG SLOW*.

;; Recommended compiler switches for MIT Scheme:
;; (set! compiler:compile-by-procedures? #f)
;; (set! compiler:generate-range-checks? #f)
;; (set! compiler:generate-stack-checks? #t)
;; (set! compiler:generate-type-checks? #f)
;; (set! compiler:open-code-floating-point-arithmetic? #t)
;; (set! compiler:open-code-primitives? #t)
;;
;; Even with these switches, this unoptimized version will be *SLOW*

;; On an 800 MHz P3, this takes about 72 seconds.

(declare (usual-integrations))

(define infinity (/ 1.0 0.0))
(define epsilon 1e-15)
(define (s*v s b) (map (lambda (t) (* s t)) b))
(define (v+v a b) (map + a b))
(define (v-v a b) (map - a b))
(define (dot a b) (apply + (map * a b)))
(define (unitise r) (s*v (/ (sqrt (dot r r))) r))

(define (ray-sphere orig dir center radius)
(let* ((v (v-v center orig))
(b (dot v dir))
(disc (+ (- (* b b) (dot v v)) (* radius radius))))
(if (< disc 0.0) infinity
(let ((t2 (+ b (sqrt disc))))
(if (< t2 0.0) infinity
(let ((t1 (- b (sqrt disc))))
(if (> t1 0.0) t1 t2)))))))

(define (intersect orig dir obj)
(let lp ((obj obj) (hit (list infinity '(0.0 0.0 0.0))))
(let ((l (ray-sphere orig dir (car obj) (cadr obj))))
(if (>= l (car hit)) hit
(if (null? (cddr obj))
(list l (unitise (v+v orig (v-v (s*v l dir) (car obj)))))
(fold-right lp hit (cddr obj)))))))

(define neg_light (unitise '(1.0 3.0 -2.0)))
(define orig '(0.0 0.0 -4.0))

(define (trace dir scene)
(let* ((hit (intersect orig dir scene))
(lam (car hit))
(normal (cadr hit)))
(if (>= lam infinity) 0.0
(let ((g (max 0.0 (dot normal neg_light)))
(p (v+v orig (v+v (s*v lam dir) (s*v (sqrt epsilon)
normal)))))
(if (< (car (intersect p neg_light scene)) infinity) 0.0 g)))))

(define (create level c r)
(let ((obj (list c r))
(a (* 3.0 (/ r (sqrt 12.0)))))
(if (= level 1) obj
(let ((aux (lambda (x z)
(create (- level 1) (v+v c (list x a z)) (* 0.5 r)))))
(list c (* 3.0 r)
obj (aux (- a) (- a)) (aux a (- a)) (aux (- a) a)
(aux a a))))))

(define level 6)
;(define n (string->number (car *argv*)))
(define n 100)
(define ss 4)
(define scene (create level '(0.0 -1.0 0.0) 1.0))
(define ss2 (* ss ss))

(define (aux x d) (+ (- x (/ n 2.0)) (/ d ss)))

(define (g x y)
(do ((dx 0 (+ dx 1))
(sum 0 (do ((dy 0 (+ dy 1))
(sum sum (+ sum (trace (unitise (list (aux x dx)
(aux (- (- n 1) y) dy)
(exact->inexact n)))
scene))))
((>= dy ss) sum))))
((>= dx ss) sum)))

(define (pixel x y)
(write-char
(ascii->char
(inexact->exact
(truncate (+ 0.5 (* 255 (/ (g x y) ss2))))))))

(define (go)
;; (gc-flip)
(with-output-to-binary-file
"scheme.pgm"
(lambda ()
(for-each display (list "P5" #\newline
n #\space n
#\newline 255
#\newline))
(do ((y 0 (+ y 1)))
((>= y n))
(do ((x 0 (+ x 1)))
((>= x n))
(pixel x y))))))
Jon Harrop

2005-08-07, 5:02 pm

Vesa Karvonen wrote:
> I'm not talking about the people who complain. I'm talking about the
> absense of people to defend your position. During the discussion of your
> ray tracer in comp.lang.functional two months ago, it was obvious to me
> that your arrogant Ocaml advocacy irritated more than a few people.


People rarely join fruitless discussions.

> Also, regarding contributions, I think that it would be appropriate to put
> a link to the page
>
> http://www.mlton.org/ForLoops
>
> in conjunction with the comment that SML has "Only while loops" in the
> "Conclusions" section of the page
>
> http://www.ffconsultancy.com/free/r.../languages.html .
>
> I must admit that I find it unpleasant to need to explicitly ask.


I'm not going to waste my time adding that.

> More to the point, as several people have advised you to do, you should
> *acknowledge all kinds of contributions* . Not just code.


To save people having to Google for the discussions about my ray tracer on
the internet, I have added three more links to newsgroups threads on our
language comparison page.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Vesa Karvonen

2005-08-07, 5:02 pm

Jon Harrop <usenet@jdh30.plus.com> wrote:
> Vesa Karvonen wrote:

[...]
> People rarely join fruitless discussions.


I agree, I know from experience that it is fruitless to educate assholes.

[color=darkred]
> I'm not going to waste my time adding that.


So, you prefer to give an arguably misleading impression of the SML
language and its capabilities. I would have added that there are a few
more pages on the MLton web site that are relevant to the Ocaml vs SML
table:

To "Records can be (ab)used to get the same effect" I would add a link to
http://mlton.org/ObjectOrientedProgramming .
To "Records must be copied manually" I would add a link to
http://mlton.org/FunctionalRecordUpdate .
To "Define infix operators only for the local scope" I would add a link to
http://mlton.org/InfixingOperators .
To "verbose grammar [...] curried anonymous functions" I would add a link to
http://mlton.org/ProductType .

I have to say that I'm not suprised about your unwillingness to
conscientiously provide unbiased information. Here is what Bjarne
Stroustrup says in book The Design and Evolution of C++ (on page 5):

"Several reviewers have asked me to compare C++ to other languages. This
I have decided against doing. Thereby, I have reaffirmed a long-standing
and strongly held view: Language comparisons are rarely meaningful and
even less often fair. A good comparison of major programming languages
requires more effort than most people are willing to spend, experience
in a wide range of application areas, a rigid maintenance of a detached
and impartial point of view, and a sense of fairness."

It seems to me that Jon lacks all of the qualities that Stroustrup
identifies. I think that we need comp.lang.ocaml.advocacy.

-Vesa Karvonen
Vesa Karvonen

2005-08-07, 5:02 pm

Vesa Karvonen <vesa.karvonen@cs.helsinki.fi> wrote:
> Jon Harrop <usenet@jdh30.plus.com> wrote:
> [...]


A couple more. To "Many incompatible compilers (MLton, SML/NJ, ML-kit,
PolyML, MoscowML, ...)" I would add a note that SML is fairly unique in
that it actually has a formal standard

http://mlton.org/DefinitionOfStandardML

unlike Ocaml. The incompatibilities referred to by Jon, AFAIK, are at the
level of invoking the various compilers rather than at the core language
level.

To "Vectors, slices, 2D polymorphic arrays" I would add a link to the SML/NJ
library

http://www.smlnj.org/doc/smlnj-lib/,

which is, AFAIK, fairly widely used.

-Vesa Karvonen
Jon Harrop

2005-08-07, 5:02 pm

Vesa Karvonen wrote:
> So, you prefer to give an arguably misleading impression of the SML
> language and its capabilities.


As we concluded elsewhere, it is not possible to do any better than giving
"arguably misleading impression".

> I would have added that there are a few
> more pages on the MLton web site that are relevant to the Ocaml vs SML
> table:
>
> To "Records can be (ab)used to get the same effect" I would add a link
> to
> http://mlton.org/ObjectOrientedProgramming .
> To "Records must be copied manually" I would add a link to
> http://mlton.org/FunctionalRecordUpdate .
> To "Define infix operators only for the local scope" I would add a link
> to
> http://mlton.org/InfixingOperators .
> To "verbose grammar [...] curried anonymous functions" I would add a
> link to
> http://mlton.org/ProductType .
>
> I have to say that I'm not suprised about your unwillingness to
> conscientiously provide unbiased information.


That'll all great stuff, thanks. I'll add links when I can find the time.

> A couple more. To "Many incompatible compilers (MLton, SML/NJ, ML-kit,
> PolyML, MoscowML, ...)" I would add a note that SML is fairly unique in
> that it actually has a formal standard
>
> http://mlton.org/DefinitionOfStandardML


Yes. I addressed this in the thread on c.l.functional. IMHO, having a
formally-defined standard has not lived up to expectations. Specifically, I
could not compile the same SML code with different SML compilers.

In contrast, OCaml lacks a standard but has implementations that share the
same front-end. Consequently, there are fewer compatibility problems with
ocamlc, ocamlopt etc. than there are with SML/NJ and MLton.

In theory, having completely separate implementations (such as SML/NJ and
MLton) will improve stability. In practice, I have never come across any
errors in the OCaml compilers but I have had problems caused by the
immaturity of the SML compilers, e.g. when reporting errors, which
(perhaps) could have been avoided had the SML/NJ and MLton authors
collaborated rather than competed.

I should probably add those paragraphs to the web page as well...

> unlike Ocaml. The incompatibilities referred to by Jon, AFAIK, are at the
> level of invoking the various compilers rather than at the core language
> level.


No. SML/NJ and MLton also inferred different types for one of my functions.
I think this is because there is no notion of a compilation unit in SML. So
SML/NJ treats the program as a sequence of separate definitions and MLton
analyses the whole program in one go.

> Here is what Bjarne
> Stroustrup says in book The Design and Evolution of C++ (on page 5):
>
> "Several reviewers have asked me to compare C++ to other languages. This
> I have decided against doing. Thereby, I have reaffirmed a long-standing
> and strongly held view: Language comparisons are rarely meaningful and
> even less often fair. A good comparison of major programming languages
> requires more effort than most people are willing to spend, experience
> in a wide range of application areas, a rigid maintenance of a detached
> and impartial point of view, and a sense of fairness."
>
> It seems to me that Jon lacks all of the qualities that Stroustrup
> identifies. I think that we need comp.lang.ocaml.advocacy.


It would be more productive if you wrote a web page detailing your own
language comparison rather than trying to find fault in mine. I will be
genuinely interested to read it.

I am happy to say that an enormous number of people have sent kind words
regarding my work on the ray tracer. It was a very gratifying exercise.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Joe Marshall

2005-08-07, 5:02 pm

Joe Marshall <prunesquallor@comcast.net> writes:

> I'm gonna play with it over the wend and see if I can't get better
> performance.


This version is an order of magnitude faster than the original
version.

;; A bare-bones ray tracer
;;
;; Original code by Jon Harrop http://www.ffconsultancy.com/
;; Ported to Scheme by Jan Van lent http://www.cs.kuleuven.be/~jvl/
;; Minor changes for MIT Scheme by jrm

;; Notes:

;; Kudos to Jan Van lent for taking the time to port this to Scheme.

;; The constant infinity is generated by dividing by zero. This may
;; not work in other implementations. Replace it by as large a
;; float as possible.

;; The value of N (image width in pixels) is hard wired at 100 rather
;; than being taken from the command line.

;; Recommended compiler switches for MIT Scheme:
;; (set! compiler:compile-by-procedures? #f)
;; (set! compiler:generate-range-checks? #f)
;; (set! compiler:generate-stack-checks? #t)
;; (set! compiler:generate-type-checks? #f)
;; (set! compiler:open-code-floating-point-arithmetic? #t)
;; (set! compiler:open-code-primitives? #t)

;; Optimizations:
;; 1. Generic arithmetic operators replaced with floating point
;; operators.
;;
;; 2. Use floating vectors for point representation.
;;
;; 3. Inline vector math.
;;
;; 4. Use CPS V-V and spread DOT in ray-sphere.

;; P3 800 MHz
;; Unoptimized 72 seconds.
;; Optimized 7.1 seconds.

(declare (usual-integrations)
(automagic-integrations))

(define-integrable (make-point x y z)
(let ((point (flo:vector-cons 3)))
(flo:vector-set! point 0 x)
(flo:vector-set! point 1 y)
(flo:vector-set! point 2 z)
point))

(define-integrable infinity (/ 1.0 0.0))
(define-integrable epsilon 1e-15)

(declare (integrate s*v v+v cpsv-v v-v unitise ray-sphere))
(define (s*v s b)
(make-point
(flo:* s (flo:vector-ref b 0))
(flo:* s (flo:vector-ref b 1))
(flo:* s (flo:vector-ref b 2))))

(define (v+v a b)
(make-point
(flo:+ (flo:vector-ref a 0) (flo:vector-ref b 0))
(flo:+ (flo:vector-ref a 1) (flo:vector-ref b 1))
(flo:+ (flo:vector-ref a 2) (flo:vector-ref b 2))))

(define (v-v a b)
(make-point
(flo:- (flo:vector-ref a 0) (flo:vector-ref b 0))
(flo:- (flo:vector-ref a 1) (flo:vector-ref b 1))
(flo:- (flo:vector-ref a 2) (flo:vector-ref b 2))))

(define (cpsv-v a b receiver)
(declare (integrate receiver))
(receiver
(flo:- (flo:vector-ref a 0) (flo:vector-ref b 0))
(flo:- (flo:vector-ref a 1) (flo:vector-ref b 1))
(flo:- (flo:vector-ref a 2) (flo:vector-ref b 2))))

(define-integrable (dot a b)
(flo:+ (flo:* (flo:vector-ref a 0) (flo:vector-ref b 0))
(flo:+ (flo:* (flo:vector-ref a 1) (flo:vector-ref b 1))
(flo:* (flo:vector-ref a 2) (flo:vector-ref b 2)))))

(define-integrable (dot1 ax ay az b)
(flo:+ (flo:* ax (flo:vector-ref b 0))
(flo:+ (flo:* ay (flo:vector-ref b 1))
(flo:* az (flo:vector-ref b 2)))))

(define-integrable (dot2 ax ay az bx by bz)
(flo:+ (flo:* ax bx)
(flo:+ (flo:* ay by)
(flo:* az bz))))

(define (unitise r) (s*v (flo:/ 1.0 (flo:sqrt (dot r r))) r))

(define (ray-sphere orig dir center radius)
(cpsv-v
center orig
(lambda (vx vy vz)
(let* ((b (dot1 vx vy vz dir))
(disc (flo:+ (flo:- (flo:* b b) (dot2 vx vy vz vx vy vz)) (flo:* radius radius))))
(if (flo:< disc 0.0) infinity
(let ((t2 (flo:+ b (flo:sqrt disc))))
(if (flo:< t2 0.0) infinity
(let ((t1 (flo:- b (flo:sqrt disc))))
(if (flo:> t1 0.0) t1 t2)))))))))

(define-integrable zero (make-point 0.0 0.0 0.0))

(define (intersect orig dir obj)
(let lp ((obj obj) (hit (list infinity zero)))
(let ((l (ray-sphere orig dir (car obj) (cadr obj))))
(cond ((flo:>= l (car hit)) hit)
((pair? (cddr obj)) (fold-right lp hit (cddr obj)))
((null? (cddr obj)) (list l (unitise (v+v orig (v-v (s*v l dir) (car obj))))))
(else (error "Bad obj" obj))))))

(define neg_light (unitise (make-point 1.0 3.0 -2.0)))
(define orig (make-point 0.0 0.0 -4.0))

(define (trace dir scene)
(let* ((hit (intersect orig dir scene))
(lam (car hit))
(normal (cadr hit)))
(cond ((flo:>= lam infinity) 0.0)
((flo:< (car (intersect (v+v orig (v+v (s*v lam dir) (s*v (flo:sqrt epsilon) normal)))
neg_light scene))
infinity) 0.0)
(else (flo:max 0.0 (dot normal neg_light))))))

(define (create level c r)
(let ((obj (list c r))
(a (* 3.0 (/ r (sqrt 12.0)))))
(if (= level 1) obj
(let ((aux (lambda (x z)
(create (- level 1) (v+v c (make-point x a z)) (* 0.5 r)))))
(list c (* 3.0 r)
obj (aux (- a) (- a)) (aux a (- a)) (aux (- a) a)
(aux a a))))))

(define level 6)
;(define n (string->number (car *argv*)))
(define n 100)
(define ss 4)
(define scene (create level (make-point 0.0 -1.0 0.0) 1.0))
(define ss2 (* ss ss))

(define (aux x d) (+ (- x (/ n 2.0)) (/ d ss)))

(define (g x y)
(do ((dx 0 (+ dx 1))
(sum 0 (do ((dy 0 (+ dy 1))
(sum sum (+ sum (trace (unitise
(make-point (aux x dx)
(aux (- (- n 1) y) dy)
(exact->inexact n)))
scene))))
((>= dy ss) sum))))
((>= dx ss) sum)))

(define (pixel x y)
(write-char
(ascii->char
(inexact->exact
(truncate (+ 0.5 (* 255 (/ (g x y) ss2))))))))

(define (go)
(let ((start-time (runtime)))
(gc-flip)
(with-output-to-binary-file
"scheme.pgm"
(lambda ()
(for-each display (list "P5" #\newline
n #\space n
#\newline 255
#\newline))
(do ((y 0 (+ y 1)))
((>= y n))
(do ((x 0 (+ x 1)))
((>= x n))
(pixel x y)))))
(- (runtime) start-time)))




--
~jrm
Vesa Karvonen

2005-08-07, 5:02 pm

Jon Harrop <usenet@jdh30.plus.com> wrote:
> Vesa Karvonen wrote:


> I should probably add those paragraphs to the web page as well...


Sounds good.

[color=darkred]
> No. SML/NJ and MLton also inferred different types for one of my functions.
> I think this is because there is no notion of a compilation unit in SML. So
> SML/NJ treats the program as a sequence of separate definitions and MLton
> analyses the whole program in one go.


Ok. If I recall correctly, then this was easy to workaround by using a
type annotation or two. However, it still seems to me that your main gripe
with the SML compilers was the lack of standard for producing a
stand-alone executable. Do you have a link to a discussion that clearly
shows otherwise?

> It would be more productive if you wrote a web page detailing your own
> language comparison rather than trying to find fault in mine. I will be
> genuinely interested to read it.


I try to avoid doing language comparisons with the purpose of advocating a
language. If you look at my comments in the comp.lang.functional
discussion, I think that you should see that I tried to explore the pros
and cons from both sides (OCaml vs SML).

> I am happy to say that an enormous number of people have sent kind words
> regarding my work on the ray tracer. It was a very gratifying exercise.


To be fair, I find your ray tracer quite interesting. It has some merit.
However, the conclusions you make from your experiment are, IMO, biased.
The most subjective issue, IMO, is your notion of verbosity, which is
highly subjective and biased in favor of your personal programming style
in Ocaml. Judging from my experience in Ocaml and from the remarks made by
others, your formatting style is neither representative nor particularly
commendable. LOC is clearly not a good way to quantify the verbosity of
programming languages, because the variation within a language can easily
be a factor of 3 (or more) higher than between similar languages. As I
have argued elsewhere, I think that you would get much more meaningful
results by simply running `wc -w' rather than `wc -l' (and even more
meaningful results with an accurate token counting program).

-Vesa Karvonen
Jon Harrop

2005-08-07, 5:02 pm

Vesa Karvonen wrote:
>
> Ok. If I recall correctly, then this was easy to workaround by using a
> type annotation or two.


Yes, once I realised what was going on I worked around the incompatibility
with a simple annotation.

> However, it still seems to me that your main gripe
> with the SML compilers was the lack of standard for producing a
> stand-alone executable. Do you have a link to a discussion that clearly
> shows otherwise?


Yes, my main gripe is with SML/NJ's bizarre way of creating executables. For
tiny projects (e.g. newbies) that was a real stumbling block. I never
mastered Matthias' solution.

>
> I try to avoid doing language comparisons with the purpose of advocating a
> language.


I do my best to be impartial. I am a scientist after all. :-)

> If you look at my comments in the comp.lang.functional
> discussion, I think that you should see that I tried to explore the pros
> and cons from both sides (OCaml vs SML).


Yes. I tried to weight up the comments that I got from everyone. Overall, I
had far more people write to me or talk to me to say that they mostly
agreed with my comments. Including many SML programmers.

>
> To be fair, I find your ray tracer quite interesting. It has some merit.
> However, the conclusions you make from your experiment are, IMO, biased.
> The most subjective issue, IMO, is your notion of verbosity, which is
> highly subjective and biased in favor of your personal programming style
> in Ocaml.


I adopted the LOC measure from the shootout, rather than choosing it because
OCaml came out on top. I agree with Matthias Blume's comments that, with
such an erroneous measure, there is no significant difference between SML
and OCaml. Also, Diego (who has done more programming in SML than me) said
that he had found SML to be more concise when dealing with sophisticated
data structures than my ray tracer example implies.

> Judging from my experience in Ocaml and from the remarks made by
> others, your formatting style is neither representative nor particularly
> commendable.


My OCaml style is somewhat unusual. Two of the SML ports that I was sent
different by a factor of 2 in LOC. I chose the shorter of the two.

> LOC is clearly not a good way to quantify the verbosity of
> programming languages, because the variation within a language can easily
> be a factor of 3 (or more) higher than between similar languages.


Yes.

> As I
> have argued elsewhere, I think that you would get much more meaningful
> results by simply running `wc -w' rather than `wc -l' (and even more
> meaningful results with an accurate token counting program).


No. I found words to be a worse measure of verbosity than LOC because they
fail to take into account tokens. Specifically, a Fortran advocate (with
the nic "Beliavsky") proposed words as a means of comparing verbosity. My
results showed that Fortran was much more verbose in terms of lines and
characters (and also tokens) but not for words. The reason was simply that
Fortran programmers (at least that one) don't put spaces between things
like symbols, commas and so on, giving the illusion that whole lines of
code were actually single words.

Ultimately, I decidedly quite quickly that all measures of verbosity were
flawed so I didn't put any more effort into honing my choice of measure.
I'm sure it can be improved upon but it would take a lot of work, e.g. a
study of lots of real code.

For a fun miniproject, I am very happy with my ray tracer. I would advise
people not to take it too seriously though...

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-07, 5:02 pm

Joe Marshall wrote:
> Joe Marshall <prunesquallor@comcast.net> writes:
>
>
> This version is an order of magnitude faster than the original
> version.


Wow! :-)

I've never used MIT-Scheme before but I just fired it up and cut and pasted
your code into the top level (replacing infinity with 1000). Curiously, it
is faster without the compiler switches. On a 1.2GHz Athlon T-bird, I get
21.98s for level=6, n=160 and ss=4 which compares to 23.3s for my most
concise OCaml implementation. Not bad!

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Kjetil Svalastog Matheussen

2005-08-07, 5:02 pm



On Sun, 7 Aug 2005, Joe Marshall wrote:

> Joe Marshall <prunesquallor@comcast.net> writes:
>
>
> This version is an order of magnitude faster than the original
> version.
>


I fixed your code so that it compiles with stalin:
[kjetil@ttleush2 stalin-0.10alpha2]$ time ./ray-tracker >gakk.pgm

real 0m1.480s
user 0m1.141s
sys 0m0.008s
[kjetil@ttleush2 stalin-0.10alpha2]$

I haven't measured to accurately, but this ieems to be about the same
speed as the c++-version.

This version is fairly compatible with all scheme-implementation s as
well, I think...


(Some srfi-1-code pasted from guile-srfi-1 at the top)


(define map1 map)
(define (any1 pred ls)
(let lp ((ls ls))
(cond ((null? ls)
#f)
((null? (cdr ls))
(pred (car ls)))
(else
(or (pred (car ls)) (lp (cdr ls)))))))
(define (any pred ls . lists)
(if (null? lists)
(any1 pred ls)
(let lp ((lists (cons ls lists)))
(cond ((any1 null? lists)
#f)
((any1 null? (map1 cdr lists))
(apply pred (map1 car lists)))
(else
(or (apply pred (map1 car lists)) (lp (map1 cdr
lists))))))))
(define (fold-right kons knil clist1 . rest)
(if (null? rest)
(let f ((list1 clist1))
(if (null? list1)
knil
(kons (car list1) (f (cdr list1)))))
(let f ((lists (cons clist1 rest)))
(if (any null? lists)
knil
(apply kons (append (map1 car lists) (list (f (map1 cdr
lists)))))))))
(define (with-output-to-binary-file filename thunk)
(thunk))
(define ascii->char integer->char)


;;Stalin didn't like vectors very much...
(define vector list)
(define vector-ref list-ref)


(define (make-point x y z)
(vector x y z))
; (let ((point (vector-cons 3)))
; (vector-set! point 0 x)
; (vector-set! point 1 y)
; (vector-set! point 2 z)
; point))

(define infinity (/ 1.0 0.0))
(define epsilon 1e-15)

(define (s*v s b)
(make-point
(* s (vector-ref b 0))
(* s (vector-ref b 1))
(* s (vector-ref b 2))))

(define (v+v a b)
(make-point
(+ (vector-ref a 0) (vector-ref b 0))
(+ (vector-ref a 1) (vector-ref b 1))
(+ (vector-ref a 2) (vector-ref b 2))))

(define (v-v a b)
(make-point
(- (vector-ref a 0) (vector-ref b 0))
(- (vector-ref a 1) (vector-ref b 1))
(- (vector-ref a 2) (vector-ref b 2))))

(define (cpsv-v a b receiver)
(receiver
(- (vector-ref a 0) (vector-ref b 0))
(- (vector-ref a 1) (vector-ref b 1))
(- (vector-ref a 2) (vector-ref b 2))))

(define (dot a b)
(+ (* (vector-ref a 0) (vector-ref b 0))
(+ (* (vector-ref a 1) (vector-ref b 1))
(* (vector-ref a 2) (vector-ref b 2)))))

(define (dot1 ax ay az b)
(+ (* ax (vector-ref b 0))
(+ (* ay (vector-ref b 1))
(* az (vector-ref b 2)))))

(define (dot2 ax ay az bx by bz)
(+ (* ax bx)
(+ (* ay by)
(* az bz))))

(define (unitise r) (s*v (/ 1.0 (sqrt (dot r r))) r))


(define (ray-sphere orig dir center radius)
(cpsv-v
center orig
(lambda (vx vy vz)
(let* ((b (dot1 vx vy vz dir))
(disc (+ (- (* b b) (dot2 vx vy vz vx vy vz)) (* radius
radius))))
(if (< disc 0.0) infinity
(let ((t2 (+ b (sqrt disc))))
(if (< t2 0.0) infinity
(let ((t1 (- b (sqrt disc))))
(if (> t1 0.0) t1 t2)))))))))

(define zero (make-point 0.0 0.0 0.0))

(define (intersect orig dir obj)
(let lp ((obj obj) (hit (list infinity zero)))
(let ((l (ray-sphere orig dir (car obj) (cadr obj))))
(cond ((>= l (car hit)) hit)
((pair? (cddr obj)) (fold-right lp hit (cddr obj)))
((null? (cddr obj)) (list l (unitise (v+v orig (v-v (s*v l
dir) (car obj))))))
(else (display "Bad obj")(display obj)(newline))))))

(define neg_light (unitise (make-point 1.0 3.0 -2.0)))
(define orig (make-point 0.0 0.0 -4.0))

(define (trace dir scene)
(let* ((hit (intersect orig dir scene))
(lam (car hit))
(normal (cadr hit)))
(cond ((>= lam infinity) 0.0)
((< (car (intersect (v+v orig (v+v (s*v lam dir) (s*v (sqrt
epsilon) normal)))
neg_light scene))
infinity) 0.0)
(else (max 0.0 (dot normal neg_light))))))

(define (create level c r)
(let ((obj (list c r))
(a (* 3.0 (/ r (sqrt 12.0)))))
(if (= level 1) obj
(let ((aux (lambda (x z)
(create (- level 1) (v+v c (make-point x a z)) (*
0.5 r)))))
(list c (* 3.0 r)
obj (aux (- a) (- a)) (aux a (- a)) (aux (- a) a)
(aux a a))))))

(define level 6)
;(define n (string->number (car *argv*)))
(define n 100)
(define ss 4)
(define scene (create level (make-point 0.0 -1.0 0.0) 1.0))
(define ss2 (* ss ss))

(define (aux x d) (+ (- x (/ n 2.0)) (/ d ss)))

(define (g x y)
(do ((dx 0 (+ dx 1))
(sum 0 (do ((dy 0 (+ dy 1))
(sum sum (+ sum (trace (unitise
(make-point (aux x dx)
(aux (- (- n 1) y)
dy)
(exact->inexact
n)))
scene))))
((>= dy ss) sum))))
((>= dx ss) sum)))

(define (pixel x y)
(write-char
(ascii->char
(inexact->exact
(truncate (+ 0.5 (* 255 (/ (g x y) ss2))))))))

(define n2 n)
(define (go)
(with-output-to-binary-file
"scheme.pgm"
(lambda ()
(for-each display (list "P5" #\newline
n #\space n
#\newline 255
#\newline))
(do ((y 0 (+ y 1)))
((>= y n2))
(do ((x 0 (+ x 1)))
((>= x n))
(pixel x y))))))

(go)


Kjetil Svalastog Matheussen

2005-08-07, 5:02 pm



On Sun, 7 Aug 2005, Jon Harrop wrote:

> Joe Marshall wrote:
>
> Wow! :-)
>
> I've never used MIT-Scheme before but I just fired it up and cut and pasted
> your code into the top level (replacing infinity with 1000). Curiously, it
> is faster without the compiler switches. On a 1.2GHz Athlon T-bird, I get
> 21.98s for level=6, n=160 and ss=4 which compares to 23.3s for my most
> concise OCaml implementation. Not bad!


For your information, stalin use 2.8 seconds on that calcualtion with my
AMD XP2800. Thats a lot faster.


--

Anton van Straaten

2005-08-07, 5:02 pm

Kjetil Svalastog Matheussen wrote:
>
> On Sun, 7 Aug 2005, Jon Harrop wrote:
>
>
> For your information, stalin use 2.8 seconds on that calcualtion with my
> AMD XP2800. Thats a lot faster.


Uh-oh. Folks, brace yourselves for the sudden influx of
performance-obsessed OCamlites! ;oP

Seriously, Jon's statement about the "most concise OCaml implementation"
makes me wonder how the fastest OCaml implementation compares.

Anton
Anton van Straaten

2005-08-07, 5:02 pm

Vesa Karvonen wrote:
> Also, regarding contributions, I think that it would be appropriate to put
> a link to the page
>
> http://www.mlton.org/ForLoops
>
> in conjunction with the comment that SML has "Only while loops" in the
> "Conclusions" section of the page


Nice page. I like the example at the end:

for (0 to 10 when (fn x => x mod 3 <> 0)
&& inList ["a", "b"] && 2 downto 1 by real)
(fn x & y & z =>
print ("("^Int.toString x^", \""^y^"\", "^Real.toString z^")\n"))

Wow! Nice to see someone finally giving Common Lisp's LOOP macro a run
for its money! ;)

Anton
Jon Harrop

2005-08-07, 5:02 pm

Anton van Straaten wrote:
> Kjetil Svalastog Matheussen wrote:

I'm just downloading Stalin...
[color=darkred]
> Uh-oh. Folks, brace yourselves for the sudden influx of
> performance-obsessed OCamlites! ;oP


:-)

I'm interested in the spectrum of brevity vs performance, provided the
programs aren't so slow that they can't feasibly be run with level=6, n=512
and ss=4 as I did for my site. The new breed of Lisp/Scheme programs are
certainly fast enough to satisfy that.

> Seriously, Jon's statement about the "most concise OCaml implementation"
> makes me wonder how the fastest OCaml implementation compares.


For equivalent performance, we should probably compare with the first (least
optimised) OCaml implementation on my web site. That is 59 LOC and about 6x
faster than the one I posted.

I believe the Scheme programs are equivalent to that one but there are
better optimised programs in all languages (algorithmic optimisations).

Can anyone give me a link to some introductory information about the
different implementations? I have no idea how MIT-Scheme, Stalin, Bigloo
etc. differ.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Anton van Straaten

2005-08-07, 5:02 pm

Jon Harrop wrote:
> Can anyone give me a link to some introductory information about the
> different implementations? I have no idea how MIT-Scheme, Stalin, Bigloo
> etc. differ.


See this page:
http://community.schemewiki.org/?ca...implementations

It has decent summaries for Bigloo and Stalin:
http://community.schemewiki.org/?Bigloo
http://community.schemewiki.org/?Stalin

I don't see MIT Scheme mentioned there. MIT Scheme is a compiler which
emits Intel native code.

Anton
Jens Axel Søgaard

2005-08-07, 5:02 pm

Jon Harrop wrote:

> Can anyone give me a link to some introductory information about the
> different implementations? I have no idea how MIT-Scheme, Stalin, Bigloo
> etc. differ.


Don't forget Gambit in your list of fast Scheme implementations.

<http://www.iro.umontreal.ca/~gambit/>

For information on the various compilers see

<http://library.readscheme.org/page8.html>

--
Jens Axel Søgaard

Jon Harrop

2005-08-07, 5:02 pm

Anton van Straaten wrote:
> Wow! Nice to see someone finally giving Common Lisp's LOOP macro a run
> for its money! ;)


Yes, that's a idea. I wrote an interpreter for a new language that
allows typeset mathematical expressions like this:

# \Union_(j in {1, 2, 3, 4}) {j, j^2};;
- : int set = {1, 2, 3, 4, 9, 16, 81}

So the subscript of "\Union" means something similar. I'm not sure how
useful this would be in practice. I think perhaps it is best left as an
educational exercise to show people that the above can be written
equivalently (in pseudo-code) as a fold:

fold_left (fun j -> {j, j^2}) {} {1, 2, 3, 4}

Might help to reduce some of the fright of functional programming. :-)

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-07, 5:02 pm

Jon Harrop wrote:
> I've never used MIT-Scheme before but I just fired it up and cut and
> pasted your code into the top level (replacing infinity with 1000).
> Curiously, it is faster without the compiler switches. On a 1.2GHz Athlon
> T-bird, I get 21.98s for level=6, n=160 and ss=4 which compares to 23.3s
> for my most concise OCaml implementation. Not bad!


Correction - I had downclocked it to 900MHz.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-07, 5:02 pm

Kjetil Svalastog Matheussen wrote:
> For your information, stalin use 2.8 seconds on that calcualtion with my
> AMD XP2800. Thats a lot faster.


I just installed Stalin but I can't get it to compile the code. I just get:

$ stalin -On ray6.scm
ray6.scm:47:1425:Unbound variable

Did you make any changes or am I doing something silly?

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Kjetil Svalastog Matheussen

2005-08-07, 5:02 pm



On Sun, 7 Aug 2005, Jon Harrop wrote:

> Kjetil Svalastog Matheussen wrote:
>
> I just installed Stalin but I can't get it to compile the code. I just get:
>
> $ stalin -On ray6.scm
> ray6.scm:47:1425:Unbound variable
>
> Did you make any changes or am I doing something silly?
>


Don't know....

Heres my make-script:

"
#!/bin/sh
ulimit -s unlimited
ulimit -c 0
../stalin -d0 -d1 -d5 -d6 -On\
-cc /usr/gcc4/bin/gcc -copt -O3 -copt -fomit-frame-pointer -copt -ffast-math -copt -Wall -copt -freg-struct-return\
$1
"

....Which I call like this:

"./make ray-tracer"


And heres the content of "ray-tracer.sc": (a bit more optimized than the
last one I posted)



(define map1 map)
(define (any1 pred ls)
(let lp ((ls ls))
(cond ((null? ls)
#f)
((null? (cdr ls))
(pred (car ls)))
(else
(or (pred (car ls)) (lp (cdr ls)))))))
(define (any pred ls . lists)
(if (null? lists)
(any1 pred ls)
(let lp ((lists (cons ls lists)))
(cond ((any1 null? lists)
#f)
((any1 null? (map1 cdr lists))
(apply pred (map1 car lists)))
(else
(or (apply pred (map1 car lists)) (lp (map1 cdr
lists))))))))
(define (fold-right kons knil clist1 . rest)
(if (null? rest)
(let f ((list1 clist1))
(if (null? list1)
knil
(kons (car list1) (f (cdr list1)))))
(let f ((lists (cons clist1 rest)))
(if (any null? lists)
knil
(apply kons (append (map1 car lists) (list (f (map1 cdr
lists)))))))))
(define (with-output-to-binary-file filename thunk)
(thunk))
(define ascii->char integer->char)

(define get0 car)
(define get1 cadr)
(define get2 caddr)

(define make-point list)

(define infinity (/ 1.0 0.0))
(define epsilon 1e-15)

(define (s*v s b) (map (lambda (t) (* s t)) b))
(define (v+v a b)
(make-point
(+ (get0 a) (get0 b))
(+ (get1 a) (get1 b))
(+ (get2 a) (get2 b))))

(define (v-v a b)
(make-point
(- (get0 a) (get0 b))
(- (get1 a) (get1 b))
(- (get2 a) (get2 b))))

(define (cpsv-v a b receiver)
(receiver
(- (get0 a) (get0 b))
(- (get1 a) (get1 b))
(- (get2 a) (get2 b))))

(define (dot a b)
(+ (* (get0 a) (get0 b))
(+ (* (get1 a) (get1 b))
(* (get2 a) (get2 b)))))

(define (dot1 ax ay az b)
(+ (* ax (get0 b))
(+ (* ay (get1 b))
(* az (get2 b)))))

(define (dot2 ax ay az bx by bz)
(+ (* ax bx)
(+ (* ay by)
(* az bz))))

(define (unitise r) (s*v (/ 1.0 (sqrt (dot r r))) r))


(define (ray-sphere orig dir center radius)
(cpsv-v
center orig
(lambda (vx vy vz)
(let* ((b (dot1 vx vy vz dir))
(disc (+ (- (* b b) (dot2 vx vy vz vx vy vz)) (* radius
radius))))
(if (< disc 0.0) infinity
(let ((t2 (+ b (sqrt disc))))
(if (< t2 0.0) infinity
(let ((t1 (- b (sqrt disc))))
(if (> t1 0.0) t1 t2)))))))))

(define zero (make-point 0.0 0.0 0.0))

(define (intersect orig dir obj)
(let lp ((obj obj) (hit (list infinity zero)))
(let ((l (ray-sphere orig dir (car obj) (cadr obj))))
(cond ((>= l (car hit)) hit)
((pair? (cddr obj)) (fold-right lp hit (cddr obj)))
((null? (cddr obj)) (list l (unitise (v+v orig (v-v (s*v l
dir) (car obj))))))
(else (display "Bad obj")(display obj)(newline))))))

(define neg_light (unitise (make-point 1.0 3.0 -2.0)))
(define orig (make-point 0.0 0.0 -4.0))

(define (trace dir scene)
(let* ((hit (intersect orig dir scene))
(lam (car hit))
(normal (cadr hit)))
(cond ((>= lam infinity) 0.0)
((< (car (intersect (v+v orig (v+v (s*v lam dir) (s*v (sqrt
epsilon) normal)))
neg_light scene))
infinity) 0.0)
(else (max 0.0 (dot normal neg_light))))))

(define (create level c r)
(let ((obj (list c r))
(a (* 3.0 (/ r (sqrt 12.0)))))
(if (= level 1) obj
(let ((aux (lambda (x z)
(create (- level 1) (v+v c (make-point x a z)) (*
0.5 r)))))
(list c (* 3.0 r)
obj (aux (- a) (- a)) (aux a (- a)) (aux (- a) a)
(aux a a))))))

(define level 6)
;(define n (string->number (car *argv*)))
(define n 100)
(define ss 4)
(define scene (create level (make-point 0.0 -1.0 0.0) 1.0))
(define ss2 (* ss ss))

(define (aux x d) (+ (- x (/ n 2.0)) (/ d ss)))

(define (g x y)
(do ((dx 0 (+ dx 1))
(sum 0 (do ((dy 0 (+ dy 1))
(sum sum (+ sum (trace (unitise
(make-point (aux x dx)
(aux (- (- n 1) y)
dy)
(exact->inexact
n)))
scene))))
((>= dy ss) sum))))
((>= dx ss) sum)))

(define (pixel x y)
(write-char
(ascii->char
(inexact->exact
(truncate (+ 0.5 (* 255 (/ (g x y) ss2))))))))

(define n2 n)
(define (go)
(with-output-to-binary-file
"scheme.pgm"
(lambda ()
(for-each display (list "P5" #\newline
n #\space n
#\newline 255
#\newline))
(do ((y 0 (+ y 1)))
((>= y n2))
(do ((x 0 (+ x 1)))
((>= x n))
(pixel x y))))))

(go)


Jens Axel Søgaard

2005-08-07, 5:02 pm

Jon Harrop wrote:
> Kjetil Svalastog Matheussen wrote:
>
>
>
> I just installed Stalin but I can't get it to compile the code. I just get:
>
> $ stalin -On ray6.scm
> ray6.scm:47:1425:Unbound variable
>
> Did you make any changes or am I doing something silly?


Just checking: Did you download the same version of Stalin
as Kjetil is using (i.e. 0.10alpha) or the easy-to-find
version 0.9 ?

--
Jens Axel Søgaard
Kjetil Svalastog Matheussen

2005-08-07, 5:02 pm



On Sun, 7 Aug 2005, Jens Axel Søgaard wrote:

> Jon Harrop wrote:
>
> Just checking: Did you download the same version of Stalin
> as Kjetil is using (i.e. 0.10alpha) or the easy-to-find
> version 0.9 ?


Hmm, by the way, 0.9 might run faster since 0.10alpha segfaults with
vectors for this program...


--

Mike Austin

2005-08-07, 5:02 pm

For the people not familiar with ray tracing terminology, can you
explain the variables such as v, b, t1, p, g, ss? p == pixel?

Thanks,
Mike
Jon Harrop

2005-08-07, 5:02 pm

Anton van Straaten wrote:
> Kjetil Svalastog Matheussen wrote:

I'm just downloading Stalin...
[color=darkred]
> Uh-oh. Folks, brace yourselves for the sudden influx of
> performance-obsessed OCamlites! ;oP


:-)

I'm interested in the spectrum of brevity vs performance, provided the
programs aren't so slow that they can't feasibly be run with level=6, n=512
and ss=4 as I did for my site. The new breed of Lisp/Scheme programs are
certainly fast enough to satisfy that.

> Seriously, Jon's statement about the "most concise OCaml implementation"
> makes me wonder how the fastest OCaml implementation compares.


For equivalent performance, we should probably compare with the first (least
optimised) OCaml implementation on my web site. That is 59 LOC and about 6x
faster than the one I posted.

I believe the Scheme programs are equivalent to that one but there are
better optimised programs in all languages (algorithmic optimisations).

Can anyone give me a link to some introductory information about the
different implementations? I have no idea how MIT-Scheme, Stalin, Bigloo
etc. differ.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-07, 5:02 pm

Mike Austin wrote:
> For the people not familiar with ray tracing terminology, can you
> explain the variables such as v, b, t1, p, g, ss? p == pixel?


Sure:

The code begins with vector-related definitions (scaling, addition,
subtraction, dot product and unitise).

The "ray_sphere" function computes the parametric intersection of a ray
(origin "orig" and direction "dir" vectors) with a sphere (center vector
and radius). The variables "v" and "b" have no special meaning - they are
just common subexpressions here. The variables "t1" and "t2" are the
parameters of the two intersections. They may be negative but the answer
must be non-negative (because the ray is only semi-infinite, starting at
its origin).

The "intersect" function computes the first intersection (smallest positive
parameter) of a ray with a scene. The variable "l" is short for lambda, the
parameter at the closest point of intersection. The intersect function is
replaced with one that includes an initial accumulator with lambda=infinity
and a (dummy) zero normal vector.

The scene is either a sphere or a group of spheres with a bounding sphere.

The "trace" function computes the intersection of an eye ray (a ray cast
from the camera) with the scene. A "shadow ray" is then cast from the point
of intersection (orig + lambda*dir) towards the light. If the shadow ray
intersects the scene then the point is in shadow.

The "create" function builds a scene recursively. The "obj" variable is the
sphere at the current level, centered at "c" and with radius "r". The next
level of spheres has a smaller radius "a". Each subsequent level is
packaged in a "Group" with a bounding sphere also centered at "c" but with
radius "3r".

The "level" variable is the number of levels of spheres to be drawn, "n" is
the number of pixels along each side of the square pixmap that is
generated, pixels are supersampled by averaging an "ss" x "ss" grid of
rays.

The first "Print.printf" prints the PGM header of the output pixmap.

The "range" function is like a "for" loop but it accumulates its result.

The "ray" function casts a single ray. The "g" variable in it is the
accumulated grayscale (a float).

The "g" function averages the ss*ss rays for a single pixel.

The "pixel" function outputs the grayscale for the given pixel as a single
byte.

There is a detailed code comparison between C++ and OCaml which also
describes what the programs do, here:

http://www.ffconsultancy.com/free/r...comparison.html

I strongly recommend learning a bit about ray tracing if you've never done
it before. It's really good fun!

I've had a lot of constructive feedback about my ray tracer from people over
the past few months. Rereading some posts by Alex Goldman yesterday got me
thinking that maybe I should work on the ray tracer a little more, to
introduce new functionality rather than to improve performance, because he
was asking if ML-style variants are as extensible as OO.

Anyway, I'm keen to see how Lisp and Scheme do. I was under the impression
that they couldn't approach the performance of the other languages (C++,
Java, SML, OCaml) but I have already been proven wrong. I don't think the
free compilers will be beating any speed records on this task but they are
doing much better than I had expected.

HTH.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
Jon Harrop

2005-08-07, 5:02 pm

Vesa Karvonen wrote:
> A couple more. To "Many incompatible compilers (MLton, SML/NJ, ML-kit,
> PolyML, MoscowML, ...)" I would add a note that SML is fairly unique in
> that it actually has a formal standard
>
> http://mlton.org/DefinitionOfStandardML
>
> unlike Ocaml. The incompatibilities referred to by Jon, AFAIK, ar