How to resolve the algorithm Closest-pair problem step by step in the Racket programming language
Published on 12 May 2024 09:40 PM
How to resolve the algorithm Closest-pair problem step by step in the Racket programming language
Table of Contents
Problem Statement
Provide a function to find the closest two points among a set of given points in two dimensions, i.e. to solve the Closest pair of points problem in the planar case. The straightforward solution is a O(n2) algorithm (which we can call brute-force algorithm); the pseudo-code (using indexes) could be simply: A better algorithm is based on the recursive divide&conquer approach, as explained also at Wikipedia's Closest pair of points problem, which is O(n log n); a pseudo-code could be:
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Closest-pair problem step by step in the Racket programming language
Source code in the racket programming language
#lang racket
(define (dist z0 z1) (magnitude (- z1 z0)))
(define (dist* zs) (apply dist zs))
(define (closest-pair zs)
(if (< (length zs) 2)
-inf.0
(first
(sort (for/list ([z0 zs])
(list z0 (argmin (λ(z) (if (= z z0) +inf.0 (dist z z0))) zs)))
< #:key dist*))))
(define result (closest-pair '(0+1i 1+2i 3+4i)))
(displayln (~a "Closest points: " result))
(displayln (~a "Distance: " (dist* result)))
#lang racket
(struct point (x y) #:transparent)
(define (closest-pair ps)
(check-type ps)
(cond [(vector? ps) (if (> (vector-length ps) 1)
(closest-pair/sorted (vector-sort ps left?)
(vector-sort ps below?))
(error 'closest-pair "2 or more points are needed" ps))]
[(sequence? ps) (closest-pair (for/vector ([x (in-sequences ps)]) x))]
[else (error 'closest-pair "closest pair only supports sequence types (excluding hash)")]))
;; accept any sequence type except hash
;; any other exclusions needed?
(define (check-type ps)
(cond [(hash? ps) (error 'closest-pair "Hash tables are not supported")]
[(sequence? ps) #t]
[else (error 'closest-pair "Only sequence types are supported")]))
;; vector -> vector -> list
(define (closest-pair/sorted Px Py)
(define L (vector-length Px))
(cond [(= L 2) (vector->list Px)]
[(= L 3) (apply min-pair (combinations (vector->list Px) 2))]
[else (let*-values ([(Qx Rx) (vector-split-at Px (floor (/ L 2)))]
; Rx-min is the left most point in Rx
[(Rx-min) (vector-ref Rx 0)]
; instead of sorting Qx, Rx by y
; - Qy are members of Py to left of Rx-min
; - Ry are the remaining members of Py
[(Qy Ry) (vector-partition Py (curryr left? Rx-min))]
[(pair1) (closest-pair/sorted Qx Qy)]
[(pair2) (closest-pair/sorted Rx Ry)]
[(delta) (min (distance^2 pair1) (distance^2 pair2))]
[(pair3) (closest-split-pair Px Py delta)])
; pair3 is null when there are no split pairs closer than delta
(min-pair pair1 pair2 pair3))]))
(define (closest-split-pair Px Py delta)
(define Lp (vector-length Px))
(define x-mid (point-x (vector-ref Px (floor (/ Lp 2)))))
(define Sy (for/vector ([p (in-vector Py)]
#:when (< (abs (- (point-x p) x-mid)) delta))
p))
(define Ls (vector-length Sy))
(define-values (_ best-pair)
(for*/fold ([new-best delta]
[new-best-pair null])
([i (in-range (sub1 Ls))]
[j (in-range (+ i 1) (min (+ i 7) Ls))]
[Sij (in-value (list (vector-ref Sy i)
(vector-ref Sy j)))]
[dij (in-value (distance^2 Sij))]
#:when (< dij new-best))
(values dij Sij)))
best-pair)
;; helper procedures
;; same as partition except for vectors
;; it's critical to maintain the relative order of elements
(define (vector-partition Py pred)
(define-values (left right)
(for/fold ([Qy null]
[Ry null])
([p (in-vector Py)])
(if (pred p)
(values (cons p Qy) Ry)
(values Qy (cons p Ry)))))
(values (list->vector (reverse left))
(list->vector (reverse right))))
; is p1 (strictly) left of p2
(define (left? p1 p2) (< (point-x p1) (point-x p2)))
; is p1 (strictly) below of p2
(define (below? p1 p2) (< (point-y p1) (point-y p2)))
;; return the pair with minimum distance
(define (min-pair . pairs)
(argmin distance^2 pairs))
;; pairs are passed around as a list of 2 points
;; distance is only for comparison so no need to use sqrt
(define (distance^2 pair)
(cond [(null? pair) +inf.0]
[else (define a (first pair))
(define b (second pair))
(+ (sqr (- (point-x b) (point-x a)))
(sqr (- (point-y b) (point-y a))))]))
; points on a quadratic curve, shuffled
(define points
(shuffle
(for/list ([ i (in-range 1000)]) (point i (* i i)))))
(match-define (list (point p1x p1y) (point p2x p2y)) (closest-pair points))
(printf "Closest points on a quadratic curve (~a,~a) (~a,~a)\n" p1x p1y p2x p2y)
Closest points: (0+1i 1+2i)
Distance: 1.4142135623730951
Closest points on a quadratic curve (0,0) (1,1)
You may also check:How to resolve the algorithm Death Star step by step in the Tcl programming language
You may also check:How to resolve the algorithm Simple windowed application step by step in the Vala programming language
You may also check:How to resolve the algorithm Safe primes and unsafe primes step by step in the Raku programming language
You may also check:How to resolve the algorithm Hailstone sequence step by step in the S-BASIC programming language
You may also check:How to resolve the algorithm Loop over multiple arrays simultaneously step by step in the Rust programming language