Skip to content

Commit c9dfceb

Browse files
authored
Merge pull request #309 from uwplse/ival-find-range
Ival find range
2 parents 2afbfc4 + 0946c43 commit c9dfceb

24 files changed

+497
-203
lines changed

bench/libraries/jmatjs.fpcore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
(FPCore (z)
44
:name "Jmat.Real.gamma, branch z greater than 0.5"
5+
:pre (> z 0.5)
56
(let ((z* (- z 1)) (g 7))
67
(let ((x
78
(+
@@ -19,6 +20,7 @@
1920

2021
(FPCore (z)
2122
:name "Jmat.Real.gamma, branch z less than 0.5"
23+
:pre (<= z 0.5)
2224
(let ((z* (- (- 1 z) 1)) (g 7))
2325
(let ((x
2426
(+
@@ -67,6 +69,7 @@
6769

6870
(FPCore (x)
6971
:name "Jmat.Real.erfi, branch x less than or equal to 0.5"
72+
:pre (<= x 0.5)
7073
(let ((sqrtPI (sqrt PI)))
7174
(let ((ps (/ 1 sqrtPI)))
7275
(let ((x* (fabs x)))
@@ -78,6 +81,7 @@
7881

7982
(FPCore (x)
8083
:name "Jmat.Real.erfi, branch x greater than or equal to 5"
84+
:pre (>= x 0.5)
8185
(let ((sqrtPI (sqrt PI)))
8286
(let ((ps (/ 1 sqrtPI)))
8387
(let ((x* (fabs x)))

bench/libraries/mathjs/arithmetic.fpcore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116

117117
(FPCore (re im)
118118
:name "math.sqrt on complex, imaginary part, im greater than 0 branch"
119+
:pre (> im 0)
119120
(* 0.5 (sqrt (* 2.0 (- (sqrt (+ (* re re) (* im im))) re)))))
120121

121122
(FPCore (re im)

bench/regression.fpcore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,13 @@
5656
(FPCore (x)
5757
:name "sqrt E"
5858
(sqrt (+ (pow x 2) (pow x 2))))
59+
60+
; This used to cause crashes
61+
62+
(FPCore (w l)
63+
:name "exp-w crasher"
64+
(* (exp (- w)) (pow l (exp w))))
65+
66+
(FPCore (x)
67+
:name "expfmod"
68+
(* (fmod (exp x) (sqrt (cos x))) (exp (- x))))

src/common.rkt

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
for/append string-prefix call-with-output-files
99
take-up-to flip-lists list/true find-duplicates all-partitions
1010
argmins argmaxs index-of set-disjoint? comparator sample-double
11-
random-ranges parse-flag get-seed set-seed!
11+
parse-flag get-seed set-seed!
1212
quasisyntax
1313
format-time format-bits in-sorted-dict web-resource
1414
(all-from-out "config.rkt") (all-from-out "debug.rkt"))
@@ -136,30 +136,6 @@
136136

137137
;; Miscellaneous helper
138138

139-
(define (random-ranges . ranges)
140-
(->* () #:rest (cons/c integer? integer?) integer?)
141-
142-
(define weights
143-
(for/list ([(lo hi) (in-dict ranges)])
144-
;; The `max` handles the case lo > hi and similar
145-
(max 0 (- hi lo))))
146-
147-
(define total-weight (apply + weights))
148-
(when (= total-weight 0)
149-
(error 'random-ranges "Empty ranges"))
150-
151-
(define num-bits (inexact->exact (ceiling (/ (log total-weight) (log 2)))))
152-
(define sample ; Rejection sampling
153-
(let loop ()
154-
(define sample (if (= num-bits 0) 0 (random-bits num-bits)))
155-
(if (< sample total-weight) sample (loop))))
156-
157-
(let loop ([sample sample] [ranges ranges] [weights weights])
158-
;; The `(car)` is guaranteed to succeed by the construction of `sample`
159-
(if (< sample (car weights))
160-
(+ (caar ranges) sample)
161-
(loop (- sample (car weights)) (cdr ranges) (cdr weights)))))
162-
163139
(define (parse-flag s)
164140
(match (string-split s ":")
165141
[(list (app string->symbol category) (app string->symbol flag))

src/config.rkt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
(define all-flags
77
#hash([precision . (double fallback)]
8-
[setup . (simplify early-exit)]
8+
[setup . (simplify early-exit search)]
99
[generate . (rr taylor simplify better-rr)]
1010
[reduce . (regimes avg-error binary-search branch-expressions)]
1111
[rules . (arithmetic polynomials fractions exponents trigonometry hyperbolic numerics special bools branches)]))
1212

1313
(define default-flags
1414
#hash([precision . (double fallback)]
15-
[setup . (simplify)]
15+
[setup . (simplify search)]
1616
[generate . (rr taylor simplify)]
1717
[reduce . (regimes avg-error binary-search branch-expressions)]
1818
[rules . (arithmetic polynomials fractions exponents trigonometry hyperbolic special bools branches)]))
@@ -49,6 +49,9 @@
4949
;; Number of iterations of the core loop for improving program accuracy
5050
(define *num-iterations* (make-parameter 4))
5151

52+
;; The maximum depth for splitting the space when searching for valid areas of points.
53+
(define *max-find-range-depth* (make-parameter 14))
54+
5255
;; The maximum number of consecutive skipped points for sampling valid points
5356
(define *max-skipped-points* (make-parameter 100))
5457

src/core/periodicity.rkt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,9 @@
187187
(let ([context
188188
(prepare-points
189189
program
190-
`(and ,@(for/list ([(var period) (lp-periods ploc)])
191-
`(<= 0 ,var ,(* 2 pi var))))
190+
`(λ ,(program-variables program)
191+
(and ,@(for/list ([(var period) (lp-periods ploc)])
192+
`(<= 0 ,var ,(* 2 pi var)))))
192193
(*output-repr*))])
193194
(parameterize ([*pcontext* context])
194195
(improve-func (make-alt program)))))))

src/core/regimes.rkt

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#lang racket
22

33
(require "../common.rkt" "../alternative.rkt" "../programs.rkt" "../timeline.rkt")
4-
(require "../syntax/types.rkt" "../interface.rkt")
4+
(require "../syntax/types.rkt" "../interface.rkt" "../errors.rkt")
55
(require "../points.rkt" "../float.rkt") ; For binary search
66

77
(module+ test
@@ -86,12 +86,12 @@
8686
(critical-subexpression? prog-body expr)))
8787
expr))
8888

89-
(define (combine-alts best-option repr)
89+
(define (combine-alts best-option repr sampler)
9090
(match-define (option splitindices alts pts expr _) best-option)
9191
(match splitindices
9292
[(list (si cidx _)) (list-ref alts cidx)]
9393
[_
94-
(define splitpoints (sindices->spoints pts expr alts splitindices repr))
94+
(define splitpoints (sindices->spoints pts expr alts splitindices repr sampler))
9595
(debug #:from 'regimes "Found splitpoints:" splitpoints ", with alts" alts)
9696

9797
(define expr*
@@ -191,7 +191,7 @@
191191
;; float form always come from the range [f(idx1), f(idx2)). If the
192192
;; float form of a split is f(idx2), or entirely outside that range,
193193
;; problems may arise.
194-
(define (sindices->spoints points expr alts sindices repr)
194+
(define (sindices->spoints points expr alts sindices repr sampler)
195195
(define eval-expr
196196
(eval-prog `(λ ,(program-variables (alt-program (car alts))) ,expr) 'fl repr))
197197

@@ -207,7 +207,10 @@
207207
[*timeline-disabled* true]
208208
[*var-reprs* (dict-set (*var-reprs*) var repr)])
209209
(define ctx
210-
(prepare-points start-prog `(== ,(caadr start-prog) ,v) repr))
210+
(prepare-points start-prog
211+
`(λ ,(program-variables start-prog) (== ,(caadr start-prog) ,v))
212+
repr
213+
(λ () (cons v (sampler)))))
211214
(< (errors-score (errors prog1 ctx repr))
212215
(errors-score (errors prog2 ctx repr)))))
213216
(define pt (binary-search-floats pred v1 v2 repr))
@@ -223,20 +226,28 @@
223226

224227
(sp (si-cidx sidx) expr (find-split prog1 prog2 p1 p2)))
225228

229+
(define (regimes-sidx->spoint sidx)
230+
(sp (si-cidx sidx) expr (apply eval-expr (list-ref points (- (si-pidx sidx) 1)))))
231+
226232
(define final-sp (sp (si-cidx (last sindices)) expr +nan.0))
227233

234+
(define use-binary
235+
(and (flag-set? 'reduce 'binary-search)
236+
;; Binary search is only valid if we correctly extracted the branch expression
237+
(andmap identity (cons start-prog progs))))
238+
(if use-binary
239+
(debug #:from 'binary-search "Improving bounds with binary search for" expr "and" alts)
240+
(debug #:from 'binary-search "Only using regimes for bounds on" expr "and" alts))
241+
228242
(append
229-
(if (and (flag-set? 'reduce 'binary-search)
230-
;; Binary search is only valid if we correctly extracted the branch expression
231-
(andmap identity (cons start-prog progs)))
232-
(begin
233-
(debug #:from 'binary-search "Improving bounds with binary search for" expr "and" alts)
234-
(for/list ([si1 sindices] [si2 (cdr sindices)])
235-
(sidx->spoint si1 si2)))
236-
(begin
237-
(debug #:from 'binary-search "Only using regimes for bounds on" expr "and" alts)
238-
(for/list ([sindex (take sindices (sub1 (length sindices)))])
239-
(sp (si-cidx sindex) expr (apply eval-expr (list-ref points (- (si-pidx sindex) 1)))))))
243+
(for/list ([si1 sindices] [si2 (cdr sindices)])
244+
(cond
245+
[use-binary
246+
(with-handlers ([exn:fail:user:herbie:sampling?
247+
(lambda (e) (regimes-sidx->spoint si1))])
248+
(sidx->spoint si1 si2))]
249+
[else
250+
(regimes-sidx->spoint si1)]))
240251
(list final-sp)))
241252

242253
(define (point-with-dim index point val)

src/errors.rkt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
#lang racket
22
(require "config.rkt")
33
(provide raise-herbie-error raise-herbie-syntax-error
4+
raise-herbie-sampling-error
45
herbie-error->string herbie-error-url
56
(struct-out exn:fail:user:herbie)
67
(struct-out exn:fail:user:herbie:syntax)
8+
(struct-out exn:fail:user:herbie:sampling)
79
warn warning-log expect-warning)
810

911
(struct exn:fail:user:herbie exn:fail:user (url)
1012
#:extra-constructor-name make-exn:fail:user:herbie)
1113

1214
(struct exn:fail:user:herbie:syntax exn:fail:user:herbie (locations)
13-
#:extra-constructor-name make-exn:fail:user:herbie:syntax)
15+
#:extra-constructor-name make-exn:fail:user:herbie:syntax)
16+
17+
(struct exn:fail:user:herbie:sampling exn:fail:user (url)
18+
#:extra-constructor-name make-exn:fail:user:herbie:sampling)
1419

1520
(define (raise-herbie-error message #:url [url #f] . args)
1621
(raise (make-exn:fail:user:herbie
@@ -20,6 +25,10 @@
2025
(raise (make-exn:fail:user:herbie:syntax
2126
(apply format message args) (current-continuation-marks) url locations)))
2227

28+
(define (raise-herbie-sampling-error message #:url [url #f] . args)
29+
(raise (make-exn:fail:user:herbie:sampling
30+
(apply format message args) (current-continuation-marks) url)))
31+
2332
(define (herbie-error-url exn)
2433
(format "https://herbie.uwplse.org/doc/~a/~a"
2534
*herbie-version* (exn:fail:user:herbie-url exn)))

src/float.rkt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
(provide
1010
get-representation*
1111
ordinary-value?
12+
largest-ordinary-value bound-ordinary-values
1213
ulp-difference ulps->bits
1314
midpoint random-generate
1415
</total <=/total =-or-nan?
@@ -55,6 +56,20 @@
5556
(ordinary-value? (imag-part x) (get-representation 'binary64)))
5657
(not (special-value? x repr))))
5758

59+
60+
(define (largest-ordinary-value repr)
61+
((representation-repr->bf repr)
62+
((representation-ordinal->repr repr)
63+
(- ((representation-repr->ordinal repr) ((representation-bf->repr repr) +inf.bf)) 1))))
64+
65+
(define (bound-ordinary-values repr)
66+
(parameterize ([bf-rounding-mode 'nearest])
67+
(let loop ([ordinal (bigfloat->ordinal (largest-ordinary-value repr))] [stepsize 1])
68+
(define bfval (ordinal->bigfloat ordinal))
69+
(if (bfinfinite? ((representation-repr->bf repr) ((representation-bf->repr repr) bfval)))
70+
bfval
71+
(loop (+ ordinal stepsize) (* stepsize 2))))))
72+
5873
(module+ test
5974
(define binary64 (get-representation 'binary64))
6075
(check-true (ordinary-value? 2.5 binary64))

src/interface.rkt

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,19 @@
3838
1
3939
null)
4040

41+
(define (shift bits fn)
42+
(define shift-val (expt 2 bits))
43+
(λ (x) (fn (- x shift-val))))
44+
45+
(define (unshift bits fn)
46+
(define shift-val (expt 2 bits))
47+
(λ (x) (+ (fn x) shift-val)))
48+
4149
(define-representation (binary64 real)
4250
bigfloat->flonum
4351
bf
44-
ordinal->flonum
45-
flonum->ordinal
52+
(shift 63 ordinal->flonum)
53+
(unshift 63 flonum->ordinal)
4654
64
4755
'(+nan.0 +inf.0 -inf.0))
4856

@@ -62,8 +70,23 @@
6270
[(< x 0) (- (bit-field->single-flonum (- x)))]
6371
[else (bit-field->single-flonum x)]))
6472

73+
(define (single-flonum-step x n)
74+
(ordinal->single-flonum (+ (single-flonum->ordinal x) n)))
75+
76+
(define (bigfloat->single-flonum x)
77+
(define loprec (parameterize ([bf-precision 24]) (bf+ 0.bf x)))
78+
(define y (real->single-flonum (bigfloat->flonum loprec)))
79+
(define x2 (bf y))
80+
(match (bf-rounding-mode)
81+
['nearest y]
82+
['up (if (bf< x2 x) (single-flonum-step y 1) y)]
83+
['down (if (bf> x2 x) (single-flonum-step y -1) y)]
84+
['zero (if (bf< x 0.bf)
85+
(if (bf< x2 x) (single-flonum-step y 1) y)
86+
(if (bf> x2 x) (single-flonum-step y -1) y))]))
87+
6588
(define-representation (binary32 real)
66-
(compose real->single-flonum bigfloat->flonum)
89+
bigfloat->single-flonum
6790
bf
6891
ordinal->single-flonum
6992
single-flonum->ordinal

0 commit comments

Comments
 (0)