@@ -4,10 +4,18 @@ use std::fmt;
4
4
pub fn least_satisfying < T , P > ( slice : & [ T ] , mut predicate : P ) -> usize
5
5
where
6
6
T : fmt:: Display + fmt:: Debug ,
7
- P : FnMut ( & T ) -> Satisfies ,
7
+ P : FnMut ( & T , usize , usize ) -> Satisfies ,
8
8
{
9
9
let mut cache = BTreeMap :: new ( ) ;
10
- let mut predicate = |idx : usize | * cache. entry ( idx) . or_insert_with ( || predicate ( & slice[ idx] ) ) ;
10
+ let mut predicate = |idx : usize , rm_no, lm_yes| {
11
+ let range = lm_yes - rm_no + 1 ;
12
+ // FIXME: This does not consider unknown_ranges.
13
+ let remaining = range / 2 ;
14
+ let estimate = estimate_steps ( range) ;
15
+ * cache
16
+ . entry ( idx)
17
+ . or_insert_with ( || predicate ( & slice[ idx] , remaining, estimate) )
18
+ } ;
11
19
let mut unknown_ranges: Vec < ( usize , usize ) > = Vec :: new ( ) ;
12
20
// presume that the slice starts with a no
13
21
// this should be tested before call
40
48
}
41
49
}
42
50
43
- let r = predicate ( next) ;
51
+ let r = predicate ( next, rm_no , lm_yes ) ;
44
52
match r {
45
53
Satisfies :: Yes => {
46
54
lm_yes = next;
@@ -52,11 +60,13 @@ where
52
60
}
53
61
Satisfies :: Unknown => {
54
62
let mut left = next;
55
- while left > 0 && predicate ( left) == Satisfies :: Unknown {
63
+ while left > 0 && predicate ( left, rm_no , lm_yes ) == Satisfies :: Unknown {
56
64
left -= 1 ;
57
65
}
58
66
let mut right = next;
59
- while right + 1 < slice. len ( ) && predicate ( right) == Satisfies :: Unknown {
67
+ while right + 1 < slice. len ( )
68
+ && predicate ( right, rm_no, lm_yes) == Satisfies :: Unknown
69
+ {
60
70
right += 1 ;
61
71
}
62
72
unknown_ranges. push ( ( left + 1 , right - 1 ) ) ;
@@ -66,10 +76,33 @@ where
66
76
}
67
77
}
68
78
79
+ fn estimate_steps ( range : usize ) -> usize {
80
+ // Replace with int_log when it is stabilized.
81
+ let log2 = |mut n| {
82
+ let mut r = 0 ;
83
+ while n > 1 {
84
+ r += 1 ;
85
+ n >>= 1 ;
86
+ }
87
+ r
88
+ } ;
89
+ if range < 3 {
90
+ return 0 ;
91
+ }
92
+ let n = log2 ( range) ;
93
+ let e = 1 << n;
94
+ let x = range - e;
95
+ if e < 3 * x {
96
+ n
97
+ } else {
98
+ n - 1
99
+ }
100
+ }
101
+
69
102
#[ cfg( test) ]
70
103
mod tests {
71
104
use super :: Satisfies :: { No , Unknown , Yes } ;
72
- use super :: { least_satisfying, Satisfies } ;
105
+ use super :: { estimate_steps , least_satisfying, Satisfies } ;
73
106
use quickcheck:: { QuickCheck , TestResult } ;
74
107
75
108
fn prop ( xs : Vec < Option < bool > > ) -> TestResult {
@@ -89,59 +122,62 @@ mod tests {
89
122
}
90
123
}
91
124
92
- let res = least_satisfying ( & satisfies_v, |i| * i) ;
125
+ let res = least_satisfying ( & satisfies_v, |i, _ , _ | * i) ;
93
126
let exp = first_yes. unwrap ( ) ;
94
127
TestResult :: from_bool ( res == exp)
95
128
}
96
129
97
130
#[ test]
98
131
fn least_satisfying_1 ( ) {
99
132
assert_eq ! (
100
- least_satisfying( & [ No , Unknown , Unknown , No , Yes ] , |i| * i) ,
133
+ least_satisfying( & [ No , Unknown , Unknown , No , Yes ] , |i, _ , _ | * i) ,
101
134
4
102
135
) ;
103
136
}
104
137
105
138
#[ test]
106
139
fn least_satisfying_2 ( ) {
107
140
assert_eq ! (
108
- least_satisfying( & [ No , Unknown , Yes , Unknown , Yes ] , |i| * i) ,
141
+ least_satisfying( & [ No , Unknown , Yes , Unknown , Yes ] , |i, _ , _ | * i) ,
109
142
2
110
143
) ;
111
144
}
112
145
113
146
#[ test]
114
147
fn least_satisfying_3 ( ) {
115
- assert_eq ! ( least_satisfying( & [ No , No , No , No , Yes ] , |i| * i) , 4 ) ;
148
+ assert_eq ! ( least_satisfying( & [ No , No , No , No , Yes ] , |i, _ , _ | * i) , 4 ) ;
116
149
}
117
150
118
151
#[ test]
119
152
fn least_satisfying_4 ( ) {
120
- assert_eq ! ( least_satisfying( & [ No , No , Yes , Yes , Yes ] , |i| * i) , 2 ) ;
153
+ assert_eq ! ( least_satisfying( & [ No , No , Yes , Yes , Yes ] , |i, _ , _ | * i) , 2 ) ;
121
154
}
122
155
123
156
#[ test]
124
157
fn least_satisfying_5 ( ) {
125
- assert_eq ! ( least_satisfying( & [ No , Yes , Yes , Yes , Yes ] , |i| * i) , 1 ) ;
158
+ assert_eq ! ( least_satisfying( & [ No , Yes , Yes , Yes , Yes ] , |i, _ , _ | * i) , 1 ) ;
126
159
}
127
160
128
161
#[ test]
129
162
fn least_satisfying_6 ( ) {
130
163
assert_eq ! (
131
- least_satisfying( & [ No , Yes , Yes , Unknown , Unknown , Yes , Unknown , Yes ] , |i| * i) ,
164
+ least_satisfying(
165
+ & [ No , Yes , Yes , Unknown , Unknown , Yes , Unknown , Yes ] ,
166
+ |i, _, _| * i
167
+ ) ,
132
168
1
133
169
) ;
134
170
}
135
171
136
172
#[ test]
137
173
fn least_satisfying_7 ( ) {
138
- assert_eq ! ( least_satisfying( & [ No , Yes , Unknown , Yes ] , |i| * i) , 1 ) ;
174
+ assert_eq ! ( least_satisfying( & [ No , Yes , Unknown , Yes ] , |i, _ , _ | * i) , 1 ) ;
139
175
}
140
176
141
177
#[ test]
142
178
fn least_satisfying_8 ( ) {
143
179
assert_eq ! (
144
- least_satisfying( & [ No , Unknown , No , No , Unknown , Yes , Yes ] , |i| * i) ,
180
+ least_satisfying( & [ No , Unknown , No , No , Unknown , Yes , Yes ] , |i, _ , _ | * i) ,
145
181
5
146
182
) ;
147
183
}
@@ -150,6 +186,22 @@ mod tests {
150
186
fn qc_prop ( ) {
151
187
QuickCheck :: new ( ) . quickcheck ( prop as fn ( _) -> _ ) ;
152
188
}
189
+
190
+ #[ test]
191
+ fn estimates ( ) {
192
+ for ( n, expect) in & [
193
+ ( 0 , 0 ) ,
194
+ ( 1 , 0 ) ,
195
+ ( 2 , 0 ) ,
196
+ ( 3 , 1 ) ,
197
+ ( 4 , 1 ) ,
198
+ ( 5 , 1 ) ,
199
+ ( 6 , 2 ) ,
200
+ ( 150 , 6 ) ,
201
+ ] {
202
+ assert_eq ! ( estimate_steps( * n) , * expect) ;
203
+ }
204
+ }
153
205
}
154
206
155
207
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
0 commit comments