function CFWCR_VOT()

	% *************************************************************
	% VOT: Always call exit command at the end to terminate Matlab!
	% *************************************************************
	cleanup = onCleanup(@() exit() );

	% *************************************************************
	% VOT: Set random seed to a different value every time.
	% *************************************************************
	RandStream.setGlobalStream(RandStream('mt19937ar', 'Seed', sum(clock)));

	% *************************************************************
	% VOT: init the resources
	% *************************************************************
	[wrapper_path, name, ext] = fileparts(mfilename('fullpath'));
	addpath(wrapper_path);
	cd_ind = strfind(wrapper_path, filesep());
	repo_path = wrapper_path(1:cd_ind(end)-1);
	addpath(repo_path);
	setup_paths();
	vl_setupnn();
	% **********************************
	% VOT: Get initialization data
	% **********************************
	[handle, image, region] = vot('polygon');
	% Initialize the tracker
	disp(image);
	bb_scale = 1;

	% If the provided region is a polygon ...
	if numel(region) > 4
	    % Init with an axis aligned bounding box with correct area and center
	    % coordinate
	    cx = mean(region(1:2:end));
	    cy = mean(region(2:2:end));
	    x1 = min(region(1:2:end));
	    x2 = max(region(1:2:end));
	    y1 = min(region(2:2:end));
	    y2 = max(region(2:2:end));
	    A1 = norm(region(1:2) - region(3:4)) * norm(region(3:4) - region(5:6));
	    A2 = (x2 - x1) * (y2 - y1);
	    s = sqrt(A1/A2);
	    w = s * (x2 - x1) + 1;
	    h = s * (y2 - y1) + 1;
	else
	    cx = region(1) + (region(3) - 1)/2;
	    cy = region(2) + (region(4) - 1)/2;
	    w = region(3);
	    h = region(4);
	end
	init_c = [cx cy];
	init_sz = bb_scale * [w h];

	im_size = size(imread(image));
	im_size = im_size([2 1]);

	init_pos = min(max(round(init_c - (init_sz - 1)/2), [1 1]), im_size);
	init_sz = min(max(round(init_sz), [1 1]), im_size - init_pos + 1);
	region = [init_pos, init_sz];
	frame = 1

	% **********************************
	% VOT: ECO init
	% **********************************
	params = init_param(region);

	max_train_samples = params.nSamples;
	features = params.t_features;

	% Set some default parameters
	params = init_default_params(params);
	if isfield(params, 't_global')
	    global_fparams = params.t_global;
	else
	    global_fparams = [];
	end

	% Init sequence data
	pos = params.init_pos(:)';
	target_sz = params.init_sz(:)';

	init_target_sz = target_sz;

	% Check if color image
	im = imread(image);
	if size(im,3) == 3
	    if all(all(im(:,:,1) == im(:,:,2)))
	        is_color_image = false;
	    else
	        is_color_image = true;
	    end
	else
	    is_color_image = false;
	end

	if size(im,3) > 1 && is_color_image == false
	    im = im(:,:,1);
	end

    params.use_mexResize = false;
    global_fparams.use_mexResize = false;
	% Calculate search area and initial scale factor
	search_area = prod(init_target_sz * params.search_area_scale);
	if search_area > params.max_image_sample_size
	    currentScaleFactor = sqrt(search_area / params.max_image_sample_size);
	elseif search_area < params.min_image_sample_size
	    currentScaleFactor = sqrt(search_area / params.min_image_sample_size);
	else
	    currentScaleFactor = 1.0;
	end

	% target size at the initial scale
	base_target_sz = target_sz / currentScaleFactor;
	% window size, taking padding into account
	switch params.search_area_shape
	    case 'proportional'
	        img_sample_sz = floor( base_target_sz * params.search_area_scale);     % proportional area, same aspect ratio as the target
	    case 'square'
	        img_sample_sz = repmat(sqrt(prod(base_target_sz * params.search_area_scale)), 1, 2); % square area, ignores the target aspect ratio
	    case 'fix_padding'
	        img_sample_sz = base_target_sz + sqrt(prod(base_target_sz * params.search_area_scale) + (base_target_sz(1) - base_target_sz(2))/4) - sum(base_target_sz)/2; % const padding
	    case 'custom'
	        img_sample_sz = [base_target_sz(1)*2 base_target_sz(2)*2]; % for testing
	end

	[features, global_fparams, feature_info] = init_features(features, global_fparams, is_color_image, img_sample_sz, 'odd_cells');
	% Set feature info
	img_support_sz = feature_info.img_support_sz;
	feature_sz = feature_info.data_sz;
	feature_dim = feature_info.dim;
	num_feature_blocks = length(feature_dim);
	feature_reg = permute(num2cell(feature_info.penalty), [2 3 1]);

	% Get feature specific parameters
	feature_params = init_feature_params(features, feature_info);
	feature_extract_info = get_feature_extract_info(features);
	if params.use_projection_matrix
	    compressed_dim = feature_params.compressed_dim;
	else
	    compressed_dim = feature_dim;
	end
	compressed_dim_cell = permute(num2cell(compressed_dim), [2 3 1]);
	% Size of the extracted feature maps
	feature_sz_cell = permute(mat2cell(feature_sz, ones(1,num_feature_blocks), 2), [2 3 1]);

	% Number of Fourier coefficients to save for each filter layer. This will
	% be an odd number.
	filter_sz = feature_sz + mod(feature_sz+1, 2);
	filter_sz_cell = permute(mat2cell(filter_sz, ones(1,num_feature_blocks), 2), [2 3 1]);

	% The size of the label function DFT. Equal to the maximum filter size.
	output_sz = max(filter_sz, [], 1);

	% How much each feature block has to be padded to the obtain output_sz
	pad_sz = cellfun(@(filter_sz) (output_sz - filter_sz) / 2, filter_sz_cell, 'uniformoutput', false);

	% Compute the Fourier series indices and their transposes
	ky = cellfun(@(sz) (-ceil((sz(1) - 1)/2) : floor((sz(1) - 1)/2))', filter_sz_cell, 'uniformoutput', false);
	kx = cellfun(@(sz) -ceil((sz(2) - 1)/2) : 0, filter_sz_cell, 'uniformoutput', false);

	% construct the Gaussian label function using Poisson formula
	sig_y = sqrt(prod(floor(base_target_sz))) * params.output_sigma_factor * (output_sz ./ img_support_sz);
	yf_y = cellfun(@(ky) single(sqrt(2*pi) * sig_y(1) / output_sz(1) * exp(-2 * (pi * sig_y(1) * ky / output_sz(1)).^2)), ky, 'uniformoutput', false);
	yf_x = cellfun(@(kx) single(sqrt(2*pi) * sig_y(2) / output_sz(2) * exp(-2 * (pi * sig_y(2) * kx / output_sz(2)).^2)), kx, 'uniformoutput', false);
	yf = cellfun(@(yf_y, yf_x) yf_y * yf_x, yf_y, yf_x, 'uniformoutput', false);

	% construct cosine window
	cos_window = cellfun(@(sz) single(hann(sz(1)+2)*hann(sz(2)+2)'), feature_sz_cell, 'uniformoutput', false);
	cos_window = cellfun(@(cos_window) cos_window(2:end-1,2:end-1), cos_window, 'uniformoutput', false);

	% Compute Fourier series of interpolation function
	[interp1_fs, interp2_fs] = cellfun(@(sz) get_interp_fourier(sz, params), filter_sz_cell, 'uniformoutput', false);
	% Get the reg_window_edge parameter
	reg_window_edge = {};
	for k = 1:length(features)
	    if isfield(features{k}.fparams, 'reg_window_edge')
	        reg_window_edge = cat(3, reg_window_edge, permute(num2cell(features{k}.fparams.reg_window_edge(:)), [2 3 1]));
	    else
	        reg_window_edge = cat(3, reg_window_edge, cell(1, 1, length(features{k}.fparams.nDim)));
	    end
	end

	% Construct spatial regularization filter
	reg_filter = cellfun(@(reg_window_edge) get_reg_filter(img_support_sz, base_target_sz, params, reg_window_edge), reg_window_edge, 'uniformoutput', false);

	% Compute the energy of the filter (used for preconditioner)
	reg_energy = cellfun(@(reg_filter) real(reg_filter(:)' * reg_filter(:)), reg_filter, 'uniformoutput', false);

	if params.use_scale_filter
	    [nScales, scale_step, scaleFactors, scale_filter, params] = init_scale_filter(params);
	else
	    % Use the translation filter to estimate the scale.
	    nScales = params.number_of_scales;
	    scale_step = params.scale_step;
	    scale_exp = (-floor((nScales-1)/2):ceil((nScales-1)/2));
	    scaleFactors = scale_step .^ scale_exp;
	end

	if nScales > 0
	    %force reasonable scale changes
	    min_scale_factor = scale_step ^ ceil(log(max(5 ./ img_support_sz)) / log(scale_step));
	    max_scale_factor = scale_step ^ floor(log(min([size(im,1) size(im,2)] ./ base_target_sz)) / log(scale_step));
	end

	% Set conjugate gradient uptions
	init_CG_opts.CG_use_FR = true;
	init_CG_opts.tol = 1e-6;
	init_CG_opts.CG_standard_alpha = true;
	init_CG_opts.debug = 0;
	CG_opts.CG_use_FR = params.CG_use_FR;
	CG_opts.tol = 1e-6;
	CG_opts.CG_standard_alpha = params.CG_standard_alpha;
	CG_opts.debug = 0;

	time = 0;

	% Initialize and allocate
	prior_weights = zeros(max_train_samples,1, 'single');
	sample_weights = prior_weights;
	samplesf = cell(1, 1, num_feature_blocks);
	for k = 1:num_feature_blocks
	    samplesf{k} = complex(zeros(max_train_samples,compressed_dim(k),filter_sz(k,1),(filter_sz(k,2)+1)/2,'single'));
	end
	score_matrix = inf(max_train_samples, 'single');

	latest_ind = [];
	frames_since_last_train = inf;
	num_training_samples = 0;
	minimum_sample_weight = params.learning_rate*(1-params.learning_rate)^(2*max_train_samples);

	res_norms = [];
	residuals_pcg = [];
	if frame == 1
        % Extract image region for training sample
        sample_pos = round(pos);
        sample_scale = currentScaleFactor;
        xl = extract_features(im, sample_pos, currentScaleFactor, features, global_fparams, feature_extract_info);

        % Do windowing of features
        xlw = cellfun(@(feat_map, cos_window) bsxfun(@times, feat_map, cos_window), xl, cos_window, 'uniformoutput', false);

        % Compute the fourier series
        xlf = cellfun(@cfft2, xlw, 'uniformoutput', false);

        % Interpolate features to the continuous domain
        xlf = interpolate_dft(xlf, interp1_fs, interp2_fs);

        % New sample to be added
        xlf = compact_fourier_coeff(xlf);

        % Initialize projection matrix
        xl1 = cellfun(@(x) reshape(x, [], size(x,3)), xl, 'uniformoutput', false);
        xl1 = cellfun(@(x) bsxfun(@minus, x, mean(x, 1)), xl1, 'uniformoutput', false);

        if strcmpi(params.proj_init_method, 'pca')
            [projection_matrix, ~, ~] = cellfun(@(x) svd(x' * x), xl1, 'uniformoutput', false);
            projection_matrix = cellfun(@(P, dim) single(P(:,1:dim)), projection_matrix, compressed_dim_cell, 'uniformoutput', false);
        elseif strcmpi(params.proj_init_method, 'rand_uni')
            projection_matrix = cellfun(@(x, dim) single(randn(size(x,2), dim)), xl1, compressed_dim_cell, 'uniformoutput', false);
            projection_matrix = cellfun(@(P) bsxfun(@rdivide, P, sqrt(sum(P.^2,1))), projection_matrix, 'uniformoutput', false);
        elseif strcmpi(params.proj_init_method, 'none')
            projection_matrix = [];
        else
            error('Unknown initialization method for the projection matrix: %s', params.proj_init_method);
        end
        clear xl1 xlw

        % Shift sample
        shift_samp = 2*pi * (pos - sample_pos) ./ (sample_scale * img_support_sz);
        xlf = shift_sample(xlf, shift_samp, kx, ky);

        % Project sample
        xlf_proj = project_sample(xlf, projection_matrix);
    elseif params.learning_rate > 0
        if ~params.use_detection_sample
            % Extract image region for training sample
            sample_pos = round(pos);
            sample_scale = currentScaleFactor;
            xl = extract_features(im, sample_pos, currentScaleFactor, features, global_fparams, feature_extract_info);

            % Project sample
            xl_proj = project_sample(xl, projection_matrix);

            % Do windowing of features
            xl_proj = cellfun(@(feat_map, cos_window) bsxfun(@times, feat_map, cos_window), xl_proj, cos_window, 'uniformoutput', false);

            % Compute the fourier series
            xlf1_proj = cellfun(@cfft2, xl_proj, 'uniformoutput', false);

            % Interpolate features to the continuous domain
            xlf1_proj = interpolate_dft(xlf1_proj, interp1_fs, interp2_fs);

            % New sample to be added
            xlf_proj = compact_fourier_coeff(xlf1_proj);
        else
            % Use the sample that was used for detection
            sample_scale = sample_scale(scale_ind);
            xlf_proj = cellfun(@(xf) xf(:,1:(size(xf,2)+1)/2,:,scale_ind), xtf_proj, 'uniformoutput', false);
        end

        % Shift the sample so that the target is centered
        shift_samp = 2*pi * (pos - sample_pos) ./ (sample_scale * img_support_sz);
        xlf_proj = shift_sample(xlf_proj, shift_samp, kx, ky);
    end
    xlf_proj_perm = cellfun(@(xf) permute(xf, [4 3 1 2]), xlf_proj, 'uniformoutput', false);

	if params.use_sample_merge
        % Find the distances with existing samples
        dist_vector = find_cluster_distances(samplesf, xlf_proj_perm, num_feature_blocks, num_training_samples, max_train_samples, params);

        [merged_sample, new_cluster, merged_cluster_id, new_cluster_id, score_matrix, prior_weights,num_training_samples] = ...
            merge_clusters(samplesf, xlf_proj_perm, dist_vector, score_matrix, prior_weights,...
                           num_training_samples,num_feature_blocks,max_train_samples,minimum_sample_weight,params);
    else
        % Do the traditional adding of a training sample and weight update
        % of C-COT
        [prior_weights, replace_ind] = update_prior_weights(prior_weights, sample_weights, latest_ind, frame, params);
        latest_ind = replace_ind;

        merged_cluster_id = 0;
        new_cluster = xlf_proj_perm;
        new_cluster_id = replace_ind;
    end

    if frame > 1 && params.learning_rate > 0 || frame == 1 && ~params.update_projection_matrix
        % Insert the new training sample
        for k = 1:num_feature_blocks
            if merged_cluster_id > 0
                samplesf{k}(merged_cluster_id,:,:,:) = merged_sample{k};
            end

            if new_cluster_id > 0
                samplesf{k}(new_cluster_id,:,:,:) = new_cluster{k};
            end
        end
    end

    sample_weights = prior_weights;

    train_tracker = (frame < params.skip_after_frame) || (frames_since_last_train >= params.train_gap);
    if train_tracker
        % Used for preconditioning
        new_sample_energy = cellfun(@(xlf) abs(xlf .* conj(xlf)), xlf_proj, 'uniformoutput', false);

        if frame == 1
            if params.update_projection_matrix
                hf = cell(2,1,num_feature_blocks);
                lf_ind = cellfun(@(sz) sz(1) * (sz(2)-1)/2 + 1, filter_sz_cell, 'uniformoutput', false);
                proj_energy = cellfun(@(P, yf) 2*sum(abs(yf(:)).^2) / sum(feature_dim) * ones(size(P), 'single'), projection_matrix, yf, 'uniformoutput', false);
            else
                hf = cell(1,1,num_feature_blocks);
            end
            % Initialize the filter
            for k = 1:num_feature_blocks
                hf{1,1,k} = complex(zeros([filter_sz(k,1) (filter_sz(k,2)+1)/2 compressed_dim(k)], 'single'));
            end

            % Initialize Conjugate Gradient parameters
            CG_opts.maxit = params.init_CG_iter; % Number of initial iterations if projection matrix is not updated
            init_CG_opts.maxit = ceil(params.init_CG_iter / params.init_GN_iter);
            sample_energy = new_sample_energy;
            rhs_samplef = cell(size(hf));
            diag_M = cell(size(hf));
            p = []; rho = []; r_old = [];
        else
            CG_opts.maxit = params.CG_iter;

            if params.CG_forgetting_rate == inf || params.learning_rate >= 1
                % CG will be reset
                p = []; rho = []; r_old = [];
            else
                rho = rho / (1-params.learning_rate)^params.CG_forgetting_rate;
            end
            % Update the approximate average sample energy using the learning
            % rate. This is only used to construct the preconditioner.
            sample_energy = cellfun(@(se, nse) (1 - params.learning_rate) * se + params.learning_rate * nse, sample_energy, new_sample_energy, 'uniformoutput', false);
        end
        % Do training
        if frame == 1 && params.update_projection_matrix
            % Initial Gauss-Newton optimization of the filter and
            % projection matrix.

            % Construct stuff for the proj matrix part
            init_samplef = cellfun(@(x) permute(x, [4 3 1 2]), xlf, 'uniformoutput', false);
            init_samplef_H = cellfun(@(X) conj(reshape(X, size(X,2), [])), init_samplef, 'uniformoutput', false);

            % Construct preconditioner
            diag_M(1,1,:) = cellfun(@(m, reg_energy) (1-params.precond_reg_param) * bsxfun(@plus, params.precond_data_param * m, (1-params.precond_data_param) * mean(m,3)) + params.precond_reg_param*reg_energy, sample_energy, reg_energy, 'uniformoutput',false);
            diag_M(2,1,:) = cellfun(@(m) params.precond_proj_param * (m + params.projection_reg), proj_energy, 'uniformoutput',false);

            projection_matrix_init = projection_matrix;
            for iter = 1:params.init_GN_iter
                % Project sample with new matrix
                init_samplef_proj = cellfun(@(x,P) mtimesx(x, P, 'speed'), init_samplef, projection_matrix, 'uniformoutput', false);
                init_hf = cellfun(@(x) permute(x, [3 4 1 2]), hf(1,1,:), 'uniformoutput', false);

                % Construct the right hand side vector for the filter part
                rhs_samplef(1,1,:) = cellfun(@(xf, yf) bsxfun(@times, conj(permute(xf, [3 4 2 1])), yf), init_samplef_proj, yf, 'uniformoutput', false);

                % Construct the right hand side vector for the projection matrix part
                fyf = cellfun(@(f, yf) reshape(bsxfun(@times, conj(f), yf), [], size(f,3)), hf(1,1,:), yf, 'uniformoutput', false);
                rhs_samplef(2,1,:) = cellfun(@(P, XH, fyf, fi) (2*real(XH * fyf - XH(:,fi:end) * fyf(fi:end,:)) - params.projection_reg * P), ...
                    projection_matrix, init_samplef_H, fyf, lf_ind, 'uniformoutput', false);

                % Initialize the projection matrix increment to zero
                hf(2,1,:) = cellfun(@(P) zeros(size(P), 'single'), projection_matrix, 'uniformoutput', false);

                % do conjugate gradient
                [hf, ~, ~, ~, res_norms_temp] = pcg_ccot(...
                    @(x) lhs_operation_joint(x, init_samplef_proj, reg_filter, feature_reg, init_samplef, init_samplef_H, init_hf, params.projection_reg),...
                    rhs_samplef, init_CG_opts, ...
                    @(x) diag_precond(x, diag_M), ...
                    [], hf);

                % Make the filter symmetric (avoid roundoff errors)
                hf(1,1,:) = symmetrize_filter(hf(1,1,:));

                % Add to the projection matrix
                projection_matrix = cellfun(@plus, projection_matrix, hf(2,1,:), 'uniformoutput', false);

                res_norms = [res_norms; res_norms_temp];
            end
            % Extract filter
            hf = hf(1,1,:);
            % Re-project and insert training sample
            xlf_proj = project_sample(xlf, projection_matrix);
            for k = 1:num_feature_blocks
                samplesf{k}(1,:,:,:) = permute(xlf_proj{k}, [4 3 1 2]);
            end
        else
            % Construct the right hand side vector
            rhs_samplef = cellfun(@(xf) permute(mtimesx(sample_weights, 'T', xf, 'speed'), [3 4 2 1]), samplesf, 'uniformoutput', false);
            rhs_samplef = cellfun(@(xf, yf) bsxfun(@times, conj(xf), yf), rhs_samplef, yf, 'uniformoutput', false);

            % Construct preconditioner
            diag_M = cellfun(@(m, reg_energy) (1-params.precond_reg_param) * bsxfun(@plus, params.precond_data_param * m, (1-params.precond_data_param) * mean(m,3)) + params.precond_reg_param*reg_energy, sample_energy, reg_energy, 'uniformoutput',false);

            % do conjugate gradient
            [hf, ~, ~, ~, res_norms, p, rho, r_old] = pcg_ccot(...
                @(x) lhs_operation(x, samplesf, reg_filter, sample_weights, feature_reg),...
                rhs_samplef, CG_opts, ...
                @(x) diag_precond(x, diag_M), ...
                [], hf, p, rho, r_old);
        end

        % Reconstruct the full Fourier series
        hf_full = full_fourier_coeff(hf);
        frames_since_last_train = 0;
    else
        frames_since_last_train = frames_since_last_train+1;
    end

    % Update the scale filter
    if nScales > 0 && params.use_scale_filter
        scale_filter = scale_filter_update(im, pos, base_target_sz, currentScaleFactor, scale_filter, params);
    end
    % Update the target size (only used for computing output box)
    target_sz = base_target_sz * currentScaleFactor;
	while true
	    % **********************************
	    % VOT: Get next frame
	    % **********************************
	    [handle, image] = handle.frame(handle);
	    if isempty(image)
	        break;
	    end;
	    disp(image);
	    frame = frame + 1;

		% **********************************
		% VOT: ECO update
		% **********************************
		im = imread(image);
    	if size(im,3) > 1 && is_color_image == false
        	im = im(:,:,1);
        end
		if frame > 1
	        old_pos = inf(size(pos));
	        iter = 1;
	        %translation search
	        while iter <= params.refinement_iterations && any(old_pos ~= pos)
	            % Extract features at multiple resolutions
	            sample_pos = round(pos);
	            det_sample_pos = sample_pos;
	            sample_scale = currentScaleFactor*scaleFactors;
	            xt = extract_features(im, sample_pos, sample_scale, features, global_fparams, feature_extract_info);
	            % Project sample
	            xt_proj = project_sample(xt, projection_matrix);

	            % Do windowing of features
	            xt_proj = cellfun(@(feat_map, cos_window) bsxfun(@times, feat_map, cos_window), xt_proj, cos_window, 'uniformoutput', false);

	            % Compute the fourier series
	            xtf_proj = cellfun(@cfft2, xt_proj, 'uniformoutput', false);

	            % Interpolate features to the continuous domain
	            xtf_proj = interpolate_dft(xtf_proj, interp1_fs, interp2_fs);
	            % Compute convolution for each feature block in the Fourier domain
	            scores_fs_feat = cellfun(@(hf, xf, pad_sz) padarray(sum(bsxfun(@times, hf, xf), 3), pad_sz), hf_full, xtf_proj, pad_sz, 'uniformoutput', false);
	            switch params.weights_type
						    case 'constant'
						    	scores_fs_feat{1,1,1} = param.weights(1) *scores_fs_feat{1,1,1};
						    	scores_fs_feat{1,1,2} = param.weights(2) *scores_fs_feat{1,1,1};
						    case 'sigmoid'
						    	coe = params.initial - params.factor./ (1 + exp(-double(frame)/params.divide_denominator));
						    	scores_fs_feat{1,1,1} = 1*scores_fs_feat{1,1,1};
	            		scores_fs_feat{1,1,2} = coe*scores_fs_feat{1,1,2};
							end
	            % Also sum over all feature blocks.
	            % Gives the fourier coefficients of the convolution response.
	            scores_fs = permute(sum(cell2mat(scores_fs_feat), 3), [1 2 4 3]);

	            % Optimize the continuous score function with Newton's method.
	            [trans_row, trans_col, scale_ind] = optimize_scores(scores_fs, params.newton_iterations);
	            % Compute the translation vector in pixel-coordinates and round
	            % to the closest integer pixel.
	            translation_vec = [trans_row, trans_col] .* (img_support_sz./output_sz) * currentScaleFactor * scaleFactors(scale_ind);
	            scale_change_factor = scaleFactors(scale_ind);

	            % update position
	            old_pos = pos;
	            pos = sample_pos + translation_vec;

	            if params.clamp_position
	                pos = max([1 1], min([size(im,1) size(im,2)], pos));
	            end
	            % Do scale tracking with the scale filter
	            if nScales > 0 && params.use_scale_filter
	                scale_change_factor = scale_filter_track(im, pos, base_target_sz, currentScaleFactor, scale_filter, params);
	            end
	            % Update the scale
	            currentScaleFactor = currentScaleFactor * scale_change_factor;

	            % Adjust to make sure we are not to large or to small
	            if currentScaleFactor < min_scale_factor
	                currentScaleFactor = min_scale_factor;
	            elseif currentScaleFactor > max_scale_factor
	                currentScaleFactor = max_scale_factor;
	            end

	            iter = iter + 1;
	        end
		end
	    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	    %% Model update step
	    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	    % Extract sample and init projection matrix
	    if frame == 1
	        % Extract image region for training sample
	        sample_pos = round(pos);
	        sample_scale = currentScaleFactor;
	        xl = extract_features(im, sample_pos, currentScaleFactor, features, global_fparams, feature_extract_info);

	        % Do windowing of features
	        xlw = cellfun(@(feat_map, cos_window) bsxfun(@times, feat_map, cos_window), xl, cos_window, 'uniformoutput', false);

	        % Compute the fourier series
	        xlf = cellfun(@cfft2, xlw, 'uniformoutput', false);

	        % Interpolate features to the continuous domain
	        xlf = interpolate_dft(xlf, interp1_fs, interp2_fs);

	        % New sample to be added
	        xlf = compact_fourier_coeff(xlf);

	        % Initialize projection matrix
	        xl1 = cellfun(@(x) reshape(x, [], size(x,3)), xl, 'uniformoutput', false);
	        xl1 = cellfun(@(x) bsxfun(@minus, x, mean(x, 1)), xl1, 'uniformoutput', false);

	        if strcmpi(params.proj_init_method, 'pca')
	            [projection_matrix, ~, ~] = cellfun(@(x) svd(x' * x), xl1, 'uniformoutput', false);
	            projection_matrix = cellfun(@(P, dim) single(P(:,1:dim)), projection_matrix, compressed_dim_cell, 'uniformoutput', false);
	        elseif strcmpi(params.proj_init_method, 'rand_uni')
	            projection_matrix = cellfun(@(x, dim) single(randn(size(x,2), dim)), xl1, compressed_dim_cell, 'uniformoutput', false);
	            projection_matrix = cellfun(@(P) bsxfun(@rdivide, P, sqrt(sum(P.^2,1))), projection_matrix, 'uniformoutput', false);
	        elseif strcmpi(params.proj_init_method, 'none')
	            projection_matrix = [];
	        else
	            error('Unknown initialization method for the projection matrix: %s', params.proj_init_method);
	        end
	        clear xl1 xlw

	        % Shift sample
	        shift_samp = 2*pi * (pos - sample_pos) ./ (sample_scale * img_support_sz);
	        xlf = shift_sample(xlf, shift_samp, kx, ky);

	        % Project sample
	        xlf_proj = project_sample(xlf, projection_matrix);
	    elseif params.learning_rate > 0
	        if ~params.use_detection_sample
	            % Extract image region for training sample
	            sample_pos = round(pos);
	            sample_scale = currentScaleFactor;
	            xl = extract_features(im, sample_pos, currentScaleFactor, features, global_fparams, feature_extract_info);

	            % Project sample
	            xl_proj = project_sample(xl, projection_matrix);

	            % Do windowing of features
	            xl_proj = cellfun(@(feat_map, cos_window) bsxfun(@times, feat_map, cos_window), xl_proj, cos_window, 'uniformoutput', false);

	            % Compute the fourier series
	            xlf1_proj = cellfun(@cfft2, xl_proj, 'uniformoutput', false);

	            % Interpolate features to the continuous domain
	            xlf1_proj = interpolate_dft(xlf1_proj, interp1_fs, interp2_fs);

	            % New sample to be added
	            xlf_proj = compact_fourier_coeff(xlf1_proj);
	        else
	            % Use the sample that was used for detection
	            sample_scale = sample_scale(scale_ind);
	            xlf_proj = cellfun(@(xf) xf(:,1:(size(xf,2)+1)/2,:,scale_ind), xtf_proj, 'uniformoutput', false);
	        end

	        % Shift the sample so that the target is centered
	        shift_samp = 2*pi * (pos - sample_pos) ./ (sample_scale * img_support_sz);
	        xlf_proj = shift_sample(xlf_proj, shift_samp, kx, ky);
	    end
	    xlf_proj_perm = cellfun(@(xf) permute(xf, [4 3 1 2]), xlf_proj, 'uniformoutput', false);
	    if params.use_sample_merge
	        % Find the distances with existing samples
	        dist_vector = find_cluster_distances(samplesf, xlf_proj_perm, num_feature_blocks, num_training_samples, max_train_samples, params);

	        [merged_sample, new_cluster, merged_cluster_id, new_cluster_id, score_matrix, prior_weights,num_training_samples] = ...
	            merge_clusters(samplesf, xlf_proj_perm, dist_vector, score_matrix, prior_weights,...
	                           num_training_samples,num_feature_blocks,max_train_samples,minimum_sample_weight,params);
	    else
	        % Do the traditional adding of a training sample and weight update
	        % of C-COT
	        [prior_weights, replace_ind] = update_prior_weights(prior_weights, sample_weights, latest_ind, frame, params);
	        latest_ind = replace_ind;

	        merged_cluster_id = 0;
	        new_cluster = xlf_proj_perm;
	        new_cluster_id = replace_ind;
	    end
	    if frame > 1 && params.learning_rate > 0 || frame == 1 && ~params.update_projection_matrix
	        % Insert the new training sample
	        for k = 1:num_feature_blocks
	            if merged_cluster_id > 0
	                samplesf{k}(merged_cluster_id,:,:,:) = merged_sample{k};
	            end

	            if new_cluster_id > 0
	                samplesf{k}(new_cluster_id,:,:,:) = new_cluster{k};
	            end
	        end
	    end
	    sample_weights = prior_weights;

	    train_tracker = (frame < params.skip_after_frame) || (frames_since_last_train >= params.train_gap);
	    if train_tracker
	        % Used for preconditioning
	        new_sample_energy = cellfun(@(xlf) abs(xlf .* conj(xlf)), xlf_proj, 'uniformoutput', false);
	        if frame == 1
	            if params.update_projection_matrix
	                hf = cell(2,1,num_feature_blocks);
	                lf_ind = cellfun(@(sz) sz(1) * (sz(2)-1)/2 + 1, filter_sz_cell, 'uniformoutput', false);
	                proj_energy = cellfun(@(P, yf) 2*sum(abs(yf(:)).^2) / sum(feature_dim) * ones(size(P), 'single'), projection_matrix, yf, 'uniformoutput', false);
	            else
	                hf = cell(1,1,num_feature_blocks);
	            end
	            % Initialize the filter
	            for k = 1:num_feature_blocks
	                hf{1,1,k} = complex(zeros([filter_sz(k,1) (filter_sz(k,2)+1)/2 compressed_dim(k)], 'single'));
	            end

	            % Initialize Conjugate Gradient parameters
	            CG_opts.maxit = params.init_CG_iter; % Number of initial iterations if projection matrix is not updated
	            init_CG_opts.maxit = ceil(params.init_CG_iter / params.init_GN_iter);
	            sample_energy = new_sample_energy;
	            rhs_samplef = cell(size(hf));
	            diag_M = cell(size(hf));
	            p = []; rho = []; r_old = [];
	        else
	            CG_opts.maxit = params.CG_iter;

	            if params.CG_forgetting_rate == inf || params.learning_rate >= 1
	                % CG will be reset
	                p = []; rho = []; r_old = [];
	            else
	                rho = rho / (1-params.learning_rate)^params.CG_forgetting_rate;
	            end
	            % Update the approximate average sample energy using the learning
	            % rate. This is only used to construct the preconditioner.
	            sample_energy = cellfun(@(se, nse) (1 - params.learning_rate) * se + params.learning_rate * nse, sample_energy, new_sample_energy, 'uniformoutput', false);
	        end
	        % Do training
	        if frame == 1 && params.update_projection_matrix
	            % Initial Gauss-Newton optimization of the filter and
	            % projection matrix.

	            % Construct stuff for the proj matrix part
	            init_samplef = cellfun(@(x) permute(x, [4 3 1 2]), xlf, 'uniformoutput', false);
	            init_samplef_H = cellfun(@(X) conj(reshape(X, size(X,2), [])), init_samplef, 'uniformoutput', false);

	            % Construct preconditioner
	            diag_M(1,1,:) = cellfun(@(m, reg_energy) (1-params.precond_reg_param) * bsxfun(@plus, params.precond_data_param * m, (1-params.precond_data_param) * mean(m,3)) + params.precond_reg_param*reg_energy, sample_energy, reg_energy, 'uniformoutput',false);
	            diag_M(2,1,:) = cellfun(@(m) params.precond_proj_param * (m + params.projection_reg), proj_energy, 'uniformoutput',false);

	            projection_matrix_init = projection_matrix;

	            for iter = 1:params.init_GN_iter
	                % Project sample with new matrix
	                init_samplef_proj = cellfun(@(x,P) mtimesx(x, P, 'speed'), init_samplef, projection_matrix, 'uniformoutput', false);
	                init_hf = cellfun(@(x) permute(x, [3 4 1 2]), hf(1,1,:), 'uniformoutput', false);

	                % Construct the right hand side vector for the filter part
	                rhs_samplef(1,1,:) = cellfun(@(xf, yf) bsxfun(@times, conj(permute(xf, [3 4 2 1])), yf), init_samplef_proj, yf, 'uniformoutput', false);

	                % Construct the right hand side vector for the projection matrix part
	                fyf = cellfun(@(f, yf) reshape(bsxfun(@times, conj(f), yf), [], size(f,3)), hf(1,1,:), yf, 'uniformoutput', false);
	                rhs_samplef(2,1,:) = cellfun(@(P, XH, fyf, fi) (2*real(XH * fyf - XH(:,fi:end) * fyf(fi:end,:)) - params.projection_reg * P), ...
	                    projection_matrix, init_samplef_H, fyf, lf_ind, 'uniformoutput', false);

	                % Initialize the projection matrix increment to zero
	                hf(2,1,:) = cellfun(@(P) zeros(size(P), 'single'), projection_matrix, 'uniformoutput', false);

	                % do conjugate gradient
	                [hf, ~, ~, ~, res_norms_temp] = pcg_ccot(...
	                    @(x) lhs_operation_joint(x, init_samplef_proj, reg_filter, feature_reg, init_samplef, init_samplef_H, init_hf, params.projection_reg),...
	                    rhs_samplef, init_CG_opts, ...
	                    @(x) diag_precond(x, diag_M), ...
	                    [], hf);

	                % Make the filter symmetric (avoid roundoff errors)
	                hf(1,1,:) = symmetrize_filter(hf(1,1,:));

	                % Add to the projection matrix
	                projection_matrix = cellfun(@plus, projection_matrix, hf(2,1,:), 'uniformoutput', false);

	                res_norms = [res_norms; res_norms_temp];
	            end
	            % Extract filter
	            hf = hf(1,1,:);

	            % Re-project and insert training sample
	            xlf_proj = project_sample(xlf, projection_matrix);
	            for k = 1:num_feature_blocks
	                samplesf{k}(1,:,:,:) = permute(xlf_proj{k}, [4 3 1 2]);
	            end
	        else
	            % Construct the right hand side vector
	            rhs_samplef = cellfun(@(xf) permute(mtimesx(sample_weights, 'T', xf, 'speed'), [3 4 2 1]), samplesf, 'uniformoutput', false);
	            rhs_samplef = cellfun(@(xf, yf) bsxfun(@times, conj(xf), yf), rhs_samplef, yf, 'uniformoutput', false);

	            % Construct preconditioner
	            diag_M = cellfun(@(m, reg_energy) (1-params.precond_reg_param) * bsxfun(@plus, params.precond_data_param * m, (1-params.precond_data_param) * mean(m,3)) + params.precond_reg_param*reg_energy, sample_energy, reg_energy, 'uniformoutput',false);

	            % do conjugate gradient
	            [hf, ~, ~, ~, res_norms, p, rho, r_old] = pcg_ccot(...
	                @(x) lhs_operation(x, samplesf, reg_filter, sample_weights, feature_reg),...
	                rhs_samplef, CG_opts, ...
	                @(x) diag_precond(x, diag_M), ...
	                [], hf, p, rho, r_old);
	        end

	        % Reconstruct the full Fourier series
	        hf_full = full_fourier_coeff(hf);

	        frames_since_last_train = 0;
	    else
	        frames_since_last_train = frames_since_last_train+1;
	    end
	    % Update the scale filter
	    if nScales > 0 && params.use_scale_filter
	        scale_filter = scale_filter_update(im, pos, base_target_sz, currentScaleFactor, scale_filter, params);
	    end
	    % Update the target size (only used for computing output box)
	    target_sz = base_target_sz * currentScaleFactor;

	    %save position and calculate FPS
	    region = round([pos([2,1]) - (target_sz([2,1]) - 1)/2, target_sz([2,1])]);
	    region = double(region);
	    disp(region);

	    % **********************************
	    % VOT: Report position for frame
	    % **********************************
	    handle = handle.report(handle, region);

	end;
	% **********************************
	% VOT: Output the results
	% **********************************
	handle.quit(handle);

end

function params = init_param(region)

	cnn_params.nn_name = 'imagenet-vgg-m-2048-cut.mat'; % Name of the network
	cnn_params.output_layer = [3 14];
	cnn_params.downsample_factor = [2 1];           % How much to downsample each output layer
	cnn_params.input_size_mode = 'adaptive';        % How to choose the sample size
	cnn_params.input_size_scale = 1;                % Extra scale factor of the input samples to the network (1 is no scaling)
	cnn_params.use_gpu = true;
	cnn_params.gpu_id = [3];

	% Which features to include
	params.t_features = {
	    struct('getFeature',@get_cnn_layers, 'fparams',cnn_params),...
	};

	% Global feature parameters1s
	params.t_global.normalize_power = 2;    % Lp normalization with this p
	params.t_global.normalize_size = true;  % Also normalize with respect to the spatial size of the feature
	params.t_global.normalize_dim = true;   % Also normalize with respect to the dimensionality of the feature

	% Image sample parameters
	params.search_area_shape = 'square';    % The shape of the samples
	params.search_area_scale = 4.0;         % The scaling of the target size to get the search area
	params.min_image_sample_size = 200^2;   % Minimum area of image samples
	params.max_image_sample_size = 250^2;   % Maximum area of image samples

	% Detection parameters
	params.refinement_iterations = 1;       % Number of iterations used to refine the resulting position in a frame
	params.newton_iterations = 5;           % The number of Newton iterations used for optimizing the detection rere
	params.clamp_position = false;          % Clamp the target position to be inside the image

	% Learning parameters
	params.output_sigma_factor = 1/12;			% Label function sigma
	params.learning_rate = 0.012;	 	 				% Learning rate
	params.nSamples = 100;                  % Maximum number of stored training samples
	params.sample_replace_strategy = 'lowest_prior';    % Which sample to replace when the memory is full
	params.lt_size = 0;                     % The size of the long-term memory (where all samples have equal weight)
	params.train_gap = 5;                   % The number of intermediate frames with no training (0 corresponds to training every frame)
	params.skip_after_frame = 1;            % After which frame number the sparse update scheme should start (1 is directly)
	params.use_detection_sample = true;     % Use the sample that was extracted at the detection stage also for learning

	% Factorized convolution parameters
	params.use_projection_matrix = true;    % Use projection matrix, i.e. use the factorized convolution formulation
	params.update_projection_matrix = true; % Whether the projection matrix should be optimized or not
	params.proj_init_method = 'pca';        % Method for initializing the projection matrix
	params.projection_reg = 2e-7;	 	 				% Regularization paremeter of the projection matrix

	% Generative sample space model parameters
	params.use_sample_merge = true;                 % Use the generative sample space model to merge samples
	params.sample_update_criteria = 'Merge';        % Strategy for updating the samples
	params.weight_update_criteria = 'WeightedAdd';  % Strategy for updating the distance matrix
	params.neglect_higher_frequency = false;        % Neglect hiigher frequency components in the distance comparison for speed

	% Conjugate Gradient parameters
	params.CG_iter = 5;                     % The number of Conjugate Gradient iterations in each update after the first frame
	params.init_CG_iter = 10*20;            % The total number of Conjugate Gradient iterations used in the first frame
	params.init_GN_iter = 10;               % The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated)
	params.CG_use_FR = false;               % Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient
	params.CG_standard_alpha = true;        % Use the standard formula for computing the step length in Conjugate Gradient
	params.CG_forgetting_rate = 75;	 	 	% Forgetting rate of the last conjugate direction
	params.precond_data_param = 0.7;	 	% Weight of the data term in the preconditioner
	params.precond_reg_param = 0.1;	 	% Weight of the regularization term in the preconditioner
	params.precond_proj_param = 30;	 	 	% Weight of the projection matrix part in the preconditioner

	% Regularization window parameters
	params.use_reg_window = true;           % Use spatial regularization or not
	params.reg_window_min = 1e-4;			% The minimum value of the regularization window
	params.reg_window_edge = 10e-3;         % The impact of the spatial regularization
	params.reg_window_power = 2;            % The degree of the polynomial to use (e.g. 2 is a quadratic window)
	params.reg_sparsity_threshold = 0.12;   % A relative threshold of which DFT coefficients that should be set to zero

	% Interpolation parameters
	params.interpolation_method = 'bicubic';    % The kind of interpolation kernel
	params.interpolation_bicubic_a = -0.75;     % The parameter for the bicubic interpolation kernel
	params.interpolation_centering = true;      % Center the kernel at the feature sample
	params.interpolation_windowing = false;     % Do additional windowing on the Fourier coefficients of the kernel

	% Scale parameters for the translation model
	% Only used if: params.use_scale_filter = false
	params.use_scale_filter = false
	params.number_of_scales = 10;           % Number of scales to run the detector
	params.scale_step = 1.03;               % The scale factor

	params.weights = [1, 2];               	% The weights factor
	params.weights_type    = 'sigmoid'; 		% type: constant, sigmoid
	params.divide_denominator = 100;
	params.initial = 1;
	params.factor = 0;

	% Initialize
	params.init_sz = [region(4), region(3)];
	params.init_pos = [region(2), region(1)] + (params.init_sz - 1)/2;
end


function ori = project(ori,varargin)
% projects orientation to a fundamental region
%
% Syntax
%   ori = project(ori,f)
%
% Input
%  ori     - @orientation
%  ori_ref - reference @rotation
%  f       - @fibre
%
% Output
%  phi1, Phi, phi2 - Euler angles
%

if isa(varargin{1},'fibre') % project to fibre

  %f = varargin{1};

  %h = f.h; r = f.r;
  h = varargin{1}; r = varargin{2};
  rotSym = ori.CS.properGroup.rot;

  d = dot_outer(times(rotSym,h,1), times(inv(ori),r,0),'noSymmetry').';
  [~,idSym] = max(d,[],2);
  ori = times(ori, rotSym(idSym),0);

else

end


classdef SVMData < handle
    properties
        data
        conditions
        labels
        trials
        nTrials
        groups
        groupLabels
    end

    methods
        %%
        function obj = SVMData(raw)
        % SVMData(raw)
        %   Constructor for SVMData.
        %
        % @param rawDataClass raw
        % @return SVMData obj
        %
            if (exist('raw','var'))
                type = class(raw);
                switch (type)
                    case {'TimeSeriesData'}
                        obj.(['convert' type])(raw);
                    otherwise
                        fprintf(1,'\nUnrecognized data type.\n');
                end
            else
                fprintf(1,'\nObject created.  No data loaded.\n');
            end
        end

        %%
        function plot(obj, selectedData, color)
        % plot(selectedData, colorMap)
        %   Plots N rows of images depicting the data values with a
        %   colormap for ease of visual inspection.
        %
        %   Usage (Function):
        %       obj.plot({2, 3, 'first'; 3:4, 7:9, 'second'}, 'autumn');
        %       The first row will be condition 2, trial 3, label 'first',
        %       while the second row will be the mean of conditions 3 and
        %       4, trials 7 through 9, label 'second'.
        %
        %   Usage (Plot):
        %       Click and drag the mouse upon the plot to zoom in.  Click
        %       without dragging to zoom out one step from where you were.
        %
        % @param Nx2_cellarray<vector<int>> selectedData
        % @param string colorMap
        % @return void
        %
            figureHandle = figure;
            isDataSelected = (exist('selectedData','var'));
            if (isDataSelected)
                nRows = size(selectedData, 1);
                dataToPlot = zeros(nRows,size(obj.data,2));
                for i = 1:nRows
                    dataToPlot(i,:) = mean(obj.data(...
                        ismember(obj.conditions, selectedData{i,1}) ...
                        & ismember(obj.trials, selectedData{i,2}),:),1);
                end
            else
                nRows = length(obj.labels);
                dataToPlot = zeros(nRows,size(obj.data,2));
                for i = 1:nRows
                    dataToPlot(i,:) = mean(obj.data(...
                        ismember(obj.conditions, i) ...
                        & ismember(obj.trials, 1:obj.nTrials(i)),:),1);
                end
            end

            if (~exist('color','var')), color = 'bone'; end
            colormap(color);

            imagesc(dataToPlot);
            set(gca, 'YTick', 1:nRows);
            if (isDataSelected)
                set(gca, 'YTickLabel', selectedData(:,3));
            else
                set(gca,'YTickLabel', obj.labels);
            end

            startLine = line(0,0);
            endLine = line(0,0);
            xClick = [0, size(dataToPlot,2)];
            xLimits = xClick;
            clickHistory = [0, size(dataToPlot,2)];
            set(figureHandle,...
                'WindowButtonUpFcn', @stopDragCallback, ...
                'WindowButtonDownFcn', @startDragCallback);

            function startDragCallback(varargin)
                point = get(gca,'CurrentPoint');
                xValue = point(1);
                if (xValue > 0 || xValue < size(dataToPlot,2))
                    set(startLine, ...
                        'XData', [xValue xValue], ...
                        'YData', [0 (nRows + .5)]);
                    set(endLine, ...
                        'XData', [xValue xValue], ...
                        'YData', [0 (nRows + .5)]);
                    xClick = ones(1,2)*round(xValue);
                    set(figureHandle, 'WindowButtonMotionFcn', @draggingCallback);
                end
            end

            function stopDragCallback(varargin)
                set(figureHandle, 'WindowButtonMotionFcn', '');
                set(startLine, 'XData', 0, 'YData', 0);
                set(endLine, 'XData', 0, 'YData', 0);
                if (xClick(1) < xClick(2))
                    clickHistory = [clickHistory; xClick];
                elseif (xClick(1) > xClick(2))
                    xClick = fliplr(xClick);
                    clickHistory = [clickHistory; xClick];
                elseif (xClick(1) == xClick(2))
                    lastClick = size(clickHistory,1);
                    if (lastClick > 1)
                        clickHistory(lastClick,:) = [];
                        xClick = clickHistory(lastClick - 1,:);
                    elseif (lastClick == 1)
                        xClick = clickHistory(1,:);
                    end
                end
                xLimits = xClick;
                set(gca, 'XLim', xClick);

            end

            function draggingCallback(varargin)
                point = get(gca,'CurrentPoint');
                xValue = point(1);
                if (xValue > xLimits(1) && xValue <= xLimits(2))
                    set(endLine, ...
                        'XData', [xValue xValue]);
                    xClick(2) = round(xValue);
                end

            end
        end

        %%
        function convertTimeSeriesData(obj, raw)
        % convertTimeSeriesData(raw)
        %   Read a TimeSeriesData object and get the data into SVM format.
        %
        % @param TimeSeriesData raw
        % @return void
        %
                if (isempty(raw.analysis))
                    raw.loadTimeCourses();
                end
                nVoxels                     = length(raw.analysis);
                [nTimePoints nConds]        = size(raw.analysis(1).meanTcs);
                obj.labels                  = strtrim(raw.analysis(1).labels)';
                obj.nTrials                 = zeros(1,nConds);

                for i = 1:nConds
                    obj.nTrials(i) = length(raw.analysis(1).allTcs(1,~isnan(raw.analysis(1).allTcs(1,:,i)),i));
                end

                temp = zeros([size(raw.analysis(1).allTcs) nVoxels]);
                for i = 1:nVoxels
                    temp(:,:,:,i) = raw.analysis(i).allTcs;
                end
                temp = permute(temp, [2 1 3 4]);

                totalTrials              = sum(obj.nTrials);
                obj.data                 = zeros(totalTrials,nVoxels*nTimePoints);
                obj.conditions           = zeros(totalTrials, 1);
                obj.trials               = zeros(totalTrials, 1);
                obj.groups               = zeros(totalTrials, 1);

                for i = 1:nConds
                    startIndex    = sum(obj.nTrials(1 : (i - 1))) + 1;
                    endIndex      = startIndex + obj.nTrials(i) - 1;
                    obj.data(startIndex : endIndex, :) = ...
                        reshape(temp(1 : obj.nTrials(i), :, i, :), obj.nTrials(i), nVoxels * nTimePoints);
                    obj.conditions(startIndex : endIndex) = i;
                    obj.trials(startIndex : endIndex) = 1:obj.nTrials(i);
                end
        end

        %% I'm unhappy with the way labels and groups are handled...
        function group(obj, conditions, groupName)
        % group(conditions, groupName)
        %   Groups a set of conditions for SVM training.
        %
        % @param vector<int> conditions
        % @param string groupName
        % @return void
        %
            if (~exist('conditions','var'))
                conditions = obj.promptUser('Enter condition(s): ', {1:length(obj.labels)});
            end

            if (length(conditions) == 1)
                tellUser('Please select more than one condition when grouping.');
                return;
            end

            % Checks if we've already grouped these conditions
            if (sum(ismember(obj.conditions(find(obj.groups)),conditions)) ~= 0)
                tellUser(['One or more of the specified conditions have already '...
                    'been grouped.\nUngroup and rerun, or choose different conditions.']);
                return;
            end

            targetIndices = ismember(obj.conditions, conditions);

            obj.groups(targetIndices) = conditions(1);

            if (exist('groupName','var'))
                obj.groupLabels = [obj.groupLabels; {conditions(1), groupName}];
            end

        end

        %% Ditto from the groupSVM function
        function ungroup(obj)
        % ungroup()
        %   Run to remove groupings of training groups.
        %
        % @return void
        %
            obj.groups(:,1) = 0;
        end

        %%
        function clonedObject = clone(obj)
        % clonedObject = clone()
        %   Generate a deep copy of the object.
        %
        % @return SVMData clonedObject
        %
            clonedObject = SVMData();
            classInfo = metaclass(obj);
            nProperties = length(classInfo.Properties);
            for i = 1:nProperties
                if (~classInfo.Properties{i}.Constant)
                    name = classInfo.Properties{i}.Name;
                    clonedObject.(name) = obj.(name);
                end
            end
        end
    end

    methods (Static)
        %%
        function userResponse = promptUser(userMessage, acceptableInput)
        % userResponse = promptUser(userMessage, acceptableInput)
        %   Prompt user with message and limit acceptable responses.
        %
        %   Usage:
        %       resp = promptUser('Give me 1, 2, or 3: ', [1 2 3]);
        %       resp = promptUser('What is your name? ', 'string');
        %       resp = promptUser('How about a vector?', {1:8});
        %
        % @param string userMessage
        % @param string|vector<int>|cellarray acceptableInput
        % @return string|int|vector<int> userResponse
        %
            while (true)
                try
                    userResponse = input(userMessage);
                catch %#ok<*CTCH>
                    tellUser('Erroneous input: Could not process input.');
                    continue;
                end

                if (isa(acceptableInput, 'char'))
                    if (isa(userResponse, 'char'))
                        break;
                    else
                        tellUser('Erroneous input: Please enter a string.');
                    end
                elseif (isa(acceptableInput,'cell'))
                    if (~isa(userResponse, 'char')) && ...
                            (length(intersect(acceptableInput{1}, userResponse)) ...
                            == length(userResponse))
                        break;
                    else
                        tellUser(['Erroneous input: One or more of the ' ...
                            'integers entered was not valid.']);
                    end
                else
                    if (~isa(userResponse, 'char') && ...
                            (~sum(acceptableInput==userResponse)==0))
                        break;
                    else
                        tellUser('Erroneous input: Please enter a valid integer.');
                    end
                end
            end
        end
    end
end

%%
function tellUser(message)
% tellUser(message)
%   Shorthand to print a message to the user with some convenient
%   line breaks.
%
% @param string message
% @return void
%
    fprintf(1,['\n' message '\n']);
end


function [AGC_atten_dB] = extract_AGC( file_in, Nlines )
%
% -------------------------------------------------------------------------
% This program reads the RADARSAT aux data and calculates the AGC settings
% -------------------------------------------------------------------------
%  file_in      : input file name including it's path
%  Nlines       : number of azimuth lines
%  AGC_atten_dB : Receiver attenuation in dB for each range line
% -------------------------------------------------------------------------
% Created  : May 05, 2004 by Kaan Ersahin & Millie Sikdar
% Modified : Nov 22, 2004 by Kaan Ersahin
% -------------------------------------------------------------------------

% The parameters encoded in the auxilary data bits are defined in RSI-D6
% also known as RSCSA-IC0009 (X-band ICD)
% -------------------------------------------------------------------------
% PARAMETER NAME                          LOCATION         LENGTH   ID
% -------------------------------------------------------------------------
% aux_sync_marker         = aux_bits (:,   1:  32);     % 32 bit -  1
% image_ref_id            = aux_bits (:,  33:  64);     % 32 bit -  2
% payload_status          = aux_bits (:,  65:  80);     % 16 bit -  3
% replica_AGC             = aux_bits (:,  81:  86);     %  6 bit -  4
% CALN_atten_LPT_pow_set  = aux_bits (:,  89:  96);     %  8 bit -  6
% pulse_waveform_number   = aux_bits (:,  97: 100);     %  4 bit -  7
% temperature             = aux_bits (:, 113: 144);     % 32 bit -  9
% beam_sequence           = aux_bits (:, 145: 160);     % 16 bit - 10
% ephemeris               = aux_bits (:, 161: 176);     % 16 bit - 11
% number_of_beams         = aux_bits (:, 177: 178);     %  2 bit - 12
% ADC_rate                = aux_bits (:, 179: 180);     %  2 bit - 13
% pulse_count_1           = aux_bits (:, 185: 192);     %  8 bit - 15
% pulse_count_2           = aux_bits (:, 193: 200);     %  8 bit - 16
% PRF_beam                = aux_bits (:, 201: 213);     % 13 bit - 17
% beam_select             = aux_bits (:, 214: 215);     %  2 bit - 18
% Rx_window_start_time    = aux_bits (:, 217: 228);     % 12 bit - 20
% Rx_window_duration      = aux_bits (:, 233: 244);     % 12 bit - 22
% altitude                = aux_bits (:, 249: 344);     % 96 bit - 24
% time                    = aux_bits (:, 345: 392);     % 48 bit - 25
% SC_T02_defaults         = aux_bits (:, 393: 393);     %  1 bit - 26
% first_replica           = aux_bits (:, 394: 394);     %  1 bit - 27
% Rx_AGC_setting          = aux_bits (:, 395: 400);     %  6 bit - 28
% -------------------------------------------------------------------------
%                                    Total  => 50 bytes (400 bits)
% -------------------------------------------------------------------------

% -------------------------------------------------------------------------
% read the binary aux data file
% -------------------------------------------------------------------------
file_in
fid_aux  = fopen(file_in,'r');
aux_bytes = fread(fid_aux,[50, Nlines],'uint8');
aux_bytes = aux_bytes';
fclose(fid_aux);

aux_bits = char(zeros(Nlines,400));
% -------------------------------------------------------------------------
% convert 50 bytes to 400 bits in general (it is only done for 50th byte)
% -------------------------------------------------------------------------
for byte = 50:50 %1:50 %% in general
   aux_bits(:,8*(byte-1)+1:8*byte) = num2str(dec2bin(aux_bytes(:,byte),8));
end
% -------------------------------------------------------------------------
%  Convert last 6 bits from binary to decimal
% -------------------------------------------------------------------------
d_Rx_AGC = bin2dec( aux_bits (:, 395: 400) );

% -------------------------------------------------------------------------
% For values greater than 31, the binary representation defined in the
% documentation is different and there is the need to substract 24 from
% decimal values to get the AGC setting in dB
% -------------------------------------------------------------------------
AGC_atten_dB = d_Rx_AGC - ( 24 * (d_Rx_AGC > 31));


function [llcfeat, x, y, wid, hgt] = llc_feature(feature, img, c)
%
% Copyright Aditya Khosla http://mit.edu/khosla
%
% Please cite this paper if you use this code in your publication:
%   A. Khosla, J. Xiao, A. Torralba, A. Oliva
%   Memorability of Image Regions
%   Advances in Neural Information Processing Systems (NIPS) 2012
%

if(~exist('c', 'var'))
	c = conf();
end

[llcfeat, x, y, wid, hgt] = feval(['llc_' feature], img, c);


%% Copyright (C) 2014-2016, 2019, 2022-2023 Colin B. Macdonald
%% Copyright (C) 2016 Lagu
%% Copyright (C) 2016 Abhinav Tripathi
%% Copyright (C) 2017 NVS Abhilash
%% Copyright (C) 2020 Fernando Alvarruiz
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published
%% by the Free Software Foundation; either version 3 of the License,
%% or (at your option) any later version.
%%
%% This software is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty
%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
%% the GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public
%% License along with this software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @defun mat_replace (@var{A}, @var{subs}, @var{rhs})
%% Private helper routine for setting symbolic array entries.
%%
%% @end defun

function z = mat_replace(A, subs, b)

  if (length (subs) == 1 && islogical (subs{1}))
    %% A(logical) = B
    subs{1} = find (subs{1});
    if isempty (subs{1})
      z = A;
      return;
    end
  end
  %% Check when b is []
  if (isempty(b))
    switch length(subs)
      case 1
        if strcmp(subs{1}, ':')
          z = sym([]);
          return
        end
        if (isempty (subs{1}))
          z = A;
          return
        end
          if rows(A) == 1
            z = delete_col(A, subs{1});
            return
          elseif columns(A) == 1
            z = delete_row(A, subs{1});
            return
          else
            z = sym([]);
            for i=1:A.size(2)
              z = [z subsref(A, substruct ('()', {':', i})).'];
            end
            z = subsasgn (z, substruct ('()', {subs{1}}), []);
            return
          end
      case 2
        if (isempty (subs{1}) || isempty (subs{2}))
          z = A;
          return
        end
        if strcmp(subs{1}, ':')
          if strcmp(subs{2}, ':')
            z = sym(zeros(0,columns(A)));
            return
          else
            z = delete_col(A, subs{2});
            return
          end
        elseif strcmp(subs{2}, ':')
          z = delete_row(A, subs{1});
          return
        else
          error('A null assignment can only have one non-colon index.'); % Standard octave error
        end
      otherwise
        error('Unexpected subs input')
    end
  end

  if (length(subs) == 1 && strcmp(subs{1}, ':') && length(b) == 1)
    z = pycall_sympy__ ('return ones(_ins[0], _ins[1])*_ins[2],', uint64(A.size(1)), uint64(A.size(2)), sym(b));
    return

  elseif (length(subs) == 1)
    % can use a single index to grow a vector, so we carefully deal with
    % vector vs linear index to matrix (not required for access)
    [n,m] = size(A);
    if (n == 0 || n == 1)
      c = subs{1};  r = ones(size(c));
    elseif (m == 1)
      r = subs{1};  c = ones(size(r));
    else
      % linear indices into 2D array
      % Octave 8 does not raise error from ind2sub so we do it ourselves
      sz = size (A);
      i = subs{1};
      if (i > prod (sz))
        error ('%d is out of bound %d (dimensions are %dx%d)\n', i, prod (sz), sz)
      end
      [r, c] = ind2sub (size (A), i);
      % keep all the indices in a row vector
      r = reshape (r, 1, []);
      c = reshape (c, 1, []);
    end

  elseif (length(subs) == 2)
    r = subs{1};
    c = subs{2};
    [n,m] = size(A);

    if (isnumeric(r) && ((isvector(r) || isempty(r))))
      % no-op
    elseif (strcmp(r,':'))
      r = 1:n;
    elseif (islogical(r) && isvector(r) && (length(r) == n))
      I = r;
      r = 1:n;  r = r(I);
    else
      error('unknown 2d-indexing in rows')
    end

    if (isnumeric(c) && ((isvector(c) || isempty(c))))
      % no-op
    elseif (strcmp(c,':'))
      c = 1:m;
    elseif (islogical(c) && isvector(c) && (length(c) == m))
      J = c;
      c = 1:m;  c = c(J);
    else
      error('unknown 2d-indexing in columns')
    end

    [r,c] = ndgrid(r,c);
    if ~(isscalar (b) || (isvector (r) && isvector (b)) || is_same_shape (r, b))
      % vectors may have diff orientations but if we have matrices then
      % they must have the same shape (Octave/Matlab do this for double)
      error('A(I,J,...) = X: dimensions mismatch')
    end
    r = r(:);
    c = c(:);
  else
    error('unknown indexing')
  end

  z = mat_rclist_asgn(A, r, c, b);

end

function z = delete_col(A, subs)
  if isscalar (A)
    z = sym(zeros (1, 0));
  else
    cmd = { 'A, subs = _ins'
            'if isinstance(subs, Integer):'
            '    A.col_del(subs - 1)'
            '    return A,'
            'for i in sorted(subs, reverse=True):'
            '    A.col_del(i - 1)'
            'return A,' };
    z = pycall_sympy__ (cmd, A, sym(subs));
  end
end

function z = delete_row(A, subs)
  if isscalar (A)
    % no test coverage: not sure how to hit this
    z = sym(zeros (0, 1));
  else
    cmd = { 'A, subs = _ins'
            'if isinstance(subs, Integer):'
            '    A.row_del(subs - 1)'
            '    return A,'
            'for i in sorted(subs, reverse=True):'
            '    A.row_del(i - 1)'
            'return A,' };
    z = pycall_sympy__ (cmd, A, sym(subs));
  end
end


%SOLVER_INITIALIZE	TFOCS helper script
%	Performs the initializations common to all of the first-order solvers

% Process the options structure and string/value pairs. First, we replace the
% default values with any values specified by the user in the 'opts' structure.
% We ignore any fields in the 'opts' structure that do not match ours, so that
% users can re-use the opts structure for other purposes.

odef = struct( ...
    'maxIts',     Inf   ,...
    'maxCounts',  Inf   ,...
    'countOps',   false ,... % adjusted if maxCounts < Inf
    'saveHist',   true  ,...
    'adjoint',    false ,...
    'saddle',     false ,...
    'tol',        1e-8  ,...
    'errFcn',     {{}}  ,...
    'stopFcn',    {{}}  ,...
    'printEvery', 100   ,...
    'maxmin',     1     ,...
    'beta',       0.5   ,...
    'alpha',      0.9   ,... % See below for special CG stuff
    'L0',         1     ,... % See below
    'Lexact',     Inf   ,...
    'mu',         0     ,...
    'fid',        1     ,...
    'stopCrit',   1     ,... % the TFOCS paper used stopCrit = 2
    'alg',        'AT'  ,...
    'restart',    Inf   ,...
    'printStopCrit', false,...
    'cntr_reset',  -50   ,... % how often to explicitly recompute A*x and A*y (set to Inf if you want )
    'cg_restart', Inf   ,... % for CG only
    'cg_type',    'pr'  ,...  % for CG only
    'stopping_criteria_always_use_x',   false, ...
    'data_collection_always_use_x',     false, ...
    'output_always_use_x',              false,  ...
    'autoRestart',  'gra', ... % function or gradient
    'printRestart', true, ...
    'debug',      false ....
    );

% Calling the solver with a no arguments returns the default options structure
if narginn < 1 || ( narginn ==1 && isstruct( smoothF ) )
    opts = odef;
    % remove the "CG" options for now, since they are undocumented
    opts    = rmfield(opts,'cg_restart');
    opts    = rmfield(opts,'cg_type');
    % if any default options are passed in (e.g. by tfocs_SCD), add those now:
    if ( narginn ==1 && isstruct( smoothF ) )
        for f = fieldnames( smoothF )'
            opts.( f{1} )   = smoothF.( f{1} );
        end
    end

    out = [];
    x = opts;
    if nargoutt == 0,
        disp('====== TFOCS default options =======');
%         disp('Format is    fieldname: { [default]  ''Usage type.
%         Description''}');

        % add some helpful description
        desc = [];
        desc.alg    = 'Algorithm, e.g. GRA for gradient descent. Values: AT, GRA, LLM, N07, N83, TS';
        desc.maxIts = 'Basic. Maximum number of allowed iterations';
        desc.saveHist   = 'Basic. Record history of all iterations';
        desc.restart    = 'Basic. Restart parameter. Make negative for "no-regress" feature';
        desc.tol    = 'Basic. Tolerance for stopping criteria';
        desc.L0     = 'Basic. Initial estimate of Lipschitz constant';
        desc.Lexact = 'Basic. Known bound of Lipschitz constant';
        desc.printEvery = 'Basic. How often to print info to the terminal; set to 0 or Inf to suppress output';
        desc.maxmin = 'Basic. +1 for convex minimization, -1 for concave maximization';

        desc.errFcn = 'Medium. User-specified error function. See user guide';
        desc.beta   = 'Medium. Backtracking parameter, in (0,1). No line search if >= 1';
        desc.alpha  = 'Medium. Line search increase parameter, in (0,1)';
        desc.autoRestart= 'Medium. Set to ''gra'' or ''fun'' to choose behavior when restart<0';

        desc.maxCounts  = 'Advanced. Vector that fine-tunes various types of iteration limits; same form as countOps';
        desc.countOps   = 'Advanced. Record number of linear multiplies, etc.; form [fcn, grad, linear, nonsmth, proj]';
        desc.mu         = 'Advanced. Strong convexity parameter.';
        desc.fid        = 'Advanced. File id, e.g. via fopen. All output is sent to this file';
        desc.stopFcn    = 'Advanced. User-supplied stopping criteria. See user guide';
        desc.stopCrit   = 'Advanced. Controls which stopping criteria to use; 1,2, 3 or 4.';
        desc.printStopCrit = 'Advanced. Controls whether to display the value used in the stopping criteria';
        desc.printRestart  = 'Advanced. Whether to signal when a restart happens';
        desc.cntr_reset = 'Advanced. Controls how often to reset some numerical computations to avoid roundoff';
        desc.debug = 'Advanced.  Turns on more useful error messages';

        desc.stopping_criteria_always_use_x = 'Advanced. Forces usage of x, never y, in stopping crit.';
        desc.data_collection_always_use_x   = 'Advanced. Forces usage of x, nevery y, in recording errors.';
        desc.output_always_use_x            = 'Advanced. Forces output of x, never y. Default: uses whichever is better';

        desc.adjoint = 'Internal.';
        desc.saddle = 'Internal.  Used by TFOCS_SCD';

        disp( opts );
        disp('====== Description of TFOCS options =======');
        disp( desc );
    end
    return % from this script only; the calling function does not return
end

% [smoothF, affineF, projectorF, x0, opts ] = deal(varargin{:});
% Check for incorrect types
F_types = {'function_handle','cell','double','single'};
assert( ismember(class(smoothF),F_types),'smoothF is of wrong type' );
assert( ismember(class(affineF),F_types),'affineF is of wrong type' );
assert( ismember(class(projectorF),F_types),'projectorF 3 is of wrong type' );
if narginn >= 4
    x0_types = {'cell','double','single','tfocs_tuple'};
    assert( ismember(class(x0),x0_types),'x0 is of wrong type' );
end
if narginn >= 5 && ~isempty(opts)
    assert( ismember(class(opts),{'struct'}),'opts is of wrong type' );
end

% Some parameters defaults depend on whether the user supplies other
% options. These will be updated later
L0_default  = odef.L0;
odef.L0     = Inf;

alpha_default    = odef.alpha; % typically 0.9
alpha_default_CG = 1;
odef.alpha  = Inf;

% Process the options structure, merging it with the default options
%   (merge "opts" into "odef")
def_fields = fieldnames(odef)';              % default options
if narginn > 4 && ~isempty(opts),
    use_fields = zeros(size(def_fields));
    opt_fields = fieldnames(opts)';          % user-supplied options
    for k = opt_fields,
        k = k{1};
        ndx = find(strcmpi(def_fields,k));
        if ~isempty(ndx)
            if ~isempty(opts.(k)) && ~use_fields(ndx),
                odef.(def_fields{ndx}) = opts.(k);
            end
            use_fields(ndx) = use_fields(ndx) + 1;
        else
            % Warn if the field is not found in our options structure
            warnState = warning('query','backtrace');
            warning off backtrace
            warning('TFOCS:OptionsStructure',' Found extraneous field "%s" in options structure', k );
            warning(warnState);
        end
    end
    % Warn if fields appear twice due to capitalization; e.g., maxIts/maxits
    if any(use_fields>1),
        warnState = warning('query','backtrace');
        warning off backtrace
        warning('TFOCS:OptionsStructure',' Some fieldnames of the options structure are identical up to capitalization: unpredictable behavior');
        warning(warnState);
    end
end

% Remove unnecessary options
if ~strcmpi( odef.alg, 'cg' )
    odef = rmfield( odef, 'cg_restart' );
    odef = rmfield( odef, 'cg_type' );
    % update our list of fieldnames
    def_fields = fieldnames(odef)';
end

% If opts.alpha wasn't supplied, use a default value:
if isinf(odef.alpha)
    if strcmpi( odef.alg, 'cg' )
        odef.alpha = alpha_default_CG;
    else
        odef.alpha = alpha_default;
    end
end

% If opts.printEvery is Inf, set it to 0
if isinf(odef.printEvery)
    odef.printEvery = 0;
end

% The default value of L0 is set to Lexact, if it is supplied
if isinf(odef.L0),
    if isinf(odef.Lexact),
        if odef.beta >= 1,
            error( 'For a fixed step size, L0 or Lexact must be supplied.' );
        end
        odef.L0 = L0_default;
    else
        odef.L0 = odef.Lexact;
    end
end
% If maxCounts is set, set countOps to true
if any(odef.maxCounts<Inf),
    odef.countOps = true;
end
% If cntr_reset is not set (signfied by being negative), set to defaults
if odef.cntr_reset < 0
    odef.cntr_reset = round(abs(odef.cntr_reset));
    % and if we requested high precision, change the default
    if odef.tol < 1e-12
        odef.cntr_reset = 10;
    end
end

% Now move the options into the current workspace
for k = def_fields,
    assignin('caller',k{1},odef.(k{1}));
end
opts = odef;

%
% Smooth function, pass 1
%

if isempty( smoothF ),
	error( 'Must supply a smooth function specification.' );
elseif isa( smoothF, 'function_handle' ),
    smoothF = { smoothF };
elseif ~isa( smoothF, 'cell' ),
    error( 'smoothF must be a function handle, or a cell array of them.' );
end
n_smooth = numel(smoothF);
saddle_ndxs = 1 : n_smooth;
% Adding Feb 2011: a get_dual function (see below)

%
% Projector, pass 1
%

if isa( projectorF, 'function_handle' ),
    projectorF = { projectorF };
elseif ~isa( projectorF, 'cell' ) && ~isempty( projectorF ),
    error( 'projectorF must be a function handle, or a cell array of them.' );
end
n_proj = numel(projectorF);

%
% Linear functions and affine offsets
%

% If the affine operator is anything *but* a cell array, convert it to one.
maxmin = sign(maxmin);
if isempty( affineF )
    affineF = { @linop_identity };
elseif isnumeric( affineF ),
    if ndims(affineF) > 1,
        error( 'Multidimensional arrays are not permitted.' );
    end
    if numel(affineF) == 1,
        identity_linop = affineF == 1;
        affineF = { linop_scale( affineF ) };
    else
        identity_linop = false;
        affineF = { linop_matrix( affineF ) };
    end
elseif isa( affineF, 'function_handle' ),
    affineF = { affineF };
elseif ~isa( affineF, 'cell' ),
    error( 'Invalid affine operator specification.' );
end

% If adjoint mode is specified, temporarily transpose the affineF cell
% array so that the rows and columns match the number of smooth functions
% and projectors, respectively. Then verify size compatibility.
if adjoint, affineF = affineF'; end
[ m_aff, n_aff ] = size( affineF );
% if all( m_aff ~= n_smooth + [0,1] ) || n_proj && all( n_aff ~= n_proj + [0,1] ),
%     error( 'The affine operation matrix has incompatible dimensions.' );
% May 16, 2011: making error messages more informative
if all( m_aff ~= n_smooth + [0,1] )
    if fid
        fprintf(fid,'Detected error: inputs are of wrong size\n');
        fprintf(fid,'  Found %d smooth functions, so expect that many primal variables\n',...
            n_smooth );
        fprintf(fid,'  So the affine operator should have %d (or %d if there is an offset) entries\n',...
            n_smooth, n_smooth+1 );
        fprintf(fid,'  but instead found %d affine operators\n', m_aff );
        fprintf(fid,' Perhaps you need the transpose of the affine operator?\n');
    end
    error( 'The affine operation matrix has incompatible dimensions.' );
elseif n_proj && all( n_aff ~= n_proj + [0,1] ),
    if fid
        fprintf(fid,'Detected error: inputs are of wrong size\n');
        fprintf(fid,'  Found %d nonsmooth functions, so expect %d or %d sets of affine operators\n',...
            n_proj, n_proj, n_proj + 1 );
        fprintf(fid,'  but instead found %d affine operators\n', n_aff );
    end
    error( 'The affine operation matrix has incompatible dimensions.' );
elseif n_proj == 0,
    n_proj = max( 1, m_aff - 1 );
end
inp_dims = cell( 1, n_proj );
otp_dims = cell( 1, n_smooth );

% If an additional affine portion of the objective has been specified,
% create an additional smooth function to contain it.
if m_aff == n_smooth + 1,
    offset          = true; % note: saddle_ndxs is 1:n_smooth
    otp_dims{end+1} = [1,1];
    smoothF{end+1}  = smooth_linear( maxmin );
    n_smooth = n_smooth + 1;
    for k = 1 : n_proj,
        offX = affineF{end,k};
        if isempty(offX),
            affineF{end,k} = 0;
        elseif isa(offX,'function_handle'),
            if adjoint, pos = 'row'; else pos = 'column'; end
            error( 'The elements in the last %s must be constants.', pos );
        elseif isnumeric(offX) && numel(offX) == 1 && offX == 0,
            affineF{end,k} = 0;
        elseif nnz(offX),
            affineF{end,k} = linop_dot( affineF{end,k}, adjoint );
            % add a case if ~nnz(offX)... Jan 2012
        elseif ~nnz(offX)
            affineF{end,k} = 0;
        end
    end
else
    offset      = false;
end

% If an affine offset has been specified, integrate those offsets into
% each smooth function, then remove that portion of the array.
if n_aff == n_proj + 1,
    for k = 1 : n_smooth,
        offX = affineF{k,end};
        if isempty(offX),
            continue;
        elseif isa(offX,'function_handle'),
            if adjoint, pos = 'column'; else pos = 'row'; end
            error( 'The elements in the last %s must be constant matrices.', pos );
        elseif isnumeric(offX) && numel(offX) == 1 && offX == 0,
            continue;
        else
            otp_dims{k} = size(offX);
            if nnz(offX),
                smoothF{k} = @(x)smoothF{k}( x + offX );
            end
        end
    end
    n_aff = n_aff - 1;
    affineF(:,end) = [];
end

% -- Todo:
%   If opts.debug = true, then before calling linop_stack,
%   we should print a message showing the sizes of everything
%   (this is useful when the linear portion is entered as "1" or "[]"
%    and we have automatically determined the size ).

% Transpose back, if necessary; then check dimensions
if adjoint,
    affineF = affineF';
    [ linearF, otp_dims, inp_dims ] = linop_stack( affineF, otp_dims, inp_dims, debug );
    linearF = linop_adjoint( linearF );
else
    [ linearF, inp_dims, otp_dims ] = linop_stack( affineF, [], [], debug );
end
identity_linop = isequal( linearF, @linop_identity ); % doesn't always catch identities
square_linop = identity_linop || isequal( inp_dims, otp_dims );
adj_arr = [0,2,1];
if countOps,
    apply_linear = @(x,mode)solver_apply( 3, linearF, x, mode );
else
    apply_linear = linearF;
end

%
% Smooth function, pass 2: integrate scale, counting
%

smoothF = smooth_stack( smoothF );
if maxmin < 0,
    smoothF = tfunc_scale( smoothF, -1 );
end
if countOps,
    apply_smooth = @(x)solver_apply( 1:(1+(nargoutt>1)), smoothF, x );
else
    apply_smooth = smoothF;
end

%
% Projector, pass 2: supply default, stack it up, etc.
%

if isempty( projectorF ),
    n_proj = 0;
    projectorF = proj_Rn;
else
    projectorF = prox_stack( projectorF );
end
if countOps,
    apply_projector = @(varargin)solver_apply( 4:(4+(nargoutt>1)), projectorF, varargin{:} );
else
    apply_projector = projectorF;
end

%
% Initialize the op counts
%

if countOps,
    global tfocs_count___
    tfocs_count___ = [0,0,0,0,0];
    maxCounts = maxCounts(:)';
end

%
% Construct the common initial values
%

L = L0;
theta = Inf;
f_v_old = Inf;
x = []; A_x = []; f_x = Inf; C_x = Inf; g_x = []; g_Ax = [];
restart_iter = 0;
warning_lipschitz = 0;
backtrack_simple = true;
backtrack_tol = 1e-10;
backtrack_steps = 0;

%
% Try to determine the size of the input, and construct the initial point.
%

% Attempt 1: From x0 itself
zero_x0 = true;
if ~isempty( x0 ),
    if isa( x0, 'tfocs_tuple' )
        x0  = cell(x0);
    end
    if isa( x0, 'cell' ),
        n_x0 = numel( x0 );
        if n_x0 == 1,
            x0 = x0{1};
        else
            x0 = tfocs_tuple( x0 );
        end
    else
        n_x0 = 1;
    end
    if n_proj && n_proj ~= n_x0,
        error( 'Size conflict detected between the projector and x0.' );
    end
    zero_x0 = ~nnz(x0);
% Attempt 2: From the linear operator dimensions
elseif ~size_ambig( inp_dims ),
    x0 = tfocs_zeros( inp_dims );
elseif ~size_ambig( otp_dims ),
    A_x = tfocs_zeros( otp_dims );
    x0 = apply_linear( A_x, 2 );
end
if isempty( x0 ),
    error( 'Could not determine the dimensions of the problem. Please supply an explicit value for x0.' );
end
x = x0;
if isinf( C_x ),
    C_x = apply_projector( x );
    if isinf( C_x ),
        zero_x0 = false;
        [ C_x, x ] = apply_projector( x, 1 );
    end
end
if isempty( A_x ),
    if identity_linop || zero_x0 && square_linop,
        A_x = x;
    elseif ~zero_x0 || size_ambig( otp_dims ),  % Jan 2012: todo: give size_ambig the 'offset' information
        A_x = apply_linear( x, 1 ); % celldisp( size(A_x) )
    else
        A_x = tfocs_zeros( otp_dims );
    end
end

% New, Jan 2012
if debug
    if ~adjoint, str1 = 'primal'; str2 = 'dual';
    else, str1 = 'dual'; str2 = 'primal';
    end
    fprintf(fid,'------- DEBUG INFO -----------\n');
    offsetPossible  = offset && ~adjoint;
    fprintf(fid,'Size of %s variable, via method 1\n', str1);
    print_cell_size( size(x0), fid, offsetPossible);
    fprintf(fid,'Size of %s variable, via method 2\n', str1);
    print_cell_size( inp_dims, fid, offsetPossible);

    offsetPossible  = offset && adjoint;
    fprintf(fid,'Size of %s variable, via method 1\n', str2);
    print_cell_size( size(A_x), fid, offsetPossible);
    fprintf(fid,'Size of %s variable, via method 2\n', str2);
    print_cell_size( otp_dims, fid, offsetPossible);
    fprintf(fid,'------------------------------\n');
end
% Added Dec 2012, check for bad sizes that are not integers
if ~isequal( otp_dims, tfocs_round(otp_dims) )
    error('Output dimensions must be integer valued');
end
if ~isequal( inp_dims, tfocs_round(inp_dims) )
    error('Input dimensions must be integer valued');
end

% Final size check
[ isOK1, inp_dims ] = size_compat( size(x0), inp_dims );
[ isOK2, otp_dims ] = size_compat( size(A_x), otp_dims );
if ~isOK1 || ~isOK2,
    if debug
        if ~isOK1
            fprintf(fid,'Debug message: size of %s variables did not line up\n',str1);
        end
        if ~isOK2
            fprintf(fid,'Debug message: size of %s variables did not line up\n',str2);
        end
    end
    error( 'Could not determine the dimensions of the problem. Please supply an explicit value for x0.' );
end
[ f_x, g_Ax ] = apply_smooth( A_x );
if isinf( f_x ),
    error( 'The initial point lies outside of the domain of the smooth function.' );
end
% Adding Feb 2011:
if isa(g_Ax,'tfocs_tuple')
    get_dual = @(g_Ax) get( g_Ax, saddle_ndxs );
else
    get_dual = @(g_Ax) g_Ax;
end

% Theta advancement function
% if mu > 0 && Lexact > mu
if mu > 0 && ~isinf(Lexact) && Lexact > mu, % fixed Dec 2011
    if ~strcmp(alg,'N83')
        warnState = warning('query','backtrace');
        warning off backtrace
        warning('TFOCS:OptionsStructure',' Lexact and mu>0 specifications only give guaranteed convergence with N83 algorithm');
        if strcmp(alg,'AT')
            warning('TFOCS:OptionsStructure',' (With AT algorithm, known to give wrong solutions sometimes when mu>0)');
        end
        warning(warnState);
    end
    % Note that we have not yet derived theory to adapt this to
    %   a local Lipschitz constant but that it should be possible
    theta_scale = sqrt(mu / Lexact);
    theta_scale = ( 1 - theta_scale ) / ( 1 + theta_scale );
    advance_theta = @(theta_old,L,L_old) min(1,theta_old*theta_scale);
else
    advance_theta = @(theta_old,L,L_old) 2/(1+sqrt(1+4*(L/L_old)/theta_old.^2));
end

% Preallocate the arrays for the output structure
out.alg = alg;
out.algorithm = algorithm;
if ~isempty(errFcn) && ~iscell(errFcn),
   errFcn = { errFcn };
end
if ~isempty(stopFcn) && ~iscell(stopFcn),
   stopFcn = { stopFcn };
end
errs = zeros(1,length(errFcn));
if nargoutt == 1,
    saveHist = false;
end
if saveHist,
    [ out.f, out.normGrad, out.stepsize, out.theta ] = deal( zeros(0,1) );
    if countOps,
        out.counts = zeros(0,length(tfocs_count___));
    end
    if ~isempty(errFcn),
        out.err = zeros(0,length(errs));
    end
end
if saddle,
    out.dual = [];
end
n_iter = 0;
status = '';

% Initialize the iterate values
y    = x;    z    = x;
A_y  = A_x;  A_z  = A_x;
C_y  = Inf;  C_z  = C_x;
f_y  = f_x;  f_z  = f_x;
g_y  = g_x;  g_z  = g_x;
g_Ay = g_Ax; g_Az = g_Ax;
norm_x = sqrt( tfocs_normsq( x ) );

% for recomputing linear operators
cntr_Ay     = 0;
cntr_Ax     = 0;

% Special setup for constant step sizes
if beta >= 1,
    beta = 1;
	alpha = 1;
end

% Print the opening text
if fid && printEvery,
	fprintf(fid,'%s\n',algorithm);
	fprintf(fid,'Iter    Objective   |dx|/|x|    step');
    if countOps, fprintf( fid, '       F     G     A     N     P' ); end
    if ~isempty(errFcn)
        nBlanks = max( [0, length(errFcn)*9 - 9] );
        fprintf( fid, '      errors%s',repmat(' ',nBlanks,1) );
    end
    if printStopCrit, fprintf( fid, '    stopping criteria' ); end
    fprintf( fid, '\n' );
	fprintf(fid,'----+----------------------------------' );
    if countOps, fprintf( fid, '+-------------------------------' ); end
%     if ~isempty(errFcn), fprintf( fid, '+-------------------' ); end
    if ~isempty(errFcn)
        fprintf( fid, '+%s', repmat('-',1+length(errFcn)*9,1) );
    end

    if printStopCrit, fprintf( fid, '+%s', repmat('-',19,1) ); end

    fprintf(fid,'\n');
end

% Initialize some variables
just_restarted = false;

% TFOCS v1.3 by Stephen Becker, Emmanuel Candes, and Michael Grant.
% Copyright 2013 California Institute of Technology and CVX Research.
% See the file LICENSE for full license information.


classdef TestDrawDetectedMarkers
    %TestDrawDetectedMarkers

    methods (Static)
        function test_1
            [img, d] = get_image_markers();
            [corners, ids, rejected] = cv.detectMarkers(img, d.dict);
            out = cv.drawDetectedMarkers(img, corners, 'IDs',ids);
            if ~isempty(rejected)
                out = cv.drawDetectedMarkers(out, rejected, ...
                    'BorderColor',[255 255 0]);
            end
            validateattributes(out, {class(img)}, {'size',size(img)});
        end

        function test_error_argnum
            try
                cv.drawDetectedMarkers();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end

function [img, d] = get_image_markers()
    % 4 markers in a diamond
    d = struct();
    d.dict = '6x6_50';
    d.ids = randi([0 49], [1 4]);
    d.slen = 80;
    d.mlen = 50;
    img = cv.drawCharucoDiamond(d.dict, d.ids, d.slen, d.mlen);
    img = repmat(img, [1 1 3]);
end


classdef SetRPYSteeringModelActionOptimVar < AbstractOptimizationVariable
    %SetRPYSteeringModelActionOptimVar Summary of this class goes here
    %   Detailed explanation goes here

    properties
        varObj = RollPitchYawPolySteeringModel.getDefaultSteeringModel()

        lb(1,10) double
        ub(1,10) double

        varRollConst(1,1) logical = false;
        varRollLin(1,1) logical   = false;
        varRollAccel(1,1) logical = false;

        varPitchConst(1,1) logical = false;
        varPitchLin(1,1) logical   = false;
        varPitchAccel(1,1) logical = false;

        varYawConst(1,1) logical = false;
        varYawLin(1,1) logical   = false;
        varYawAccel(1,1) logical = false;

        varTimeOffset(1,1) logical = false;
    end

    methods
        function obj = SetRPYSteeringModelActionOptimVar(varObj)
            obj.varObj = varObj;
            obj.varObj.optVar = obj;

            obj.id = rand();
        end

        function x = getXsForVariable(obj)
            x = NaN(1,10);

            if(obj.varRollConst)
                x(1) = obj.varObj.rollModel.constTerm;
            end
            if(obj.varRollLin)
                x(2) = obj.varObj.rollModel.linearTerm;
            end
            if(obj.varRollAccel)
                x(3) = obj.varObj.rollModel.accelTerm;
            end

            if(obj.varPitchConst)
                x(4) = obj.varObj.pitchModel.constTerm;
            end
            if(obj.varPitchLin)
                x(5) = obj.varObj.pitchModel.linearTerm;
            end
            if(obj.varPitchAccel)
                x(6) = obj.varObj.pitchModel.accelTerm;
            end

            if(obj.varYawConst)
                x(7) = obj.varObj.yawModel.constTerm;
            end
            if(obj.varYawLin)
                x(8) = obj.varObj.yawModel.linearTerm;
            end
            if(obj.varYawAccel)
                x(9) = obj.varObj.yawModel.accelTerm;
            end

            if(obj.varTimeOffset)
                x(10) = obj.varObj.yawModel.tOffset; %this applies for all angle models
            end

            x(isnan(x)) = [];
        end

        function [lb, ub] = getBndsForVariable(obj)
            useTf = obj.getUseTfForVariable();

            lb = obj.lb(useTf);
            ub = obj.ub(useTf);
        end

        function [lb, ub] = getAllBndsForVariable(obj)
            lb = obj.lb;
            ub = obj.lb;
        end

        function setBndsForVariable(obj, lb, ub)
            if(length(lb) == 10 && length(ub) == 10)
                obj.lb = lb;
                obj.ub = ub;
            else
                useTf = obj.getUseTfForVariable();

                obj.lb(useTf) = lb;
                obj.ub(useTf) = ub;
            end
        end

        function useTf = getUseTfForVariable(obj)
            useTf = [obj.varRollConst obj.varRollLin obj.varRollAccel, ...
                     obj.varPitchConst obj.varPitchLin obj.varPitchAccel, ...
                     obj.varYawConst obj.varYawLin obj.varYawAccel, ...
                     obj.varTimeOffset];

            useTf = logical(useTf);
        end

        function setUseTfForVariable(obj, useTf)
            obj.varRollConst = useTf(1);
            obj.varRollLin = useTf(2);
            obj.varRollAccel = useTf(3);

            obj.varPitchConst = useTf(4);
            obj.varPitchLin = useTf(5);
            obj.varPitchAccel = useTf(6);

            obj.varYawConst = useTf(7);
            obj.varYawLin = useTf(8);
            obj.varYawAccel = useTf(9);

            obj.varTimeOffset = useTf(10);
        end

        function updateObjWithVarValue(obj, x)
            ind = 1;

            if(obj.varRollConst)
                obj.varObj.rollModel.constTerm = x(ind);
                ind = ind + 1;
            end
            if(obj.varRollLin)
                obj.varObj.rollModel.linearTerm = x(ind);
                ind = ind + 1;
            end
            if(obj.varRollAccel)
                obj.varObj.rollModel.accelTerm = x(ind);
                ind = ind + 1;
            end

            if(obj.varPitchConst)
                obj.varObj.pitchModel.constTerm = x(ind);
                ind = ind + 1;
            end
            if(obj.varPitchLin)
                obj.varObj.pitchModel.linearTerm = x(ind);
                ind = ind + 1;
            end
            if(obj.varPitchAccel)
                obj.varObj.pitchModel.accelTerm = x(ind);
                ind = ind + 1;
            end

            if(obj.varYawConst)
                obj.varObj.yawModel.constTerm = x(ind);
                ind = ind + 1;
            end
            if(obj.varYawLin)
                obj.varObj.yawModel.linearTerm = x(ind);
                ind = ind + 1;
            end
            if(obj.varYawAccel)
                obj.varObj.yawModel.accelTerm = x(ind);
                ind = ind + 1;
            end

            if(obj.varTimeOffset)
                obj.varObj.yawModel.tOffset = x(ind);
                obj.varObj.pitchModel.tOffset = x(ind);
                obj.varObj.rollModel.tOffset = x(ind);
                ind = ind + 1; %#ok<NASGU>
            end
        end

        function nameStrs = getStrNamesOfVars(obj, evtNum, varLocType)
           if(evtNum > 0)
                subStr = sprintf('Event %i',evtNum);
            else
                subStr = varLocType;
            end

            nameStrs = {sprintf('%s Roll Angle Constant', subStr), ...
                        sprintf('%s Roll Angle Rate', subStr), ...
                        sprintf('%s Roll Angle Acceleration', subStr), ...
                        sprintf('%s Pitch Constant', subStr), ...
                        sprintf('%s Pitch Rate', subStr), ...
                        sprintf('%s Pitch Acceleration', subStr), ...
                        sprintf('%s Yaw Slip Constant', subStr), ...
                        sprintf('%s Yaw Slip Rate', subStr), ...
                        sprintf('%s Yaw Slip Acceleration', subStr), ...
                        sprintf('%s Steering Time Offset', subStr)};

            nameStrs = nameStrs(obj.getUseTfForVariable());
        end

        function varsStoredInRad = getVarsStoredInRad(obj)
            varsStoredInRad = [true true true  true true true  true true true  false];
        end
    end
end


function mv = mv_plotsMenu(mv,hfig);
%
% mv = mv_plotsMenu(mv,hfig);
%
% Attach menus providing plotting options for
% the MultiVoxel UI.
%
% ras, 04/05
if ieNotDefined('hfig')
    hfig = gcf;
end

if ieNotDefined('mv')
    mv = get(hfig,'UserData');
end

mv.ui.plotMenu = uimenu('ForegroundColor', 'k', 'Label', 'Plot', ...
                        'Separator', 'on');

h(1) = uimenu(mv.ui.plotMenu,'Label','Whole Time Course For Each Voxel',...
        'Separator','off',...
        'Accelerator','J',...
        'CallBack','mv_selectPlotType(1); mv_plotWholeTc;');

h(2) = uimenu(mv.ui.plotMenu,'Label','Mean Amps: Voxel by Condition',...
        'Separator','off',...
        'Accelerator','M',...
        'CallBack','mv_selectPlotType(2); mv_plotAmps([],[2 3]);');

h(3) = uimenu(mv.ui.plotMenu,'Label','Mean Amps Subplots',...
        'Separator','off',...
        'Accelerator','B',...
        'CallBack','mv_selectPlotType(3); mv_ampsSubplots;');

h(4) = uimenu(mv.ui.plotMenu, 'Label', 'Mean Amps Subplots (remove means)', ...
        'Separator', 'off', ...
		'Accelerator', 'V', ...
        'CallBack','mv_selectPlotType(4); mv_ampsSubplots([],[],[],1);');

h(5) = uimenu(mv.ui.plotMenu,'Label','Mean Amps: Trial by Voxel by Condition',...
        'Separator','off',...
        'CallBack','mv_selectPlotType(5); mv_plotAmps([],[1 2 3]);');

h(6) = uimenu(mv.ui.plotMenu,'Label','Histograms',...
        'Separator','on',...
        'Accelerator','H',...
        'CallBack','mv_selectPlotType(6); mv_histograms; ');

h(7) = uimenu(mv.ui.plotMenu,'Label','Cross-Correlation Matrix',...
        'Separator','off',...
        'Accelerator','R',...
        'CallBack','mv_selectPlotType(7); mv_corrcoef; ');

h(8) = uimenu(mv.ui.plotMenu,'Label','Cross-Correlation Matrix (remove means)',...
        'Separator','off',...
        'Accelerator','T',...
        'CallBack','mv_selectPlotType(8); mv_corrcoef([], 1); ');

h(9) = uimenu(mv.ui.plotMenu,'Label','Visualize GLMs',...
        'Separator','on',...
        'Accelerator','G',...
        'CallBack','mv_selectPlotType(9); mv_visualizeGlm; ');

mv.ui.plotHandles = h;

return