/
huber.jl
60 lines (50 loc) · 1.47 KB
/
huber.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
export huber
struct HuberAtom <: AbstractExpr
head::Symbol
id_hash::UInt64
children::Tuple{AbstractExpr}
size::Tuple{Int, Int}
M::Real
function HuberAtom(x::AbstractExpr, M::Real)
if sign(x) == ComplexSign()
error("Arguemt must be real")
elseif M <= 0
error("Huber parameter must by a positive scalar")
end
children = (x,)
return new(:huber, hash((children, M)), children, x.size, M)
end
end
function sign(x::HuberAtom)
return Positive()
end
function monotonicity(x::HuberAtom)
return (Nondecreasing() * sign(x.children[1]),)
end
function curvature(x::HuberAtom)
return ConvexVexity()
end
function evaluate(x::HuberAtom)
c = evaluate(x.children[1])
for i in 1:length(c)
if c[i] <= x.M
c[i] = c[i]^2
else
c[i] = 2*x.M*c[i] - x.M^2
end
end
return c
end
function conic_form!(x::HuberAtom, unique_conic_forms::UniqueConicForms=UniqueConicForms())
if !has_conic_form(unique_conic_forms, x)
c = x.children[1]
s = Variable(c.size)
n = Variable(c.size)
# objective given by s.^2 + 2 * M * |n|
objective = conic_form!(square(s) + 2 * x.M * abs(n), unique_conic_forms)
conic_form!(c == s + n, unique_conic_forms)
cache_conic_form!(unique_conic_forms, x, objective)
end
return get_conic_form(unique_conic_forms, x)
end
huber(x::AbstractExpr, M::Real=1.0) = HuberAtom(x, M)