-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtry-search.scm
More file actions
171 lines (154 loc) · 6.25 KB
/
try-search.scm
File metadata and controls
171 lines (154 loc) · 6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
(load "gram.scm")
(load "tree.scm")
(load "phog.scm")
(load "corpus-json.scm")
;; Dynamically conjoin full-sym-matcho goals for a list of patterns
(define (all-sym-match regex pats)
(lambda (st)
(let loop ((stream (succeed st)) (ps pats))
(if (null? ps)
stream
(loop (bind stream (full-sym-matcho regex (car ps)))
(cdr ps))))))
;; Monotonic nanosecond timestamp
(define (now-ns)
(let ((t (current-time 'time-monotonic)))
(+ (* (time-second t) 1000000000) (time-nanosecond t))))
;; Absolute deadline N seconds from now
(define (deadline-from-now seconds)
(add-duration (current-time 'time-utc) (make-time 'time-duration 0 seconds)))
;; ============================================================
;; Single-thread search (one thread per symbol)
;; ============================================================
(define (launch-search type-name pats)
(let ((mx (make-mutex))
(cv (make-condition))
(result (box #f))
(elapsed-ns (box #f))
(done (box #f)))
(fork-thread
(lambda ()
(let* ((t0 (now-ns))
(v (run 1 (regex) (all-sym-match regex pats)))
(t1 (now-ns)))
(mutex-acquire mx)
(set-box! result v)
(set-box! elapsed-ns (- t1 t0))
(set-box! done #t)
(condition-signal cv)
(mutex-release mx))))
(vector type-name pats mx cv result elapsed-ns done)))
;; ============================================================
;; Or-parallel search (N threads per symbol, first wins)
;; ============================================================
;; Top-level regex constructors to split the search space
(define top-level-splits
(list
(cons "cat" (lambda (regex) (fresh (r1 r2) (== regex `(cat ,r1 ,r2)))))
(cons "alt" (lambda (regex) (fresh (r1 r2) (== regex `(alt ,r1 ,r2)))))
(cons "rep" (lambda (regex) (fresh (r) (== regex `(rep ,r)))))
(cons "opt" (lambda (regex) (fresh (r) (== regex `(opt ,r)))))
(cons "sym" (lambda (regex) (fresh (n) (== regex `(sym ,n)))))))
(define (launch-parallel-search type-name pats)
(let ((mx (make-mutex))
(cv (make-condition))
(result (box #f))
(elapsed-ns (box #f))
(done (box #f))
(winner (box #f)))
;; Spawn one thread per top-level constructor
(for-each
(lambda (split)
(let ((split-name (car split))
(constraint (cdr split)))
(fork-thread
(lambda ()
(let* ((t0 (now-ns))
(v (run 1 (regex)
(constraint regex)
(all-sym-match regex pats)))
(t1 (now-ns)))
(mutex-acquire mx)
;; First thread to finish wins
(when (and (not (unbox done)) (not (null? v)))
(set-box! result v)
(set-box! elapsed-ns (- t1 t0))
(set-box! winner split-name)
(set-box! done #t)
(condition-signal cv))
(mutex-release mx))))))
top-level-splits)
(vector type-name pats mx cv result elapsed-ns done winner)))
;; ============================================================
;; Gather (works for both single and parallel jobs)
;; ============================================================
(define (gather-job job deadline)
(let ((type-name (vector-ref job 0))
(pats (vector-ref job 1))
(mx (vector-ref job 2))
(cv (vector-ref job 3))
(result (vector-ref job 4))
(elapsed-ns (vector-ref job 5))
(done (vector-ref job 6))
(winner (if (> (vector-length job) 7) (vector-ref job 7) #f)))
(mutex-acquire mx)
(unless (unbox done)
(condition-wait cv mx deadline))
(let ((d (unbox done))
(r (unbox result))
(ns (unbox elapsed-ns))
(w (if winner (unbox winner) #f)))
(mutex-release mx)
(list type-name (length pats)
(if d (/ ns 1000000.0) #f)
(if d (car r) 'TIMEOUT)
w))))
(define (print-result r)
(let ((type-name (list-ref r 0))
(npats (list-ref r 1))
(ms (list-ref r 2))
(result (list-ref r 3))
(winner (list-ref r 4)))
(if ms
(printf " ~a (~a pats) ~a~a — ~a\n"
type-name npats
(format "~,1fms" ms)
(if winner (format " [~a]" winner) "")
result)
(printf " ~a (~a pats) TIMEOUT\n"
type-name npats))))
;; ============================================================
;; Tiered search
;; ============================================================
(define tier1-timeout 5)
(define tier2-timeout 30)
(let* ((types (cst-collect-types corpus))
(multi-pat-types
(filter (lambda (type-name)
(> (length (cst-collect-child-patterns corpus type-name)) 1))
types)))
;; --- Tier 1: one thread per symbol ---
(printf "=== Tier 1: single-thread (~as) ===\n" tier1-timeout)
(let* ((jobs (map (lambda (type-name)
(launch-search type-name
(cst-collect-child-patterns corpus type-name)))
multi-pat-types))
(deadline (deadline-from-now tier1-timeout))
(results (map (lambda (job) (gather-job job deadline)) jobs))
(timed-out (filter (lambda (r) (not (list-ref r 2))) results)))
(for-each print-result results)
;; --- Tier 2: or-parallel for timeouts ---
(unless (null? timed-out)
(printf "\n=== Tier 2: or-parallel (~as, ~a splits) ===\n"
tier2-timeout (length top-level-splits))
(printf " Threads: ~a symbols × ~a splits = ~a threads\n\n"
(length timed-out) (length top-level-splits)
(* (length timed-out) (length top-level-splits)))
(let* ((jobs2 (map (lambda (r)
(launch-parallel-search
(list-ref r 0)
(cst-collect-child-patterns corpus (list-ref r 0))))
timed-out))
(deadline2 (deadline-from-now tier2-timeout))
(results2 (map (lambda (job) (gather-job job deadline2)) jobs2)))
(for-each print-result results2)))))