Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Partial Order design proposal #276

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7fa0243
Add Partial Order design proposal
AlexKnauth Feb 8, 2023
52bea25
Start PartialOrder implementation
AlexKnauth Feb 8, 2023
2c3b0e6
Self is implicit
AlexKnauth Feb 8, 2023
2d20e6b
Add within to design
AlexKnauth Feb 8, 2023
f8af877
Implement within
AlexKnauth Feb 8, 2023
a8d84be
Add Lexicographic class
AlexKnauth Feb 8, 2023
4fae130
Add Lexicographic.and macro
AlexKnauth Feb 8, 2023
f55fc81
Pass the pieces in the same order they came in
AlexKnauth Feb 9, 2023
beacd59
Factor out partial-order-util
AlexKnauth Feb 10, 2023
b5a28a3
Add Option D: false on incomparable
AlexKnauth Feb 10, 2023
a07c911
Factor out product-compare/recur
AlexKnauth Feb 10, 2023
dd3272c
Start PartialOrder option D-A implementation
AlexKnauth Feb 10, 2023
7254627
Check eq? in product-compare/recur
AlexKnauth Feb 10, 2023
80783e5
Test that it doesn't check eq? too soon
AlexKnauth Feb 10, 2023
3f31229
Use #nan literal
AlexKnauth Feb 11, 2023
5a4c2e4
Start PartialOrder option D-C implementation
AlexKnauth Feb 14, 2023
01d0789
D-C: Add flvector test
AlexKnauth Feb 15, 2023
e909370
More flvector tests
AlexKnauth Feb 16, 2023
4c735d7
D-C: Connect an Equatable to PartialOrder
AlexKnauth Feb 16, 2023
c5a3885
Add separate D-A and D-C files
AlexKnauth Feb 16, 2023
9286812
D-C: Add partial_order default via key
AlexKnauth Feb 17, 2023
8515b78
D-C: Use equal-hash-code/recur
AlexKnauth Mar 2, 2023
56db933
Refactor into partial-order-util
AlexKnauth Mar 2, 2023
1a41023
Add mode to product-compare/recur
AlexKnauth Mar 2, 2023
7b9fe2d
Start option E implementation
AlexKnauth Mar 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions design/partial-order/A/Lexicographic.rhm
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#lang rhombus

export Lexicographic

import "partial-order.rkt" open

class Lexicographic(elements):
export and
constructor(& elements): super(elements)
private implements PartialOrder
private override partial_compare(other :: Lexicographic, recur):
lexicographic_compare_list(elements, other.elements, recur)

macro
| 'and: $(c :: Group)': '$c'
| 'and: $c; $r; ...':
'begin:
let cv: $c
if cv .= 0
| and: $r; ...
| cv'

fun
| lexicographic_compare_list([], [], _): 0
| lexicographic_compare_list([], [_, & _], _): -1
| lexicographic_compare_list([_, & _], [], _): 1
| lexicographic_compare_list([f1, & r1], [f2, & r2], recur):
Lexicographic.and:
recur(f1, f2)
lexicographic_compare_list(r1, r2, recur)
131 changes: 131 additions & 0 deletions design/partial-order/A/partial-order.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#lang racket/base

(require rhombus/private/provide)
(provide (for-spaces (rhombus/class
rhombus/namespace)
PartialOrder)
(for-spaces (#f
rhombus/repet)
=~
!=~
<~
>~
<=~
>=~))

(require (for-syntax racket/base
rhombus/private/interface-parse)
rhombus/private/define-operator
(only-in rhombus/private/arithmetic
\|\| &&
[+ rhombus+]
[- rhombus-]
[* rhombus*]
[/ rhombus/])
rhombus/private/name-root
rhombus/private/realm
(only-in rhombus/private/class-desc define-class-desc-syntax)
"../common/partial-order-util.rkt")

;; ---------------------------------------------------------

;; PartialOrder struct type property and interface

(define-values (prop:partial-order partial-order? partial-order-ref)
(make-struct-type-property
'partial-order
(λ (value _type-info)
(unless (and (procedure? value)
(procedure-arity-includes? value 3))
(raise-argument-error* 'partial_compare
rhombus-realm
"a method of 2 arguments (after this)"
value))
(list (gensym) value))))

(define-values (prop:PartialOrder _PartialOrder? PartialOrder-ref)
(make-struct-type-property
'PartialOrder
#false
(list (cons prop:partial-order (lambda (v) (vector-ref v 0))))))

(define-class-desc-syntax PartialOrder
(interface-desc #'PartialOrder
#'PartialOrder
#'()
#'prop:PartialOrder
#'PartialOrder-ref
(vector-immutable (box-immutable 'partial_compare))
#'#(#:abstract)
(hasheq 'partial_compare 0)
#hasheq()
#t))

;; ---------------------------------------------------------

;; Public operations

(define-name-root PartialOrder
#:fields
(partial_compare
compare
within))

(define (partial-compare/recur a b recur)
(define (cmp ai bi)
(partial-ordering-normalize (recur ai bi)))
(cond
[(partial-order? a)
(ord-and/bool
(partial-order? b)
(let ([av (partial-order-ref a)])
(ord-and/bool
(eq? av (partial-order-ref b))
(partial-ordering-normalize ((cadr av) a b cmp)))))]
[(realish? a)
(ord-and/bool (realish? b) (partial-compare-realish a b))]
[else
(product-compare/recur a b cmp #true)]))

(define (partial_compare a b)
(partial-compare/recur a b partial_compare))

(define (compare/recur a b recur)
(define (cmp ai bi) (ordering-normalize (recur ai bi)))
(ordering-normalize (partial-compare/recur a b cmp)))

(define (compare a b)
(compare/recur a b compare))

(define (partial-compare/within a b epsilon)
(cond
[(realish? a)
(ord-and/bool (realish? b) (partial-compare-realish/within a b epsilon))]
[else
(define (cmp ai bi) (partial-compare/within ai bi epsilon))
(partial-compare/recur a b cmp)]))

(define (within a b epsilon)
(zero? (partial-compare/within a b epsilon)))

(define (=~? a b) (zero? (partial_compare a b)))
(define (!=~? a b) (not (zero? (partial_compare a b))))

(define (<~? a b) (negative? (compare a b)))
(define (>~? a b) (positive? (compare a b)))
(define (<=~? a b) (<= (compare a b) 0))
(define (>=~? a b) (>= (compare a b) 0))

(define-syntax-rule (define-comp~-infix name racket-name)
(define-infix name racket-name
#:weaker-than (rhombus+ rhombus- rhombus* rhombus/)
#:same-as (<~ <=~ =~ !=~ >=~ >~)
#:stronger-than (\|\| &&)
#:associate 'none))

(define-comp~-infix <~ <~?)
(define-comp~-infix <=~ <=~?)
(define-comp~-infix =~ =~?)
(define-comp~-infix !=~ !=~?)
(define-comp~-infix >=~ >=~?)
(define-comp~-infix >~ >~?)
62 changes: 62 additions & 0 deletions design/partial-order/A/test-partial-order.rhm
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#lang rhombus

import:
lib("racket/flonum.rkt").flvector
"partial-order.rkt" open
"Lexicographic.rhm".Lexicographic

class UnredRatio(n :: Integer, d :: PositiveInteger):
private implements PartialOrder
private override partial_compare(other :: UnredRatio, recur):
recur(n * other.d, other.n * d)

check UnredRatio(1, 2) =~ UnredRatio(2, 4) ~is #true
check UnredRatio(1, 2) =~ UnredRatio(3, 4) ~is #false
check UnredRatio(1, 2) <~ UnredRatio(3, 4) ~is #true
check UnredRatio(1, 2) <~ UnredRatio(1, 4) ~is #false
check UnredRatio(1, 2) >~ UnredRatio(1, 4) ~is #true
check:
[UnredRatio(1, 2), UnredRatio(-1, 2)] <~ [UnredRatio(3, 4), UnredRatio(-1, 4)]
~is #true
check:
[UnredRatio(1, 2), UnredRatio(-1, 2)] >~ [UnredRatio(1, 4), UnredRatio(-3, 4)]
~is #true

check:
Lexicographic(UnredRatio(1, 2), UnredRatio(-1, 2)) <~ Lexicographic(UnredRatio(3, 4), UnredRatio(-1, 4))
~is #true
check:
Lexicographic(UnredRatio(1, 2), UnredRatio(-1, 2)) >~ Lexicographic(UnredRatio(1, 4), UnredRatio(-3, 4))
~is #true

check: Lexicographic(5, 8, 3, 13, 2) =~ Lexicographic(5, 8, 3, 13, 2) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) =~ Lexicographic(5, 8, 3, 13, 2, -1) ~is #false
check: Lexicographic(5, 8, 3, 13, 2) !=~ Lexicographic(5, 8, 3, 13, 2, -1) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) <=~ Lexicographic(5, 8, 3, 13, 2, -1) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) <~ Lexicographic(5, 8, 3, 13, 2, -1) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) <=~ Lexicographic(5, 8, 2, 13, 2, -1) ~is #false
check: Lexicographic(5, 8, 3, 13, 2) >=~ Lexicographic(5, 8, 2, 13, 2, -1) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) >~ Lexicographic(5, 8, 2, 13, 2, -1) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) >=~ Lexicographic(6, -1) ~is #false
check: Lexicographic(5, 8, 3, 13, 2) <=~ Lexicographic(6, -1) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) <~ Lexicographic(6, -1) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) <=~ Lexicographic(4, 18) ~is #false
check: Lexicographic(5, 8, 3, 13, 2) >=~ Lexicographic(4, 18) ~is #true
check: Lexicographic(5, 8, 3, 13, 2) >~ Lexicographic(4, 18) ~is #true

check: PartialOrder.within([6, 10], [6.02, 9.99], 0.05) ~is #true
check: PartialOrder.within({#'C: 20, #'F: 68}, {#'C: 25, #'F: 77}, 10) ~is #true

check: PartialOrder.within([6e+23, 10.0], [6.02e+23, 9.8], 0.05) ~is #false
check: PartialOrder.within({#'C: 18, #'F: 64}, {#'C: 25, #'F: 77}, 10) ~is #false

check: flvector(0.0) =~ flvector(-0.0) ~is #true
check: flvector(0.0, -0.0) =~ flvector(-0.0, 0.0) ~is #true
check: flvector(0.0, 1.0) =~ flvector(-0.0, 2.0) ~is #false
check: flvector(0.0, 1.0) !=~ flvector(-0.0, 2.0) ~is #true
check: flvector(0.0, 1.0) <=~ flvector(-0.0, 2.0) ~is #true
check: flvector(0.0, 1.0) <~ flvector(-0.0, 2.0) ~is #true
check: flvector(2.0, -0.0) <=~ flvector(1.0, 0.0) ~is #false
check: flvector(2.0, -0.0) >=~ flvector(1.0, 0.0) ~is #true
check: flvector(2.0, -0.0) >~ flvector(1.0, 0.0) ~is #true

30 changes: 30 additions & 0 deletions design/partial-order/D-A/Lexicographic.rhm
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#lang rhombus

export Lexicographic

import "partial-order.rkt" open

class Lexicographic(elements):
export and
constructor(& elements): super(elements)
private implements PartialOrder
private override partial_compare(other :: Lexicographic, recur):
lexicographic_compare_list(elements, other.elements, recur)

macro
| 'and: $(c :: Group)': '$c'
| 'and: $c; $r; ...':
'begin:
let cv: $c
if cv .= 0
| and: $r; ...
| cv'

fun
| lexicographic_compare_list([], [], _): 0
| lexicographic_compare_list([], [_, & _], _): -1
| lexicographic_compare_list([_, & _], [], _): 1
| lexicographic_compare_list([f1, & r1], [f2, & r2], recur):
Lexicographic.and:
recur(f1, f2)
lexicographic_compare_list(r1, r2, recur)