[racket] Typed Racket Binding For Plot

7 views
Skip to first unread message

Ray Racine

unread,
Oct 27, 2012, 1:57:23 PM10/27/12
to Racket
Racket Committers,

Noticed in the RacketCon that it was mentioned that there were nothing to lift the plot collection into TR.  Awhile back I did do a run at a fairly comprehensive TRing of the Plot collection.  All the basic things (basic plots etc) I attempted worked just fine.  While  I haven't used plot since, it currently builds without error against the current Racket Git Master.

In general, I'd like to think that most of the heavy lifting is out of the way  in the sense of all the inane typing, but may require some polish.

With the new release over, I'd like to start getting it merged into Racket.  Next steps???

Thanks,

Ray

Neil Toronto

unread,
Oct 29, 2012, 12:31:56 AM10/29/12
to us...@racket-lang.org

Ah, I should have replied to this email before, not the other one. Well,
I'm catching up.

I think the next step is to wait for me to be free to work on it.

IIRC, there were two issues with TR-ing plot:

1. Typing functions that take optional arguments *and* keyword
arguments.

2. Mutable data types in input.

#1 is fixed *enough* now to put an actual TR face on plot without making
users write a bunch of `#f' in every function application. The issue
would be writing all the huge `case->' types. Not fun. TR needs a nicer
way to specify optional arguments---maybe something corresponding to a
`->*' contract.

Example of #2 is `points', which takes a (Listof (Vectorof Real)) IIRC.
The problem is that you can't send a (Listof (Vectorof Integer)) to a
function that accepts just that type, because vectors are mutable and
could be used as a communication channel. (Plot won't mutate them into
reals, but TR can't know that.) Fixing this requires either waiting for
possibly research-level changes to TR, or changing plot's API.

I wouldn't mind changing the API; it would be nice to have things like
`points' accept sequences anyway. I haven't put much thought into what
would be in the sequences, though.

So I suppose that would be a nice next step. What's an appropriate type
for pairs/triplets/tuples of numbers? Should we let it accept
(Sequenceof (U (Listof Real) (Vectorof Real)))? (Would that subtype
nicely?) Sequences of sequences?

Neil ⊥

____________________
Racket Users list:
http://lists.racket-lang.org/users

Matthias Felleisen

unread,
Oct 29, 2012, 9:03:01 AM10/29/12
to Neil Toronto, us...@racket-lang.org


On Oct 29, 2012, at 12:31 AM, Neil Toronto wrote:

> I wouldn't mind changing the API; it would be nice to have things like `points' accept sequences anyway. I haven't put much thought into what would be in the sequences, though.


Question: can you change the API for the Typed version and support both APIs for the Untyped one? -- Matthias

Neil Toronto

unread,
Nov 3, 2012, 11:13:05 AM11/3/12
to Matthias Felleisen, us...@racket-lang.org

More easily than the other way around. Also, that would work around the
covariance problem with vectors. I could change the contract to accept a
sequence of vectors or lists, and use the type (Sequenceof (List Real
Real)).

I still need a `->*' type constructor, because most plot functions have
2-5 optional arguments and 10-20 arguments altogether. For the largest
functions, a `case->' type would be huge and easy to get wrong. Also,
I'm morally opposed to types that don't fit on my screen.

I'll get around to submitting a formal request, after I get this Poisson
distribution quantile function working...

Matthias Felleisen

unread,
Nov 3, 2012, 11:20:36 AM11/3/12
to Neil Toronto, us...@racket-lang.org
Last night Sam, Tony and I had a discussion on TR/R boundaries
for his "racket on a router" project. Tony ported his software
from Racket to Typed Racket and stopped halfway in between. The
'framework' (aka kernel) is now in TR and the 'user program' aka
'client' lives in R. I had predicted that the boundary between the
two would cause a severe performance and Tony has now confirmed
this conjecture. (We are talking factors not small percentages.)

As you get racket/math ready for production, I think you too should
measure the performance hit from going across the boundary. If it
is bad, we should consider including both a typed and an untyped
variant where the latter is generated from the former (I believe
you are working in TR so that's why I wrote the last sentence).
That is, when the library is installed the Untyped one should be
generated by disabling types and type checking.

-- Matthias

Jay McCarthy

unread,
Nov 3, 2012, 11:41:25 AM11/3/12
to Matthias Felleisen, users
I have a little language for doing this:


run


to see the SEGFAULT

:)


____________________
  Racket Users list:
  http://lists.racket-lang.org/users




--
Jay McCarthy <j...@cs.byu.edu>
Assistant Professor / Brigham Young University
http://faculty.cs.byu.edu/~jay

"The glory of God is Intelligence" - D&C 93

Matthias Felleisen

unread,
Nov 3, 2012, 11:46:36 AM11/3/12
to Jay McCarthy, users

I was thinking of turning of type checking and the translation of types into contracts. (Unless I misunderstand your mini language, I think you're cheating in a more fundamental manner "-) 

Neil Toronto

unread,
Nov 3, 2012, 1:46:32 PM11/3/12
to Matthias Felleisen, us...@racket-lang.org
Moving to dev so as to not upset the locals with preliminary results. :D

On 11/03/2012 09:20 AM, Matthias Felleisen wrote:
> Last night Sam, Tony and I had a discussion on TR/R boundaries
> for his "racket on a router" project. Tony ported his software
> from Racket to Typed Racket and stopped halfway in between. The
> 'framework' (aka kernel) is now in TR and the 'user program' aka
> 'client' lives in R. I had predicted that the boundary between the
> two would cause a severe performance and Tony has now confirmed
> this conjecture. (We are talking factors not small percentages.)
>
> As you get racket/math ready for production, I think you too should
> measure the performance hit from going across the boundary.

I've already done that somewhat. First-order functions are okay; all the
new flonum functions, special functions, bigfloats, number theory, etc.,
run at a decent clip on the untyped side of the contract boundary. For
example, I get 4 million `gamma' applications per second in TR, and 1.2
million per second untyped.

(I think the difference for `gamma' is more about how well Vincent and
Matthew have done with TR's optimizer and the JIT. Thanks to their work,
computing gamma comes down to about 100 flops running right on the CPU.)

Higher-order functions, though, are dog slow. In particular, all the
array functions are higher-order, because an array is just a function
with a rectangular domain; e.g. `array-map' is composition. Here's a
program that times computing the elements of an array:

#lang racket
(require math/array)

(define arr
(build-array #(3 3) (λ (js)
(match-define (vector j0 j1) js)
(+ j0 j1))))
arr

(for ([_ (in-range 5)])
(time (for ([_ (in-range 50000)])
(array-strict arr))))


This is the output I get:

(array [[0 1 2] [1 2 3] [2 3 4]])
cpu time: 2680 real time: 2684 gc time: 170
cpu time: 2650 real time: 2659 gc time: 140
cpu time: 2660 real time: 2662 gc time: 170
cpu time: 2650 real time: 2653 gc time: 170
cpu time: 2660 real time: 2660 gc time: 160

Changing the language to "typed/racket", I get this:

(array [[0 1 2] [1 2 3] [2 3 4]])
cpu time: 90 real time: 90 gc time: 20
cpu time: 70 real time: 77 gc time: 0
cpu time: 80 real time: 75 gc time: 10
cpu time: 80 real time: 77 gc time: 10
cpu time: 80 real time: 82 gc time: 20

So here, the contract boundary slows things down 33x.

Huh. I just tried `make-array', which creates the array's function in TR
code, and I get 53x. I didn't expect that. I also get 20x for using
distribution objects, which are immutable structs that contain functions
that are only created in TR code.

> If it
> is bad, we should consider including both a typed and an untyped
> variant where the latter is generated from the former (I believe
> you are working in TR so that's why I wrote the last sentence).
> That is, when the library is installed the Untyped one should be
> generated by disabling types and type checking.

We should consider it, then, unless there's a way to significantly speed
up a type's generated, higher-order contracts.

I'm a bit confused about how this would help, though. The interface
between the library and the user will still have to be contracted, so
where does the performance gain come from?

Matthias Felleisen

unread,
Nov 3, 2012, 5:42:37 PM11/3/12
to Neil Toronto, us...@racket-lang.org

On Nov 3, 2012, at 1:46 PM, Neil Toronto wrote:

> Higher-order functions, though, are dog slow. In particular, all the array functions are higher-order, because an array is just a function with a rectangular domain; e.g. `array-map' is composition.


That's the only thing I am talking about. And your 33x slowdown is what I am afraid of.


>
>> If it is bad, we should consider including both a typed and an untyped
>> variant where the latter is generated from the former (I believe
>> you are working in TR so that's why I wrote the last sentence).
>> That is, when the library is installed the Untyped one should be
>> generated by disabling types and type checking.
>
> We should consider it, then, unless there's a way to significantly speed up a type's generated, higher-order contracts.
>
> I'm a bit confused about how this would help, though. The interface between the library and the user will still have to be contracted, so where does the performance gain come from?


No, the idea would be that the generate version does NOT use contracts and avoids the cost. -- Matthias



Robby Findler

unread,
Nov 3, 2012, 5:48:26 PM11/3/12
to Matthias Felleisen, Racket Users
I can't recall why exactly now, but there is something about how the
contract system wraps first-order contracts that lets things run
faster.

Robby
Reply all
Reply to author
Forward
0 new messages