Hello,
I am trying to build a sort of L_2-norm constraint piecewise, using
code like this (simplified form of the actual code):
x = [Convex.Variable(m*s+2r, m*s+2r) for _ in 1:N];
for t in 1:N
@debug "x[$(t)].id_hash is: " x[t]
end
Β± = [-1.0, +1.0]; # well, Julia does allow crazy variable names
total = 0;
for t in 1:N
@info "Starting computation of constraint A[$(t)] at $(now()) ..."
# 1. introduce sign perturbation `R`
a1 = (rand(Β±, size(x[t])) .* x[t]) + x[1];
# 2. 2D-convolution with PSF matrix `Q`
a2, cs = conv2d(Q, a1);
@debug "Result of conv2d(Q,x): " a2
# 3. build contraint
for i in 1:s, j in 1:s
total += a2[i,j] * a2[i,j];
end
end; # for t
constraint = (total < 42);
@debug "final constraint is: " constraint
Now the first 3 debug lines show that all involved variables have different IDs; in the final constraint however, all variable IDs are the one of x[1]
. Hereβs an excerpt from the logs:
DEBUG: x[1].id_hash is id: 18435402678986543539
DEBUG: x[2].id_hash is id: 2006040311771778825
DEBUG: x[3].id_hash is id: 4770220102282770796
DEBUG: x[4].id_hash is id: 384228606706033487
DEBUG: x[5].id_hash is id: 10429728996535255788
[ Info: Starting computation of constraint A[1] at 2020-03-14T08:22:23.864 ...
β Debug: Entering conv2d(Q,x):
β x =
β + (affine; real)
β ββ .* (affine; real)
β β ββ 102Γ102 Array{Float64,2}
β β ββ 102Γ102 real variable (id: 18435402678986543539)
β ββ 102Γ102 real variable (id: 18435402678986543539)
β @ Main ~/w/BEAM.jl/issue.jl:26
DEBUG: x_padded.id_hash=id: 6461239074267313883
β Debug: Result of conv2d(Q,x):
β a2 =
β index (affine; real)
β ββ reshape (affine; real)
β ββ * (affine; real)
β ββ 14884Γ12424 SparseMatrixCSC{Float64,Int64}
β ββ index (affine; real)
β ββ reshape (affine; real)
β ββ 122Γ122 real variable (id: 6461239074267313883)
β @ Main ~/w/BEAM.jl/issue.jl:100
...
β Debug: final constraint is:
β constraint =
β <= constraint (convex)
β ββ + (convex; positive)
β β ββ 0
β β ββ qol_elem (convex; positive)
β β β ββ index (affine; real)
β β β β ββ index (affine; real)
β β β β ββ reshape (affine; real)
β β β β ββ * (affine; real)
β β β β ββ 14884Γ12424 SparseMatrixCSC{Float64,Int64}
β β β β ββ index (affine; real)
β β β β ββ reshape (affine; real)
β β β β ββ 122Γ122 real variable (id: 6461239074267313883)
β β β ββ [1.0]
β β ββ qol_elem (convex; positive)
β β β ββ index (affine; real)
β β β β ββ index (affine; real)
β β β β ββ reshape (affine; real)
β β β β ββ * (affine; real)
β β β β ββ 14884Γ12424 SparseMatrixCSC{Float64,Int64}
β β β β ββ index (affine; real)
β β β β ββ reshape (affine; real)
β β β β ββ 122Γ122 real variable (id: 6461239074267313883)
β β β ββ [1.0]
...
Iβm relatively new to both Julia and Convex.jl so itβs possible that Iβm doing something wrong here, but I cannot see any issue in the codeβ¦
Thanks for any suggestion!
Hereβs a complete working example for reproducing the output above:
import Convex;
Convex.MAXDIGITS[] = 32; # show IDs in full
Convex.MAXWIDTH[] = 120;
Convex.MAXDEPTH[] = 12;
using SparseArrays;
using Dates: now;
# parameters controlling the size of the problem
const N = 5;
const r = 10;
const m = 2;
const s = 4*r + 1;
# generate fake data
Q = randn(2r+1,2r+1);
y = zeros(s,s,N);
for t = 1:N
y[:, :, t] .= sprand(Float64, s, s, 0.15);
end
# aux functions
function conv2d(Q, x)
@debug "Entering conv2d(Q,x): " x
Q_hat = make_conv2d_matrix(Q, size(x));
return conv2d(Q_hat, size(Q), x);
end # conv2d/2
function conv2d(Q_hat, Q_size, x)
m, n = Q_size;
k, l = size(x);
C_rows = m + k - 1;
C_cols = n + l -1;
x_padded = Convex.Variable(C_rows, C_cols);
@debug "x_padded.id_hash=$(Convex.show_id(x_padded))";
constraints = [
x_padded[1:k, 1:l] == x,
x_padded[(k+1):end, :] == 0,
x_padded[1:k, (l+1):end] == 0,
];
x_vector = vec(x_padded)[1 : (l-1)*(m+k-1)+k];
C_vector = Q_hat * x_vector;
C = reshape(C_vector, C_rows, C_cols);
return (C[m:k, n:l], constraints)
end # conv2d/3
function make_conv2d_matrix(Q, sz::Tuple{Int, Int})
m, n = size(Q);
k, l = sz;
Z_rows = m+k-1;
Z_cols = n+l-1;
Q_padded = zeros(Z_rows, Z_cols);
Q_padded[1:m, 1:n] .= Q;
Q_vec = vec(Q_padded)[1 : (n-1)*(m+k-1)+m];
return make_conv1d_matrix(Q_vec, (l-1)*(m+k-1)+k);
end # make_conv2D_matrix
function make_conv1d_matrix(v::AbstractVector, n::Int)
m = length(v);
# It is much more efficient to construct sparse matrices
# this way rather than starting from `spzeros` and indexing into it.
Is = Int[]
Js = Int[]
Vs = eltype(v)[]
for i = 1:n
for (ind, j) = enumerate(i:m+i-1:i)
push!(Is, i)
push!(Js, j)
push!(Vs, v[ind])
end
end
return sparse(Is, Js, Vs, m+n-1, n);
end # make_conv1D_matrix
# main
function main()
x = [Convex.Variable(m*s+2r, m*s+2r) for _ in 1:N];
for t in 1:N
@debug "x[$(t)].id_hash=$(Convex.show_id(x[t]))"
end
Β± = [-1.0, +1.0]; # well, Julia does allow crazy variable names
total = 0;
for t in 1:N
@info "Starting computation of constraint A[$(t)] at $(now()) ..."
# 1. introduce sign perturbation `R`
#a1 = x[1] + (rand(Β±, size(x[t])) .* x[t]);
a1 = (rand(Β±, size(x[t])) .* x[t]);
# 2. 2D-convolution with PSF matrix `Q`
a2, cs = conv2d(Q, a1);
@debug "Result of conv2d(Q,x): " a2
# 3. build contraint
for i in 1:s, j in 1:s
total += a2[i,j] * a2[i,j];
end
end; # for t
constraint = (total < 42);
@debug "final constraint is: " constraint
end # main
main()
Edit: Simplified MWE a bit.