TFOCS: tfocs_SCD options adjoint

I’m trying to solve a basis pursuit denoising problem uinsg tfocs_SCD.
I figured I would start by using the default options and tweak them to suit my needs.

Unfortunately, it seems like there is a bug in the defaults provided by tfocs_SCD.

This is a snippet from my code

  opts = tfocs_SCD(); % get the default options
  opts = rmfield(opts, 'adjoint');% this seems to fix a bug
  % in tfocs_SCD they invert the value of opts.adjoint in line 92
  % so i remove the parameter and let them set it back to the default


  [x, out, optsOut] = solver_sBPDN_W(A, WWt_rw, y, ...
                                      epsilon, mu, x, lambda0, opts, cont_opts);

Without my ‘fix’, this is the error message I get

Error using tfocs_initialize (line 294)
The elements in the last column must be constants.

Error in tfocs_AT (line 13)

Am I doing something wrong?


In reply to Stephen Becker:

Lines 41-44 have been replaced by lines 35-38 that are RIGHT above them. Line 39 is particularly confusing because both the if statement and the expression to be evaluated are on the same line.

In my original question, I made reference to lines 92, here is the relevant code

% The affine quantities will be used in adjoint orientation
if isfield( opts, 'adjoint'  ),
    opts.adjoint = ~opts.adjoint;
    opts.adjoint = true;

It seems very strange to be that opts.adjoint is inverted … The default opts return adjoint=true, then this inverts it, maybe it was meant to be a double negative?

opts.adjoint = ~~opts.adjoint

I need more than 10 karma to attach a file, so I’ve just copied the contents below.

Note, I just made a toy example and I’m not too interested if some of the parameter choices are entirely correct.

clear all;
close all;

% define the vector space and number of measurements
N = 100;
m = 30;
k = 3; % sparsity

% Make a sparse target
x = zeros(N, 1);
x(randperm(N, k)) = 1;

A = 2*(randi([0, 1], m, N) -0.5);

y = A *x;

W = @(x_) x_;
Wt = @(x_) x_;

epsilon = 0.1;
mu = 0.01;

opts = tfocs_SCD();
opts.debug = true;
% Comment out the line below to see the magic working
%opts = rmfield(opts, 'adjoint'); % this seems to fix a bug

WWt = linop_handles([N, N], W, Wt);

x_guess = A\y;
lambda_guess = [];

x_reconstructed = solver_sBPDN_W(A, WWt, y, epsilon, mu,  x_guess, lambda_guess, opts);

hold on
plot(x, 'vb')
plot(x_reconstructed, '^r');

---- Aug 22 2013 —
hmm, ok, I didn’t realize that adjoint was an internal parameter. Is there any reason why line 92 would ever need to be executed (maybe other solvers need it)? If there isn’t, why not simply remove the if statements around line 94 and let
opts.adjoint = true;


I think that may be a bug in the options; the lines 41-44 in tfocs_SCD.m are commented out, but they should not be. But it seems unrelated to the error you are getting. That error is called when it detects an input to be a function handle when it really should be a number. If you provide more code (describing A, WWt_rw, y, …) we can help you debug this.

Also, I recommend setting opts.debug=true when an error like this happens, as it will give you a bit more information on what is happening internally.

– Response to the revised question –

So I found the issue. The underlying root cause is that the ‘adjoint’ parameter is our internal parameter that is not for the user to manipulate, but since you wanted to have a set of default values, we gave you a default value for ‘adjoint’ when it doesn’t really have a default. Everything is fixed if you edit line 42 and remove x.adjoint=true with x = rmfield(x,'adjoint').

Line 39 isn’t confusing, it’s just poorly formatted so hard to read quickly, but the intent is clear. Lines 41-44 are not contradicting lines 35-38, but rather re-setting default values after tfocs handles them. Our convention to get default values requires some interesting tricks, since Matlab doesn’t have a standard way to do this.

Anyhow, bottom line is that the adjoint stuff works fine, and it’s confusing, but it isn’t necessary for the user to work with it. The problem is that we also tried to incorporate it into the default values, which is how it affected you. The new fix should clear it up.

Btw, for anyone else who runs this code, randperm(N, k) is not backward compatible with older versions of matlab; a substitute is randsample(N,k) if you have the stats toolbox.