@@ -5,42 +5,89 @@ export branch_and_prune, Bisection, Newton
5
5
6
6
diam (x:: Root ) = diam (x. interval)
7
7
8
-
9
8
Base. size (x:: Interval ) = (1 ,)
10
9
11
10
isinterior {N} (X:: IntervalBox{N} , Y:: IntervalBox{N} ) = all (isinterior .(X, Y))
12
11
12
+ # contractors:
13
+ """
14
+ Contractor{F}
13
15
16
+ Abstract type for contractors.
14
17
"""
15
- branch_and_prune(f, X, contractor, tol=1e-3)
18
+ abstract type Contractor{F} end
16
19
17
- Generic branch and prune routine for finding isolated roots of a function
18
- `f:R^n → R^n` in a box.
20
+ export Bisection, Newton
19
21
20
- Inputs:
21
- - `f`: function whose roots will be found
22
- - `X`: `Interval` or `IntervalBox`
23
- - `contractor`: function that, when applied to the function `f`, determines
24
- the status of a given box `X`. It returns the new box and a symbol indicating
25
- the status. Current possible values are `Bisection` and `Newton`.
22
+ struct Bisection{F} <: Contractor{F}
23
+ f:: F
24
+ end
26
25
27
- """
28
- function branch_and_prune (f, X, contractor, tol = 1e-3 )
26
+ function (contractor :: Bisection )(X)
27
+ image = contractor . f (X )
29
28
30
- input_dim = length (X)
31
- output_dim = length (X)
29
+ if ! (contains_zero (image))
30
+ return :empty , X
31
+ end
32
+
33
+ return :unknown , X
34
+ end
32
35
33
- # @show input_dim
34
- # @show output_dim
35
36
36
- # if !(input_dim == output_dim)
37
- # throw(ArgumentError("Input dimension ($input_dim) and output dimension ($output_dim) must be the same."))
38
- # end
37
+ struct Newton{F,FP,O} <: Contractor{F}
38
+ f:: F
39
+ f_prime:: FP
40
+ op:: O
41
+ end
39
42
40
- contract = contractor (Val{input_dim}, f)
43
+ function Newton (f:: Function , f_prime:: Function )
44
+ Newton (f, f_prime, N)
45
+ end
41
46
42
- # main algorithm:
47
+ function Newton (f_prime:: Function )
48
+ return NewtonConstructor (f_prime)
49
+ end
43
50
51
+ function (C:: Newton )(X)
52
+ # use Bisection contractor for this:
53
+ if ! (contains_zero (IntervalBox (C. f (X))))
54
+ return :empty , X
55
+ end
56
+
57
+ # given that have the Jacobian, can also do mean value form
58
+
59
+ NX = C. op (C. f, C. f_prime, X) ∩ X
60
+
61
+ isempty (NX) && return :empty , X
62
+
63
+ if NX ⪽ X # isinterior; know there's a unique root inside
64
+ NX = refine (X -> C. op (C. f, C. f_prime, X), NX)
65
+ return :unique , NX
66
+ end
67
+
68
+ return :unknown , NX
69
+ end
70
+
71
+
72
+ struct NewtonConstructor{FP}
73
+ f_prime:: FP
74
+ end
75
+
76
+
77
+ """
78
+ branch_and_prune(X, contract, tol=1e-3)
79
+
80
+ Generic branch and prune routine for finding isolated roots using the `contract`
81
+ function as the contractor.
82
+
83
+ Inputs:
84
+ - `X`: `Interval` or `IntervalBox`
85
+ - `contractor`: function that determines the status of a given box `X`. It
86
+ returns the new box and a symbol indicating the status. Current possible
87
+ values are of type `Bisection` or `Newton`
88
+
89
+ """
90
+ function branch_and_prune (X, contractor, tol= 1e-3 )
44
91
working = [X]
45
92
outputs = Root{typeof (X)}[]
46
93
@@ -51,7 +98,7 @@ function branch_and_prune(f, X, contractor, tol=1e-3)
51
98
# @show working
52
99
X = pop! (working)
53
100
54
- status, output = contract (X)
101
+ status, output = contractor (X)
55
102
56
103
if status == :empty
57
104
continue
@@ -67,23 +114,11 @@ function branch_and_prune(f, X, contractor, tol=1e-3)
67
114
68
115
push! (working, X1, X2)
69
116
end
70
-
71
117
end
72
118
73
119
return outputs
74
120
end
75
121
76
- branch_and_prune (f, X:: Root , contractor, tol= 1e-3 ) =
77
- branch_and_prune (f, X. interval, contractor, tol)
78
-
79
-
80
- function branch_and_prune (f, V:: Vector{Root{T}} , contractor, tol= 1e-3 ) where {T}
81
- reduce (append!, Root{T}[], [branch_and_prune (f, X. interval, contractor, tol) for X in V])
82
- end
83
-
84
- function branch_and_prune (f, V:: Vector{T} , contractor, tol= 1e-3 ) where {T}
85
- reduce (append!, Root{T}[], [branch_and_prune (f, X, contractor, tol) for X in V])
86
- end
87
122
88
123
export recursively_branch_and_prune
89
124
@@ -99,54 +134,12 @@ function recursively_branch_and_prune(h, X, contractor=BisectionContractor, fina
99
134
return roots
100
135
end
101
136
102
- """
103
- If the input interval is complex, treat `f` as a complex function, currently of one complex variable `z`.
104
- """
105
- function branch_and_prune {T} (f, Xc:: Complex{Interval{T}} , contractor, tol= 1e-3 )
106
-
107
- g = realify (f)
108
- Y = IntervalBox (reim (Xc))
109
-
110
- roots = branch_and_prune (g, Y, contractor, tol)
111
-
112
- # @show roots
113
-
114
- return [Root (Complex (root. interval... ), root. status) for root in roots]
115
- end
116
-
117
-
118
137
119
138
contains_zero {T} (X:: Interval{T} ) = zero (T) ∈ X
120
139
contains_zero (X:: SVector ) = all (contains_zero .(X))
121
140
contains_zero (X:: IntervalBox ) = all (contains_zero (X[i]) for i in 1 : length (X))
122
141
123
142
124
- # contractors:
125
-
126
- abstract type Contractor{F} end
127
-
128
- export Bisection, Newton
129
-
130
- struct Bisection{F} <: Contractor{F}
131
- dimension:: Int
132
- f:: F
133
- end
134
-
135
- Bisection {n} (:: Type{Val{n}} , f) = Bisection (n, f)
136
-
137
-
138
- function (contractor:: Bisection )(X)
139
- image = contractor. f (X)
140
-
141
- if ! (contains_zero (image))
142
- return :empty , X
143
- end
144
-
145
- return :unknown , X
146
- end
147
-
148
-
149
-
150
143
"""
151
144
Generic refine operation for Krawczyk and Newton.
152
145
This assumes that it is already known that `X` contains a unique root.
@@ -166,49 +159,7 @@ function refine(op, X)
166
159
end
167
160
168
161
169
-
170
- struct Newton{F,FP,O} <: Contractor{F}
171
- dimension:: Int
172
- f:: F
173
- fp:: FP
174
- op:: O
175
- end
176
-
177
- function Newton (:: Type{Val{1}} , f:: Function )
178
- f_prime = x -> ForwardDiff. derivative (f, x)
179
- Newton (1 , f, f_prime, N)
180
- end
181
-
182
- function Newton {n} (:: Type{Val{n}} , f:: Function )
183
- f_prime = x -> ForwardDiff. jacobian (f, x)
184
- Newton (n, f, f_prime, N)
185
- end
186
-
187
-
188
- function (C:: Newton )(X)
189
-
190
- # use Bisection contractor for this:
191
- if ! (contains_zero (IntervalBox (C. f (X))))
192
- return :empty , X
193
- end
194
-
195
- # given that have the Jacobian, can also do mean value form
196
-
197
-
198
- NX = C. op (C. f, C. fp, X) ∩ X
199
-
200
- isempty (NX) && return :empty , X
201
-
202
-
203
- if NX ⪽ X # isinterior; know there's a unique root inside
204
- NX = refine (X -> C. op (C. f, C. fp, X), NX)
205
- return :unique , NX
206
- end
207
-
208
-
209
- return :unknown , NX
210
- end
211
-
162
+ IntervalLike{T} = Union{Interval{T}, IntervalBox{T}}
212
163
213
164
"""
214
165
roots(f, X, contractor, tol=1e-3)
@@ -221,9 +172,52 @@ Inputs:
221
172
- `X`: `Interval` or `IntervalBox`
222
173
- `contractor`: function that, when applied to the function `f`, determines
223
174
the status of a given box `X`. It returns the new box and a symbol indicating
224
- the status. Current possible values are `Bisection` and `Newton`.
175
+ the status. Current possible values are `Bisection`, `Newton` and
176
+ `Newton(f_prime)` where `f_prime` is the derivative or jacobian of `f`.
225
177
226
178
"""
227
- roots {C<:Contractor} (f, X, contractor:: Type{C} , tol:: Float64 = 1e-3 ) = branch_and_prune (f, X, contractor, tol)
179
+ # Contractor specific `roots` functions
180
+ function roots (f, X:: IntervalLike{T} , :: Type{Bisection} , tol:: Float64 = 1e-3 ) where {T}
181
+ branch_and_prune (X, Bisection (f), tol)
182
+ end
183
+
184
+ function roots (f, X:: Interval{T} , :: Type{Newton} , tol:: Float64 = 1e-3 ) where {T}
185
+ branch_and_prune (X, Newton (f, x -> ForwardDiff. derivative (f, x)), tol)
186
+ end
187
+
188
+ function roots (f, X:: IntervalBox{T} , :: Type{Newton} , tol:: Float64 = 1e-3 ) where {T}
189
+ branch_and_prune (X, Newton (f, x -> ForwardDiff. jacobian (f, x)), tol)
190
+ end
191
+
192
+ function roots {T} (f, X:: IntervalLike{T} , nc:: NewtonConstructor , tol:: Float64 = 1e-3 )
193
+ branch_and_prune (X, Newton (f, nc. f_prime), tol)
194
+ end
195
+
196
+ # `roots` function for cases where `X` is not an `Interval` or `IntervalBox`
197
+ function roots (f, V:: Vector{Root{T}} , contractor:: Type{C} , tol:: Float64 = 1e-3 ) where {T, C<: Contractor }
198
+ reduce (append!, Root{T}[], [roots (f, X. interval, contractor, tol) for X in V])
199
+ end
200
+
201
+ function roots (f, V:: Vector{T} , contractor:: Type{C} , tol:: Float64 = 1e-3 ) where {T, C<: Contractor }
202
+ reduce (append!, Root{T}[], [roots (f, X, contractor, tol) for X in V])
203
+ end
204
+
205
+ function roots (f, Xc:: Complex{Interval{T}} , contractor:: Type{C} , tol:: Float64 = 1e-3 ) where {T, C<: Contractor }
206
+ g = realify (f)
207
+ Y = IntervalBox (reim (Xc))
208
+ rts = roots (g, Y, contractor, tol)
209
+
210
+ return [Root (Complex (root. interval... ), root. status) for root in rts]
211
+ end
212
+
213
+ function roots (f, Xc:: Complex{Interval{T}} , nc:: NewtonConstructor , tol:: Float64 = 1e-3 ) where {T}
214
+ g = realify (f)
215
+ g_prime = realify_derivative (nc. f_prime)
216
+ Y = IntervalBox (reim (Xc))
217
+ rts = roots (g, Y, Newton (g_prime), tol)
218
+
219
+ return [Root (Complex (root. interval... ), root. status) for root in rts]
220
+ end
228
221
229
- roots (f, X, tol:: Float64 = 1e-3 ) = branch_and_prune (f, X, Newton, tol)
222
+ # Default
223
+ roots (f, X, tol:: Float64 = 1e-3 ) = roots (f, X, Newton, tol)
0 commit comments