1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ; Description: The Boyer benchmark
6 ; Modified: 10-Apr-85 14:52:20 (Bob Shaw)
7 ; 22-Jul-87 (Will Clinger)
8 ; 2-Jul-88 (Will Clinger -- distinguished #f and the empty list)
9 ; 13-Feb-97 (Will Clinger -- fixed bugs in unifier and rules,
10 ; rewrote to eliminate property lists, and added
11 ; a scaling parameter suggested by Bob Boyer)
12 ; 19-Mar-99 (Will Clinger -- cleaned up comments)
13 ; 4-Apr-01 (Will Clinger -- changed four 1- symbols to sub1)
15 ; Status: Public Domain
16 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18 ;;; SBOYER -- Logic programming benchmark, originally written by Bob Boyer.
19 ;;; Much less CONS-intensive than NBOYER because it uses Henry Baker's
22 ; Note: The version of this benchmark that appears in Dick Gabriel's book
23 ; contained several bugs that are corrected here. These bugs are discussed
24 ; by Henry Baker, "The Boyer Benchmark Meets Linear Logic", ACM SIGPLAN Lisp
25 ; Pointers 6(4), October-December 1993, pages 3-10. The fixed bugs are:
27 ; The benchmark now returns a boolean result.
28 ; FALSEP and TRUEP use TERM-MEMBER? rather than MEMV (which is called MEMBER
30 ; ONE-WAY-UNIFY1 now treats numbers correctly
31 ; ONE-WAY-UNIFY1-LST now treats empty lists correctly
32 ; Rule 19 has been corrected (this rule was not touched by the original
33 ; benchmark, but is used by this version)
34 ; Rules 84 and 101 have been corrected (but these rules are never touched
37 ; According to Baker, these bug fixes make the benchmark 10-25% slower.
38 ; Please do not compare the timings from this benchmark against those of
39 ; the original benchmark.
41 ; This version of the benchmark also prints the number of rewrites as a sanity
42 ; check, because it is too easy for a buggy version to return the correct
43 ; boolean result. The correct number of rewrites is
45 ; n rewrites peak live storage (approximate, in bytes)
53 ; Sboyer is a 2-phase benchmark.
54 ; The first phase attaches lemmas to symbols. This phase is not timed,
55 ; but it accounts for very little of the runtime anyway.
56 ; The second phase creates the test problem, and tests to see
57 ; whether it is implied by the lemmas.
59 (define (sboyer-benchmark . args)
60 (let ((n (if (null? args) 0 (car args))))
62 (run-benchmark (string-append "sboyer"
65 (lambda () (test-boyer n))
67 (and (number? rewrites)
69 ((0) (= rewrites 95024))
70 ((1) (= rewrites 591777))
71 ((2) (= rewrites 1813975))
72 ((3) (= rewrites 5375678))
73 ((4) (= rewrites 16445406))
74 ((5) (= rewrites 51507739))
75 ; If it works for n <= 5, assume it works.
78 (define (setup-boyer) #t) ; assigned below
79 (define (test-boyer) #t) ; assigned below
81 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
85 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87 ; In the original benchmark, it stored a list of lemmas on the
88 ; property lists of symbols.
89 ; In the new benchmark, it maintains an association list of
90 ; symbols and symbol-records, and stores the list of lemmas
91 ; within the symbol-records.
97 (quote ((equal (compile form)
98 (reverse (codegen (optimize form)
103 (equal (greaterp x y)
107 (equal (greatereqp x y)
119 (equal (countps- l pred)
120 (countps-loop l pred (zero)))
124 (reverse-loop x (nil)))
126 (zerop (remainder y x)))
127 (equal (assume-true var alist)
130 (equal (assume-false var alist)
133 (equal (tautology-checker x)
134 (tautologyp (normalize x)
137 (falsify1 (normalize x)
141 (not (equal x (add1 (zero))))
142 (prime1 x (sub1 x))))
162 (equal (if (if a b c)
169 (equal (plus (plus x y)
172 (equal (equal (plus a b)
176 (equal (difference x x)
178 (equal (equal (plus a b)
185 (equal (equal x (difference x y))
189 (equal (meaning (plus-tree (append x y))
191 (plus (meaning (plus-tree x)
193 (meaning (plus-tree y)
195 (equal (meaning (plus-tree (plus-fringe x))
198 (equal (append (append x y)
200 (append x (append y z)))
201 (equal (reverse (append a b))
204 (equal (times x (plus y z))
207 (equal (times (times x y)
209 (times x (times y z)))
210 (equal (equal (times x y)
214 (equal (exec (append x y)
216 (exec y (exec x pds envrn)
218 (equal (mc-flatten x y)
221 (equal (member x (append a b))
224 (equal (member x (reverse y))
226 (equal (length (reverse x))
228 (equal (member a (intersect b c))
234 (equal (exp i (plus j k))
237 (equal (exp i (times j k))
240 (equal (reverse-loop x y)
243 (equal (reverse-loop x (nil))
245 (equal (count-list z (sort-lp x y))
246 (plus (count-list z x)
248 (equal (equal (append a b)
251 (equal (plus (remainder x y)
252 (times y (quotient x y)))
254 (equal (power-eval (big-plus1 l i base)
256 (plus (power-eval l base)
258 (equal (power-eval (big-plus x y i base)
260 (plus i (plus (power-eval x base)
261 (power-eval y base))))
262 (equal (remainder y 1)
264 (equal (lessp (remainder x y)
267 (equal (remainder x x)
269 (equal (lessp (quotient i j)
274 (equal (lessp (remainder x y)
279 (equal (power-eval (power-rep i base)
282 (equal (power-eval (big-plus (power-rep i base)
290 (equal (nth (append a b)
293 (nth b (difference i (length a)))))
294 (equal (difference (plus x y)
297 (equal (difference (plus y x)
300 (equal (difference (plus x y)
303 (equal (times x (difference c w))
304 (difference (times c x)
306 (equal (remainder (times x z)
309 (equal (difference (plus b (plus a c))
312 (equal (difference (add1 (plus y z))
315 (equal (lessp (plus x y)
318 (equal (lessp (times x z)
322 (equal (lessp y (plus x y))
324 (equal (gcd (times x z)
327 (equal (value (normalize x)
330 (equal (equal (flatten x)
334 (equal (listp (gopher x))
336 (equal (samefringe x y)
339 (equal (equal (greatest-factor x y)
344 (equal (equal (greatest-factor x y)
347 (equal (numberp (greatest-factor x y))
348 (not (and (or (zerop y)
351 (equal (times-list (append x y))
352 (times (times-list x)
354 (equal (prime-list (append x y))
357 (equal (equal z (times w z))
361 (equal (greatereqp x y)
363 (equal (equal x (times x y))
367 (equal (remainder (times y x)
370 (equal (equal (times a b)
372 (and (not (equal a (zero)))
373 (not (equal b (zero)))
380 (equal (lessp (length (delete x l))
383 (equal (sort2 (delete x l))
384 (delete x (sort2 l)))
387 (equal (length (cons x1
392 (plus 6 (length x7)))
393 (equal (difference (add1 (add1 x))
396 (equal (quotient (plus x (plus x y))
398 (plus x (quotient y 2)))
401 (quotient (times i (add1 i))
403 (equal (plus x (add1 y))
407 (equal (equal (difference x y)
415 (equal (meaning (plus-tree (delete x y))
418 (difference (meaning (plus-tree y)
421 (meaning (plus-tree y)
423 (equal (times x (add1 y))
432 (equal (last (append a b))
439 (equal (equal (lessp x y)
444 (equal (assignment x (append a b))
448 (equal (car (gopher x))
452 (equal (flatten (cdr (gopher x)))
457 (equal (quotient (times y x)
462 (equal (get j (set i val mem))
467 (define (add-lemma-lst lst)
470 (else (add-lemma (car lst))
471 (add-lemma-lst (cdr lst)))))
473 (define (add-lemma term)
474 (cond ((and (pair? term)
478 (put (car (cadr term))
481 (translate-term term)
482 (get (car (cadr term)) (quote lemmas)))))
483 (else (error "ADD-LEMMA did not like term: " term))))
485 ; Translates a term by replacing its constructor symbols by symbol-records.
487 (define (translate-term term)
488 (cond ((not (pair? term))
490 (else (cons (symbol->symbol-record (car term))
491 (translate-args (cdr term))))))
493 (define (translate-args lst)
496 (else (cons (translate-term (car lst))
497 (translate-args (cdr lst))))))
499 ; For debugging only, so the use of MAP does not change
500 ; the first-order character of the benchmark.
502 (define (untranslate-term term)
503 (cond ((not (pair? term))
505 (else (cons (get-name (car term))
506 (map untranslate-term (cdr term))))))
508 ; A symbol-record is represented as a vector with two fields:
509 ; the symbol (for debugging) and
510 ; the list of lemmas associated with the symbol.
512 (define (put sym property value)
513 (put-lemmas! (symbol->symbol-record sym) value))
515 (define (get sym property)
516 (get-lemmas (symbol->symbol-record sym)))
518 (define (symbol->symbol-record sym)
519 (let ((x (assq sym *symbol-records-alist*)))
522 (let ((r (make-symbol-record sym)))
523 (set! *symbol-records-alist*
525 *symbol-records-alist*))
528 ; Association list of symbols and symbol-records.
530 (define *symbol-records-alist* '())
532 ; A symbol-record is represented as a vector with two fields:
533 ; the symbol (for debugging) and
534 ; the list of lemmas associated with the symbol.
536 (define (make-symbol-record sym)
539 (define (put-lemmas! symbol-record lemmas)
540 (vector-set! symbol-record 1 lemmas))
542 (define (get-lemmas symbol-record)
543 (vector-ref symbol-record 1))
545 (define (get-name symbol-record)
546 (vector-ref symbol-record 0))
548 (define (symbol-record-equal? r1 r2)
551 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
555 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
561 (quote ((x f (plus (plus a b)
563 (y f (times (times a b)
565 (z f (reverse (append (append a b)
569 (w lessp (remainder a b)
570 (member a (length b))))))
573 (quote (implies (and (implies x y)
578 (list 'or term '(f)))
580 ((zero? n) term))))))
583 (define (translate-alist alist)
586 (else (cons (cons (caar alist)
587 (translate-term (cdar alist)))
588 (translate-alist (cdr alist))))))
590 (define (apply-subst alist term)
591 (cond ((not (pair? term))
592 (let ((temp-temp (assq term alist)))
596 (else (cons (car term)
597 (apply-subst-lst alist (cdr term))))))
599 (define (apply-subst-lst alist lst)
602 (else (cons (apply-subst alist (car lst))
603 (apply-subst-lst alist (cdr lst))))))
606 (tautologyp (rewrite x)
609 (define (tautologyp x true-lst false-lst)
610 (cond ((truep x true-lst)
612 ((falsep x false-lst)
616 ((eq? (car x) if-constructor)
617 (cond ((truep (cadr x)
619 (tautologyp (caddr x)
623 (tautologyp (cadddr x)
625 (else (and (tautologyp (caddr x)
629 (tautologyp (cadddr x)
635 (define if-constructor '*) ; becomes (symbol->symbol-record 'if)
637 (define rewrite-count 0) ; sanity check
639 ; The next procedure is Henry Baker's sharing CONS, which avoids
640 ; allocation if the result is already in hand.
641 ; The REWRITE and REWRITE-ARGS procedures have been modified to
642 ; use SCONS instead of CONS.
644 (define (scons x y original)
645 (if (and (eq? x (car original))
646 (eq? y (cdr original)))
650 (define (rewrite term)
651 (set! rewrite-count (+ rewrite-count 1))
652 (cond ((not (pair? term))
654 (else (rewrite-with-lemmas (scons (car term)
655 (rewrite-args (cdr term))
657 (get-lemmas (car term))))))
659 (define (rewrite-args lst)
662 (else (scons (rewrite (car lst))
663 (rewrite-args (cdr lst))
666 (define (rewrite-with-lemmas term lst)
669 ((one-way-unify term (cadr (car lst)))
670 (rewrite (apply-subst unify-subst (caddr (car lst)))))
671 (else (rewrite-with-lemmas term (cdr lst)))))
673 (define unify-subst '*)
675 (define (one-way-unify term1 term2)
676 (begin (set! unify-subst '())
677 (one-way-unify1 term1 term2)))
679 (define (one-way-unify1 term1 term2)
680 (cond ((not (pair? term2))
681 (let ((temp-temp (assq term2 unify-subst)))
683 (term-equal? term1 (cdr temp-temp)))
684 ((number? term2) ; This bug fix makes
685 (equal? term1 term2)) ; nboyer 10-25% slower!
687 (set! unify-subst (cons (cons term2 term1)
694 (one-way-unify1-lst (cdr term1)
698 (define (one-way-unify1-lst lst1 lst2)
703 ((one-way-unify1 (car lst1)
705 (one-way-unify1-lst (cdr lst1)
709 (define (falsep x lst)
710 (or (term-equal? x false-term)
711 (term-member? x lst)))
713 (define (truep x lst)
714 (or (term-equal? x true-term)
715 (term-member? x lst)))
717 (define false-term '*) ; becomes (translate-term '(f))
718 (define true-term '*) ; becomes (translate-term '(t))
720 ; The next two procedures were in the original benchmark
721 ; but were never used.
723 (define (trans-of-implies n)
725 (list (quote implies)
726 (trans-of-implies1 n)
727 (list (quote implies)
730 (define (trans-of-implies1 n)
732 (list (quote implies)
734 (else (list (quote and)
735 (list (quote implies)
738 (trans-of-implies1 (- n 1))))))
740 ; Translated terms can be circular structures, which can't be
741 ; compared using Scheme's equal? and member procedures, so we
744 (define (term-equal? x y)
747 (symbol-record-equal? (car x) (car y))
748 (term-args-equal? (cdr x) (cdr y))))
749 (else (equal? x y))))
751 (define (term-args-equal? lst1 lst2)
756 ((term-equal? (car lst1) (car lst2))
757 (term-args-equal? (cdr lst1) (cdr lst2)))
760 (define (term-member? x lst)
763 ((term-equal? x (car lst))
765 (else (term-member? x (cdr lst)))))
769 (set! *symbol-records-alist* '())
770 (set! if-constructor (symbol->symbol-record 'if))
771 (set! false-term (translate-term '(f)))
772 (set! true-term (translate-term '(t)))
777 (set! rewrite-count 0)
778 (let ((answer (test n)))
779 (write rewrite-count)
780 (display " rewrites")