|
1 | 1 | import RobotDynamics: jacobian!
|
2 | 2 |
|
3 |
| - |
4 |
| -"""" |
5 |
| -Specifies whether the constraint is an equality or inequality constraint. |
6 |
| -Valid subtypes are `Equality`, `Inequality` ⟺ `NegativeOrthant`, and `SecondOrderCone`. |
7 |
| -
|
8 |
| -The sense of a constraint can be queried using `sense(::AbstractConstraint)` |
9 |
| -
|
10 |
| -If `sense(con) <: Conic` (i.e. not `Equality`), then the following operations are supported: |
11 |
| -* `Base.in(::Conic, x::StaticVector)`. i.e. `x ∈ cone` |
12 |
| -* `projection(::Conic, x::StaticVector)` |
13 |
| -* `∇projection(::Conic, J, x::StaticVector)` |
14 |
| -* `∇²projection(::Conic, J, x::StaticVector, b::StaticVector)` |
15 |
| -""" |
16 |
| -abstract type ConstraintSense end |
17 |
| -abstract type Conic <: ConstraintSense end |
18 |
| - |
19 |
| -""" |
20 |
| -Equality constraints of the form ``g(x) = 0`. |
21 |
| -Type singleton, so it is created with `Equality()`. |
22 |
| -""" |
23 |
| -struct Equality <: ConstraintSense end |
24 |
| -""" |
25 |
| -Inequality constraints of the form ``h(x) \\leq 0``. |
26 |
| -Type singleton, so it is created with `Inequality()`. |
27 |
| -Equivalent to `NegativeOrthant`. |
28 |
| -""" |
29 |
| -struct NegativeOrthant <: Conic end |
30 |
| -const Inequality = NegativeOrthant |
31 |
| - |
32 |
| -struct PositiveOrthant <: Conic end |
33 |
| - |
34 |
| -""" |
35 |
| -The second-order cone is defined as |
36 |
| -``\\|x\\| \\leq t`` |
37 |
| -where ``x`` and ``t`` are both part of the cone. |
38 |
| -TrajectoryOptimization assumes the scalar part ``t`` is |
39 |
| -the last element in the vector. |
40 |
| -""" |
41 |
| -struct SecondOrderCone <: Conic end |
42 |
| - |
43 |
| -dualcone(::NegativeOrthant) = NegativeOrthant() |
44 |
| -dualcone(::PositiveOrthant) = PositiveOrthant() |
45 |
| -dualcone(::SecondOrderCone) = SecondOrderCone() |
46 |
| - |
47 |
| -projection(::NegativeOrthant, x) = min.(0, x) |
48 |
| -projection(::PositiveOrthant, x) = max.(0, x) |
49 |
| - |
50 |
| -function projection(::SecondOrderCone, x::StaticVector) |
51 |
| - # assumes x is stacked [v; s] such that ||v||₂ ≤ s |
52 |
| - s = x[end] |
53 |
| - v = pop(x) |
54 |
| - a = norm(v) |
55 |
| - if a <= -s # below the cone |
56 |
| - return zero(x) |
57 |
| - elseif a <= s # in the cone |
58 |
| - return x |
59 |
| - elseif a >= abs(s) # outside the cone |
60 |
| - return 0.5 * (1 + s/a) * push(v, a) |
61 |
| - else |
62 |
| - throw(ErrorException("Invalid second-order cone projection")) |
63 |
| - end |
64 |
| -end |
65 |
| - |
66 |
| -function ∇projection!(::SecondOrderCone, J, x::StaticVector{n}) where n |
67 |
| - s = x[end] |
68 |
| - v = pop(x) |
69 |
| - a = norm(v) |
70 |
| - if a <= -s # below cone |
71 |
| - J .*= 0 |
72 |
| - elseif a <= s # in cone |
73 |
| - J .*= 0 |
74 |
| - for i = 1:n |
75 |
| - J[i,i] = 1.0 |
76 |
| - end |
77 |
| - elseif a >= abs(s) # outside cone |
78 |
| - # scalar |
79 |
| - b = 0.5 * (1 + s/a) |
80 |
| - dbdv = -0.5*s/a^3 * v |
81 |
| - dbds = 0.5 / a |
82 |
| - |
83 |
| - # dvdv = dbdv * v' + b * oneunit(SMatrix{n-1,n-1,T}) |
84 |
| - for i = 1:n-1, j = 1:n-1 |
85 |
| - J[i,j] = dbdv[i] * v[j] |
86 |
| - if i == j |
87 |
| - J[i,j] += b |
88 |
| - end |
89 |
| - end |
90 |
| - |
91 |
| - # dvds |
92 |
| - J[1:n-1,n] .= dbds * v |
93 |
| - |
94 |
| - # ds |
95 |
| - dsdv = dbdv * a + b * v / a |
96 |
| - dsds = dbds * a |
97 |
| - ds = push(dsdv, dsds) |
98 |
| - J[n,:] .= ds |
99 |
| - else |
100 |
| - throw(ErrorException("Invalid second-order cone projection")) |
101 |
| - end |
102 |
| - return J |
103 |
| -end |
104 |
| - |
105 |
| -function Base.in(x, ::SecondOrderCone) |
106 |
| - s = x[end] |
107 |
| - v = pop(x) |
108 |
| - a = norm(v) |
109 |
| - return a <= s |
110 |
| -end |
111 |
| - |
112 |
| -function cone_status(::SecondOrderCone, x) |
113 |
| - s = x[end] |
114 |
| - v = pop(x) |
115 |
| - a = norm(v) |
116 |
| - if a <= -s |
117 |
| - return :below |
118 |
| - elseif a <= s |
119 |
| - return :in |
120 |
| - elseif a > abs(s) |
121 |
| - return :outside |
122 |
| - else |
123 |
| - return :invalid |
124 |
| - end |
125 |
| -end |
126 |
| - |
127 |
| -function ∇²projection!(::SecondOrderCone, hess, x::StaticVector, b::StaticVector) |
128 |
| - n = length(x) |
129 |
| - s = x[end] |
130 |
| - v = pop(x) |
131 |
| - bs = b[end] |
132 |
| - bv = pop(b) |
133 |
| - a = norm(v) |
134 |
| - |
135 |
| - if a <= -s |
136 |
| - return hess .= 0 |
137 |
| - elseif a <= s |
138 |
| - return hess .= 0 |
139 |
| - elseif a > abs(s) |
140 |
| - dvdv = -s/norm(v)^2/norm(v)*(I - (v*v')/(v'v))*bv*v' + |
141 |
| - s/norm(v)*((v*(v'bv))/(v'v)^2 * 2v' - (I*(v'bv) + v*bv')/(v'v)) + |
142 |
| - bs/norm(v)*(I - (v*v')/(v'v)) |
143 |
| - dvds = 1/norm(v)*(I - (v*v')/(v'v))*bv; |
144 |
| - dsdv = bv'/norm(v) - v'bv/norm(v)^3*v' |
145 |
| - dsds = 0 |
146 |
| - hess[1:n-1,1:n-1] .= dvdv*0.5 |
147 |
| - hess[1:n-1,n] .= dvds*0.5 |
148 |
| - hess[n:n,1:n-1] .= dsdv*0.5 |
149 |
| - hess[n,n] = 0 |
150 |
| - return hess |
151 |
| - # return 0.5*[dvdv dvds; dsdv dsds] |
152 |
| - else |
153 |
| - throw(ErrorException("Invalid second-order cone projection")) |
154 |
| - end |
155 |
| -end |
156 |
| - |
157 |
| -function ∇projection!(::NegativeOrthant, J, x::StaticVector{n}) where n |
158 |
| - for i = 1:n |
159 |
| - J[i,i] = x <= 0 ? 1 : 0 |
160 |
| - end |
161 |
| -end |
162 |
| - |
163 |
| -function ∇²projection!(::NegativeOrthant, hess, x::StaticVector, b::StaticVector) |
164 |
| - hess .= 0 |
165 |
| -end |
166 |
| - |
167 |
| -Base.in(::NegativeOrthant, x::StaticVector) = all(x->x<=0, x) |
168 |
| - |
169 | 3 | """
|
170 | 4 | AbstractConstraint
|
171 | 5 |
|
|
0 commit comments