-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathcontractor.jl
102 lines (71 loc) · 2.68 KB
/
contractor.jl
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
abstract type AbstractContractor end
struct Contractor{V, E, CC} <: AbstractContractor
vars::V
ex::E
contractor::CC
end
Contractor(ex, vars) = Contractor(vars, ex, forward_backward_contractor(ex, vars))
(CC::Contractor)(X, constraint=interval(0.0)) = IntervalBox(CC.contractor(X, constraint)[1])
abstract type AbstractSeparator end
"A separator models the inside and outside of a constraint set using a forward--backward contractor"
struct Separator{V,E,C,F,R} <: AbstractSeparator
vars::V
ex::E
constraint::C
f::F
contractor::R
end
# Base.show(io::IO, S::Separator) = print(io, "Separator($(S.ex) ∈ $(S.constraint), vars = $(join(S.vars, ", ")))")
Base.show(io::IO, S::AbstractSeparator) = print(io, "Separator($(S.ex), vars=$(join(S.vars, ", ")))")
function Separator(orig_expr, vars)
ex, constraint = analyse(orig_expr)
return Separator(ex, vars, constraint)
end
Separator(ex, vars, constraint::Interval) = Separator(vars, ex ∈ constraint, constraint, make_function(ex, vars), Contractor(ex, vars))
function separate_infinite_box(S::Separator, X::IntervalBox)
# for an box that extends to infinity we cannot evaluate at a corner
# so use the old method instead where we do inner and outer contractors separately
C = S.contractor
a, b = inf(S.constraint), sup(S.constraint)
inner = C(X, interval(a, b))
# to compute outer, we contract with respect to the complement of `a..b`:
local outer
if a == -Inf
outer = C(X, interval(b, Inf))
elseif b == Inf
outer = C(X, interval(-Inf, a))
else
# the complement is a union of two pieces
outer1 = C(X, interval(-Inf, a))
outer2 = C(X, interval(b, Inf))
outer = outer1 ⊔ outer2
end
boundary = inner ⊓ outer
return (boundary, inner, outer)
end
"Returns boundary, inner, outer"
function (SS::Separator)(X)
if any(x -> isinf(diam(x)), X)
return separate_infinite_box(SS, X)
end
# using the contractor to compute the boundary:
boundary = SS.contractor(X) # contract with respect to 0, which is always the boundary
# extend the boundary by evaluating at corners of the box to determine inner and outer:
lb = IntervalBox(inf.(X))
ub = IntervalBox(sup.(X))
inner = boundary
outer = boundary
lb_image = SS.f(lb)
if !isempty_interval(lb_image) && issubset_interval(lb_image, SS.constraint)
inner = inner ⊔ lb
else
outer = outer ⊔ lb
end
ub_image = SS.f(ub)
if !isempty_interval(ub_image) && issubset_interval(ub_image, SS.constraint)
inner = inner ⊔ ub
else
outer = outer ⊔ ub
end
return boundary, inner, outer
end