1
1
2
2
import IntervalArithmetic: diam, isinterior
3
+ import Base: start, next, done, copy, eltype, iteratorsize
3
4
4
- export branch_and_prune, Bisection, Newton
5
+ export branch_and_prune, Bisection, Newton, RootSearch
6
+ export start, next, done, copy, step!, eltype, iteratorsize
5
7
6
8
diam (x:: Root ) = diam (x. interval)
7
9
8
10
Base. size (x:: Interval ) = (1 ,)
9
11
10
12
isinterior {N} (X:: IntervalBox{N} , Y:: IntervalBox{N} ) = all (isinterior .(X, Y))
11
13
14
+ struct RootSearchState{T <: Union{Interval,IntervalBox} }
15
+ working:: Vector{T}
16
+ outputs:: Vector{Root{T}}
17
+ end
18
+ RootSearchState {T<:Union{Interval,IntervalBox}} (region:: T ) =
19
+ RootSearchState ([region], Root{T}[])
20
+
21
+ copy (state:: RootSearchState ) =
22
+ RootSearchState (copy (state. working), copy (state. outputs))
12
23
24
+ """
25
+ RootSearch{R <: Union{Interval,IntervalBox}, S <: Contractor, T <: Real}
26
+
27
+ Type implementing the `Base.Iterator` interface to the branch and prune routine.
28
+ Returns the `RootSearchState` at each iteration. Note: Each iteration mutates
29
+ the `RootSearchState`. Use `copy(state::RootSearchState)` to create an
30
+ independent instance if necessary.
31
+ """
32
+ struct RootSearch{R <: Union{Interval,IntervalBox} , S <: Contractor , T <: Real }
33
+ region:: R
34
+ contractor:: S
35
+ tolerance:: T
36
+ end
37
+
38
+ eltype {R, T <: RootSearch{R}} (:: Type{T} ) = RootSearchState{R}
39
+ iteratorsize {T <: RootSearch} (:: Type{T} ) = Base. SizeUnknown ()
40
+
41
+ function start (iter:: RootSearch )
42
+ state = RootSearchState (iter. region)
43
+ sizehint! (state. outputs, 100 )
44
+ sizehint! (state. working, 1000 )
45
+ return state
46
+ end
47
+
48
+ """
49
+ step!(state::RootSearchState, contractor, tolerance)
50
+
51
+ Progress `state` by treating one of its `working` regions. Note: `state.working`
52
+ is always modified. If a root is found, it is added to `state.outputs`.
53
+ """
54
+ function step! (state:: RootSearchState , contractor, tolerance)
55
+ X = pop! (state. working)
56
+ status, output = contractor (X, tolerance)
57
+ if status == :empty
58
+ return nothing
59
+ elseif status == :unique
60
+ push! (state. outputs, Root (output, :unique ))
61
+ elseif diam (output) < tolerance
62
+ push! (state. outputs, Root (output, :unknown ))
63
+ else # branch
64
+ X1, X2 = bisect (X)
65
+ push! (state. working, X1, X2)
66
+ end
67
+ return nothing
68
+ end
69
+
70
+ function next (iter:: RootSearch , state:: RootSearchState )
71
+ step! (state, iter. contractor, iter. tolerance)
72
+ return state, state
73
+ end
74
+
75
+ done (iter:: RootSearch , state:: RootSearchState ) = isempty (state. working)
13
76
14
77
"""
15
78
branch_and_prune(X, contract, tol=1e-3)
@@ -25,38 +88,13 @@ Inputs:
25
88
26
89
"""
27
90
function branch_and_prune (X, contractor, tol= 1e-3 )
28
- working = [X]
29
- outputs = Root{typeof (X)}[]
30
-
31
- sizehint! (outputs, 100 )
32
- sizehint! (working, 1000 )
33
-
34
- while ! isempty (working)
35
- # @show working
36
- X = pop! (working)
37
-
38
- status, output = contractor (X, tol)
39
-
40
- if status == :empty
41
- continue
42
-
43
- elseif status == :unique
44
- push! (outputs, Root (output, :unique ))
45
-
46
- elseif diam (output) < tol
47
- push! (outputs, Root (output, :unknown ))
48
-
49
- else # branch
50
- X1, X2 = bisect (X)
51
-
52
- push! (working, X1, X2)
53
- end
54
- end
55
-
56
- return outputs
91
+ iter = RootSearch (X, contractor, tol)
92
+ local state
93
+ # complete iteration
94
+ for state in iter end
95
+ return state. outputs
57
96
end
58
97
59
-
60
98
export recursively_branch_and_prune
61
99
62
100
function recursively_branch_and_prune (h, X, contractor= BisectionContractor, final_tol= 1e-14 )
0 commit comments