/
transpose.jl
138 lines (107 loc) · 3.55 KB
/
transpose.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#############################################################################
# transpose.jl
# Returns the transpose of a matrix
# All expressions and atoms are subtpyes of AbstractExpr.
# Please read expressions.jl first.
#############################################################################
import Base.transpose, Base.adjoint
struct TransposeAtom <: AbstractExpr
head::Symbol
id_hash::UInt64
children::Tuple{AbstractExpr}
size::Tuple{Int, Int}
function TransposeAtom(x::AbstractExpr)
children = (x,)
return new(:transpose, hash(children), children, (x.size[2], x.size[1]))
end
end
function sign(x::TransposeAtom)
return sign(x.children[1])
end
function monotonicity(x::TransposeAtom)
return (Nondecreasing(),)
end
function curvature(x::TransposeAtom)
return ConstVexity()
end
function evaluate(x::TransposeAtom)
return transpose(evaluate(x.children[1]))
end
# Since everything is vectorized, we simply need to multiply x by a permutation
# matrix such that coeff * vectorized(x) - vectorized(x') = 0
function conic_form!(x::TransposeAtom, unique_conic_forms::UniqueConicForms)
if !has_conic_form(unique_conic_forms, x)
objective = conic_form!(x.children[1], unique_conic_forms)
sz = length(x)
num_rows = x.size[1]
num_cols = x.size[2]
I = Array{Int}(undef, sz)
J = Array{Int}(undef, sz)
k = 1
for r = 1:num_rows
for c = 1:num_cols
I[k] = (c - 1) * num_rows + r
J[k] = (r - 1) * num_cols + c
k += 1
end
end
transpose_matrix = sparse(I, J, 1.0)
objective = transpose_matrix * objective
cache_conic_form!(unique_conic_forms, x, objective)
end
return get_conic_form(unique_conic_forms, x)
end
transpose(x::AbstractExpr) = TransposeAtom(x)
struct AdjointAtom <: AbstractExpr
head::Symbol
id_hash::UInt64
children::Tuple{AbstractExpr}
size::Tuple{Int, Int}
function AdjointAtom(x::AbstractExpr)
children = (x,)
return new(:adjoint, hash(children), children, (x.size[2], x.size[1]))
end
end
function sign(x::AdjointAtom)
return sign(x.children[1])
end
function monotonicity(x::AdjointAtom)
return (Nondecreasing(),)
end
function curvature(x::AdjointAtom)
return ConstVexity()
end
function evaluate(x::AdjointAtom)
return evaluate(x.children[1])'
end
# Since everything is vectorized, we simply need to multiply x by a permutation
# matrix such that coeff * vectorized(x) - vectorized(x') = 0
function conic_form!(x::AdjointAtom, unique_conic_forms::UniqueConicForms)
if !has_conic_form(unique_conic_forms, x)
objective = conic_form!(x.children[1], unique_conic_forms)
sz = length(x)
num_rows = x.size[1]
num_cols = x.size[2]
I = Array{Int}(undef, sz)
J = Array{Int}(undef, sz)
k = 1
for r = 1:num_rows
for c = 1:num_cols
I[k] = (c - 1) * num_rows + r
J[k] = (r - 1) * num_cols + c
k += 1
end
end
transpose_matrix = sparse(I, J, 1.0)
objective = transpose_matrix * objective
for var in keys(objective)
x1 = conj(objective[var][1])
x2 = conj(objective[var][2])
objective[var] = (x1,x2)
end
cache_conic_form!(unique_conic_forms, x, objective)
end
return get_conic_form(unique_conic_forms, x)
end
adjoint(x::AbstractExpr) = AdjointAtom(x)
adjoint(x::Constant) = Constant(x.value')