
Summer picture competition community choice
You don’t have to choose - you can vote for as many favourites as you want!
Vote early, vote often, because voting ends Sunday afternoon uk time.

I forgot to mention the prize is a limited edition racketeer cap. As far as I know racketeer caps are the most popular and desirable swag. ‘Rare as hens teeth’. Priceless maybe.

@dasheng523 has joined the channel

@mflatt apropos of your recent change to parameters on racketcs, I had contemplated a different idea, and I wonder if you thought about it: trying to determine in schemify if a value was a parameter and then explicitly introducing the code to access the parameter value. I suppose that could still be done in schemify, although it’s a little tricky with the closure representation for default values.

Yes, that could work. I can imagine changing the application of a parameter to be a call to unsafe-parameter-ref
and still avoid a jump or two that way. Probably a smaller additional effect than the representation change, but possibly worthwhile. I’ll put that on my list of things to try.

Nice idea, but doesn’t seem to speed up a microbenchmark that just accesses a parameter.

Can you share the branch that tried this out? I’m interested in looking at the generated code


Technically not complete, since I didn’ update “http://internal.ss\|internal.ss” and “built-in-symbol.rkt”, but close enough.

I think all the time is in parameter-cell
and thread-cell-ref
, but I could be wrong.

I finally published a basic transducers API! https://docs.racket-lang.org/rebellion/Transducers.html

Summer picture competition community choice
You don’t have to choose - you can vote for as many favourites as you want!
Vote early, vote often, because voting ends Sunday afternoon uk time.

Votes needed

I have a problem that could need a couple of new eyes.

In MetaPict bezier curves are represented as (bez p0 p1 p2 p3) . The curve goes from p0 to p3 and the control points are p1 and p2.

The function bez-intersection-point-and-time
calculates an intersection point between two bezier curves b1 and b2.

It works in most cases - but I have found an edge case, where I get an infinite loop.

#lang racket
(require metapict)
(define b1
(bez (pt -4.999999999999893 2989.799999999806)
(pt -4.999999999999893 2989.7999999998056)
(pt -4.999999999999893 2989.7999999998056)
(pt -4.999999999999893 2989.7999999998056)))
(define b2
(bez (pt -4.999999999999893 2989.799999999806)
(pt -4.999999999999893 2989.799999999806)
(pt -4.999999999999893 2989.799999999806)
(pt -4.999999999999893 2989.799999999806)))
(bez-intersection-point-and-times b1 b2)

The bezier curve b2 has p0=p1=p2=p3 which means it represents a point.

The other bezier curve b1 is almost the same point.

The function is defined here:


quick idea: switch to #lang exact-decimal racket
and see what happens

Is the effect of exact-decimal to make the reader turn floating points numbers into exact numbers?

yes, it makes 4.999999999999893
read as that exact value instead of reading as the base–2 floating point value that most closely approximates it

I also see no performance improvement. I was, however, motivated to look at what parameters are used a lot; turns out current-namespace
and current-locale
are called many many times. I’ll try to post the numbers later.

I don’t think there will be an effect: > (read (open-input-string "-4.999999999999893"))
-4.999999999999893

Also the first thing the function bez-intersection-point-and-times
does is to convert into inexact numbers in order to avoid exact fractions (which have a tendency to grow very large).

ah so probably not gonna do anything useful then

Let me attempt to explain the algorithm.

reading through that function, I don’t see any recursion or looping constructs

Oh wait, now I see - you aliased the function to again

The parameter t belongs to b1 and runs from 0 to 1, which corresponds to the beginning point p0 and the end point p3 respectively.

Yes.

During the search the interval becomes smaller and smaller and goes from t- to t+.

Likewise the interval for the second curve is from u- to u+.

First the bounding boxes (non-tight) of b1 and b2 are computed.

If the bounding boxes doesn’t overlap, then the curves have no intersection, and #f is returned.

If the bounding boxes overlap and are very small (practically a point), then the point in the center is returned and we have found an intersection point.

If the bounding boxes overlap but aren’t small, then the two curves are split in two halves.

b1 is split into b11 and b12

b2 is split into b21 and b22

Then the search continues for intersection points between the four possibilities.

The idea is of course that the curves gets smaller.

My approach to debugging it would be to gut it by splitting it up into smaller functions, maybe adding some structs to bundle together related values, and replacing the recursion with something easier for my brain to statically analyze. As is I have no idea why it loops forever.

It “looks” correct, but I must be missing something.

Could you add some comparison functions that explicitly take a tolerance param, to make it easier to verify that that’s being handled correctly? Like these:
(define (fuzzy=? x y #:tolerance [tolerance <very small default value>])
(define delta (abs (- x y)))
(<= delta tolerance))
(define (fuzzy<? x y #:tolerance [tolerance ...]) ...)
... similar for >, <=, >=, etc. ...
Then you could 1) unit test the hell out of them, and 2) run them through Herbie (https://herbie.uwplse.org) to check that floating point isn’t doing something weird.

I did try the above approach but I couldn’t find the right spot.

I need to step though all the temporary results and see if they match what I expect.

I have found one odd thing. The bounding box for b1 in the examples is not small.

bez.rkt> (define b1
(bez (pt -4.999999999999893 2989.799999999806)
(pt -4.999999999999893 2989.7999999998056)
(pt -4.999999999999893 2989.7999999998056)
(pt -4.999999999999893 2989.7999999998056)))
bez.rkt> (bez-large-bounding-box b1)
(window
-4.999999999999893
-4.999999999999893
2989.7999999998056
2989.799999999806)
bez.rkt> (def ε 1e-15)
bez.rkt> (define (very-small? w)
(defm (window x- x+ y- y+) w)
(and (<= (- x+ x-) ε)
(<= (- y+ y-) ε)))
bez.rkt> (very-small? (bez-large-bounding-box b1))
#f

In this edge case b1 is an vertical line and b2 is a point.

Maybe I should special case points and vertical/horizontal lines?

Or perhaps I should make sure that the split curves b11 and b12 actually are different from b1.

¯_(ツ)_/¯

> Or perhaps I should make sure that the split curves b11 and b12 actually are different from b1.

That’s what I was going to suggest

In this case, b11 is the same as b1

@soegaard2 what’s defm
do?

That’s short for define-match.

defv is short for define-values

def is short for define

ahh

So is window
a struct somewhere then?

structs.rkt

(struct window (minx maxx miny maxy))

Poking around structs.rkt
now out of curiosity

After inserting checks and displays I see that: b11=b1 b21=b2 b22=b2

So the first of the four recursive calls uses b11 and b21 which are the same as b1 and b2.

So only the times are changed.

what if you change small-bb1?
and small-bb2?
to check both very-small?
and splittable?
?

I mean: (or (very-small? x) (unsplittable? x))

where the latter is true if splitting the argument results in a box that’s equal to the argument.

Sounds like the right place to make a change.

Let’s see. The place where a point is found is:
(or (and small-bb1? small-bb2?
(<= (+ (area bb1) (area bb2)) ε)
(list (window-center bb1) ; point
; todo : instead of the center, find
; the intersection of lines
(/ (+ t- t+) 2) ; time on original b1
(/ (+ u- u+) 2))) ; time on original b2

So can we ever be in a situation where there is an intersection point, but the curves are splittable?

Yes… that’s taken care of by very-small?.

I think it will work.

And after some testing - it seems to work.

Thank you both.

I did this: (defv (b11 b12) (split-bez b1 1/2))
(defv (b21 b22) (split-bez b2 1/2))
(def small-bb1? (or (very-small? bb1) (equal? b11 b1)))
(def small-bb2? (or (very-small? bb2) (equal? b21 b2)))

It bothers me it isn’t symmetrical.

thank you too, for a totally unrelated reason: metapict’s structs are a good use case for me to consider for rebellion/type

I did use quite a few features of struct in that file.

do you have any other files in other projects where you define tons and tons of structs?

Not quite as many, but there are few in remacs: https://github.com/soegaard/remacs/blob/master/representation.rkt

If you need examples with many structs, scribble has one: https://github.com/racket/scribble/blob/master/scribble-lib/scribble/struct.rkt

:exploding_head: NO NOT TWO REMACSES.
which one is older?

Are you referring to the Rust one?

yes

Then this one is older - but it is a horrible name.

If (and I doubt it) it ever becomes good enough to use for others than me, then it needs a better name.

There is also rmacs.

Just in case it wasn’t confusing enough :wink:

I like “Sublime Text”.

Simple and clear.

@soegaard2 both great examples! added to a list https://github.com/jackfirth/rebellion/wiki