function [varargout] = ndgrid(varargin)

% NDGRID Generation of arrays for N-D functions and interpolation.
% [X1,X2,X3,...] = NDGRID(x1,x2,x3,...) transforms the domain
% specified by vectors x1,x2,x3, etc. into arrays X1,X2,X3, etc. that
% can be used for the evaluation of functions of N variables and N-D
% interpolation.  The i-th dimension of the output array Xi are copies
% of elements of the vector xi.
%
% [X1,X2,...] = NDGRID(x) is the same as [X1,X2,...] = NDGRID(x,x,...).
%
% For example, to evaluate the function  x2*exp(-x1^2-x2^2-x^3) over the
% range  -2 < x1 < 2,  -2 < x2 < 2, -2 < x3 < 2,
%
%     [x1,x2,x3] = ndgrid(-2:.2:2, -2:.25:2, -2:.16:2);
%     z = x2 .* exp(-x1.^2 - x2.^2 - x3.^2);
%     slice(x2,x1,x3,z,[-1.2 .8 2],2,[-2 -.2])
%
% NDGRID is like MESHGRID except that the order of the first two input
% arguments are switched (i.e., [X1,X2,X3] = NDGRID(x1,x2,x3) produces
% the same result as [X2,X1,X3] = MESHGRID(x2,x1,x3)).  Because of
% this, NDGRID is better suited to N-D problems that aren't spatially
% based, while MESHGRID is better suited to problems in cartesian
% space (2-D or 3-D).
%
% This is a drop-in replacement for the MATLAB version in elmat, which is
% relatively slow for big grids. Note that this function only works up
% to 5 dimensions
%
% See also MESHGRID, INTERPN.

% Copyright(C) 2010, Jan-Mathijs Schoffelen, DCCN
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

if nargin==0
  ft_error('MATLAB:ndgrid:NotEnoughInputs', 'Not enough input arguments.');
end
if nargin==1, varargin = repmat(varargin,[1 max(nargout,2)]); end

ndims = numel(varargin);
switch ndims
case 2
  ones1 = ones(1,numel(varargin{1}));
  ones2 = ones(1,numel(varargin{2}));

  x   = varargin{1}(:);
  y   = varargin{2}(:)';

  varargout{1} = x(:, ones2);
  varargout{2} = y(ones1, :);
case 3
  ones1 = ones(1,numel(varargin{1}));
  ones2 = ones(1,numel(varargin{2}));
  ones3 = ones(1,numel(varargin{3}));

  x   = varargin{1}(:);
  y   = varargin{2}(:)';
  z   = zeros(1,1,numel(varargin{3}));
  z(:) = varargin{3};

  varargout{1} = x(:, ones2, ones3);
  varargout{2} = y(ones1, :, ones3);
  varargout{3} = z(ones1, ones2, :);
case 4
  ones1 = ones(1,numel(varargin{1}));
  ones2 = ones(1,numel(varargin{2}));
  ones3 = ones(1,numel(varargin{3}));
  ones4 = ones(1,numel(varargin{4}));

  x   = varargin{1}(:);
  y   = varargin{2}(:)';
  z   = zeros(1,1,numel(varargin{3}));
  z(:) = varargin{3};
  xx   = zeros(1,1,1,numel(varargin{4}));
  xx(:) = varargin{4};

  varargout{1} = x(:, ones2, ones3, ones4);
  varargout{2} = y(ones1, :, ones3, ones4);
  varargout{3} = z(ones1, ones2, :, ones4);
  varargout{4} = xx(ones1, ones2, ones3, :);
case 5
  ones1 = ones(1,numel(varargin{1}));
  ones2 = ones(1,numel(varargin{2}));
  ones3 = ones(1,numel(varargin{3}));
  ones4 = ones(1,numel(varargin{4}));
  ones5 = ones(1,numel(varargin{5}));

  x   = varargin{1}(:);
  y   = varargin{2}(:)';
  z   = zeros(1,1,numel(varargin{3}));
  z(:) = varargin{3};
  xx   = zeros(1,1,1,numel(varargin{4}));
  xx(:) = varargin{4};
  yy   = zeros(1,1,1,1,numel(varargin{5}));
  yy(:) = varargin{5};

  varargout{1} = x(:, ones2, ones3, ones4, ones5);
  varargout{2} = y(ones1, :, ones3, ones4, ones5);
  varargout{3} = z(ones1, ones2, :, ones4, ones5);
  varargout{4} = xx(ones1, ones2, ones3, :,ones5);
  varargout{5} = yy(ones1, ones2, ones3, :,ones5);
otherwise
  ft_error('this version of ndgrid supports inputs up to 5 dimensions');
  %call the ndgrid from elmat
  %FIXME this has to be done
end


% Copyright (C) Daphne Koller, Stanford Univerity, 2012

function sample = SampleMultinomial(probabilities)

dice = rand(1,1);
accumulate = 0;
for i=1:length(probabilities)
    accumulate = accumulate + probabilities(i);
   if accumulate/sum(probabilities) > dice
       break
   end
end
sample = i;


function s = logsumexp(a, dim, method)
% Returns log(sum(exp(a),dim)) while avoiding numerical underflow.
% Default is dim = 1 (columns).
% logsumexp(a, 2) will sum across rows instead of columns.
% Unlike matlab's "sum", it will not switch the summing direction
% if you provide a row vector.
%
% Example: s = logsumexp(rand(10,3),2)

% Written by Tom Minka
% (c) Microsoft Corporation. All rights reserved.

if nargin < 2, dim = 2; end
if nargin < 3, method = 1; end

% subtract the largest in each column
y = max(a,[],dim);
if method==1
  dims = ones(1,ndims(a));
  dims(dim) = size(a,dim);
  a = a - repmat(y, dims);
else
  % Added by KPM. Just a hair faster (see timing comparison below).
  % A=rand(1000,100);N=100;
  % tic; for i=1:N, s1 = logsumexp(A,2,1); end; t1=toc;
  % tic; for i=1:N, s2=logsumexp(A,2,2); end; t2=toc;
  % assert(approxeq(s1,s2)); [t1 t2]
  a = bsxfun(@minus, a, y);
end

s = y + log(sum(exp(a),dim));
i = find(~isfinite(y));
if ~isempty(i)
  s(i) = y(i);
end


function [ mOutputImage ] = ApplyBoxFilter( mInputImage, boxRadius, borderType, borderValue, normalizeFlag )
% ----------------------------------------------------------------------------------------------- %
% [ mFilteredImage ] = ApplyBoxFilter( mInputImage, boxBlurKernelRadius )
%   Applies Box Filter using Integral Images.
% Input:
%   - mInputImage   -   Input Image.
%                       Structure: Image Matrix (Single Channel)
%                       Type: 'Single' / 'Double'.
%                       Range: [0, 1].
%   - boxRadius     -   Box Radius.
%                       The radius of the box neighborhood for the
%                       summation process.
%                       Structure: Scalar.
%                       Type: 'Single' / 'Double'.
%                       Range: {1, 2, ..., }.
% Output:
%   - mOutputImage  -   Output Image.
%                       Structure: Image Matrix (Single Channel)
%                       Type: 'Single' / 'Double'.
%                       Range: [0, 1].
% Remarks:
%   1.  References: "..."
%   2.  The running sum matches Intel IPP 'SumWindowRow' / 'SumWindowColumn'.
% TODO:
%   1.  s
%   Release Notes:
%   -   1.2.001     29/04/2016  Royi Avital
%       *   Fixed bug were the border pixels weren't calculated correctly.
%   -   1.2.000     29/04/2016  Royi Avital
%       *   Updated function input.
%   -   1.1.000     04/01/2016  Royi Avital
%       *   Using "Running Sum" instead of Integral Images / Summed Area
%           Table due to numeric issues.
%   -   1.0.000     14/03/2015  Royi Avital
%       *   First release version.
% ----------------------------------------------------------------------------------------------- %

FALSE   = 0;
TRUE    = 1;

OFF = 0;
ON  = 1;

BORDER_TYPE_CONSTANT    = 1;
BORDER_TYPE_CIRCULAR    = 2;
BORDER_TYPE_REPLICATE   = 3;
BORDER_TYPE_SYMMETRIC   = 4;

numRows = size(mInputImage, 1);
numCols = size(mInputImage, 2);

boxBlurKernelLength     = (2 * boxRadius) + 1;

mOutputImage    = zeros([(numRows + boxBlurKernelLength - 1), (numCols + boxBlurKernelLength - 1)]);
switch(borderType)
    case(BORDER_TYPE_CONSTANT)
        mInputImage     = padarray(mInputImage, [boxRadius, boxRadius], borderValue, 'both');
    case(BORDER_TYPE_CIRCULAR)
        mInputImage     = padarray(mInputImage, [boxRadius, boxRadius], 'circular', 'both');
    case(BORDER_TYPE_REPLICATE)
        mInputImage     = padarray(mInputImage, [boxRadius, boxRadius], 'replicate', 'both');
    case(BORDER_TYPE_SYMMETRIC)
        mInputImage     = padarray(mInputImage, [boxRadius, boxRadius], 'symmetric', 'both');
end

vRowsIdx = boxRadius + [1:numRows];
vColsIdx = boxRadius + [1:numCols];
removedIdx = boxRadius + 1;

vCurrSum = sum(mInputImage(1:boxBlurKernelLength, :), 1);
mOutputImage((boxRadius + 1), :) = vCurrSum;

for iRow = boxRadius + [2:numRows]
    vRowToAdd       = mInputImage((iRow + boxRadius) ,:);
    vRowToRemove    = mInputImage((iRow - removedIdx) ,:);
    vCurrSum        = vCurrSum + vRowToAdd - vRowToRemove;

    mOutputImage(iRow, :) = vCurrSum;
end

mInputImage = mOutputImage;

vCurrSum = sum(mInputImage(:, 1:boxBlurKernelLength), 2);
mOutputImage(:, (boxRadius + 1)) = vCurrSum;

for iCol = boxRadius + [2:numCols]
    vColToAdd       = mInputImage(:, (iCol + boxRadius));
    vColToRemove    = mInputImage(:, (iCol - removedIdx));
    vCurrSum        = vCurrSum + vColToAdd - vColToRemove;

    mOutputImage(:, iCol) = vCurrSum;
end

mOutputImage = mOutputImage(vRowsIdx, vColsIdx);

if(normalizeFlag == ON)
    mOutputImage = mOutputImage ./ (boxBlurKernelLength * boxBlurKernelLength);
end

end


function [err,time,solver,eqn,node,elem] = afemPoisson(mesh,pde,option,varargin)

%% Check input arguments
if isfield(mesh,'node') && isfield(mesh,'elem')
    node = mesh.node;
    elem = double(mesh.elem);
end
if ~exist('node','var') || ~exist('elem','var')
    % default mesh: Lshape
    [node,elem] = squaremesh([-1,1,-1,1],1);
    [node,elem] = delmesh(node,elem,'x>0 & y<0');
end
if isfield(mesh,'bdFlag')
    bdFlag = mesh.bdFlag;
else % default boundary condition
    bdFlag = setboundary(node,elem,'Dirichlet');
end
if ~exist('option','var'), option = []; end
if ~exist('pde','var')
    pde = Lshapedata;                          % default data
end

%% Parameters
option = afemoption(option,2);
maxIt = option.maxIt;
refType = option.refType;
elemType = option.elemType;
theta = option.theta;

%% Initialize err
errL2 = zeros(maxIt,1);   errH1 = zeros(maxIt,1); erreta = zeros(maxIt,1);
erruIuh = zeros(maxIt,1); errMax = zeros(maxIt,1);
errTime = zeros(maxIt,1); solverTime = zeros(maxIt,1);
assembleTime = zeros(maxIt,1); meshTime = zeros(maxIt,1);
estimateTime = zeros(maxIt,1);
itStep = zeros(maxIt,1);  stopErr = zeros(maxIt,1); flag = zeros(maxIt,1);
N = zeros(maxIt,1);

%% Generate an initial mesh
for k = 1:option.L0
    if strcmp(refType,'red')
        [node,elem,bdFlag] = uniformrefine(node,elem,bdFlag);
    elseif strcmp(refType,'bisect')
        [node,elem,bdFlag] = uniformbisect(node,elem,bdFlag);
    end
end

%%  Adaptive Finite Element Method
% *SOLVE* -> *ESTIMATE* -> *MARK* -> *REFINE*
for k = 1:maxIt
    % Step 1: SOLVE
    switch elemType
        case 'P1'     % piecewise linear function P1 element
            [soln,eqn,info] = Poisson(node,elem,bdFlag,pde,option);
        case 'CR'     % piecewise linear function CR element
            [soln,eqn,info] = PoissonCR(node,elem,bdFlag,pde,option);
        case 'P2'     % piecewise quadratic function
            [soln,eqn,info] = PoissonP2(node,elem,bdFlag,pde,option);
        case 'WG'     % weak Galerkin element
            [soln,eqn,info] = PoissonWG(node,elem,bdFlag,pde,option);
    end
    uh = soln.u;
    % compute error
    t = cputime;
    if isfield(pde,'Du')
        if ~isfield(pde,'d')
            pde.d = [];
        end
        if isfield(soln,'Du') && ~isempty(soln.Du) % Du is in the output
            errH1(k) = getH1error(node,elem,pde.Du,soln.Du,pde.d);
        else
            errH1(k) = getH1error(node,elem,pde.Du,soln.Du,pde.d);
        end
    end
    if isfield(pde,'exactu')
        errL2(k) = getL2error(node,elem,pde.exactu,uh);
        % interpolation
        switch elemType
            case 'P1'
                uI = Lagrangeinterpolate(pde.exactu,node,elem);
            case 'Q1'
                uI = Lagrangeinterpolate(pde.exactu,node,elem);
            case 'CR'
                uI = Lagrangeinterpolate(pde.exactu,node,elem,'CR',eqn.edge);
            case 'P2'
                uI = Lagrangeinterpolate(pde.exactu,node,elem,'P2',eqn.edge);
            case 'P3'
                uI = Lagrangeinterpolate(pde.exactu,node,elem,'P3',eqn.edge);
            case 'WG'
                uI = Lagrangeinterpolate(pde.exactu,node,elem,'WG',eqn.edge);
        end
        erruIuh(k) = sqrt((uh-uI)'*eqn.A*(uh-uI));
        errMax(k) = max(abs(uh-uI));
    end
    errTime(k) = cputime - t;
    % record time
    solverTime(k) = info.solverTime;
    assembleTime(k) = info.assembleTime;
    if option.printlevel>1
        fprintf('Time to compute the error %4.2g s \n H1 err %4.2g    L2err %4.2g \n',...
            errTime(k),errH1(k), errL2(k));
    end
    % record solver information
    itStep(k) = info.itStep;
    stopErr(k) = info.stopErr;
    flag(k) = info.flag;
    % plot
    N(k) = length(uh);
    if  strcmp(elemType,'WG') % modify size for WG
        if ~isfield(option,'reducesystem') || (option.reducesystem == 1)
            N(k) = N(k) - size(elem,1); % reduced system
        end
    end
    if option.plotflag % show mesh and solution
       figure(1);
       showresult(node,elem,uh,option.viewangle);
    end
    % Step 2: ESTIMATE
    t = cputime;
    switch option.estType
        case 'recovery' % recovery type
            eta = estimaterecovery(node,elem,uh);
        case 'residual' % residual type
            switch elemType
                case 'P1'
                    eta = estimateresidual(node,elem,uh,pde,bdFlag);
                case 'WG'
                    eta = estimateresidualWG(node,elem,uh,soln.Du,pde);
            end
    end
    erreta(k) = sqrt(sum(eta.^2));
    estimateTime(k) = cputime - t;
    % Step 3: MARK
    switch option.markType
        case 'L2'
            markedElem = mark(elem,eta,theta);
        case 'MAX'
            markedElem = mark(elem,eta,theta,'MAX');
    end
    % Step 4: REFINE
    t = cputime;
    if (N(k) > option.maxN) || (k == maxIt) % no refinement
        break;
    end
    [node,elem,bdFlag,HB,tree] = bisect(node,elem,markedElem,bdFlag); %#ok<ASGLU>
    % Step 4.2: COARSEN
    if option.coarsenflag
        eta = eleminterpolate(eta,tree);
        markedElem = mark(elem,eta,0.25*theta,'COARSEN');
        [node,elem,bdFlag] = coarsen(node,elem,markedElem,bdFlag);
    end
    meshTime(k) = cputime - t;
end

%% Plot convergence rates
if option.rateflag
    if ~isfield(option,'rateshift')
        option.rateshift = 10;
    end
    figure;
    set(gcf,'Units','normal');
    set(gcf,'Position',[0.25,0.25,0.55,0.4]);
    subplot(1,2,1)
    showrate2(N(1:k),errH1(1:k),option.rateshift,'-*','|| Du-Du_h||',...
              N(1:k),errL2(1:k),option.rateshift,'k-+','|| u-u_h||');
    subplot(1,2,2)
    showrate2(N(1:k),erruIuh(1:k),option.rateshift,'m-+','||Du_I-Du_h||',...
              N(1:k),errMax(1:k),option.rateshift,'r-*','||u_I-u_h||_{\infty}');
end

%% Output
err = struct('N',N(1:k),'H1',errH1(1:k),'L2',errL2(1:k),...
             'uIuhH1',erruIuh(1:k),'uIuhMax',errMax(1:k),'eta',erreta(1:k));
time = struct('N',N(1:k),'err',errTime(1:k),'solver',solverTime(1:k), ...
              'assemble',assembleTime(1:k),'mesh',meshTime(1:k),...
              'estimate',estimateTime(1:k));
solver = struct('N',N(1:k),'itStep',itStep(1:k),'time',solverTime(1:k),...
                'stopErr',stopErr(1:k),'flag',flag(1:k));

%% Display error and CPU time
if option.dispflag
    if ~isfield(option,'dispspace')
       option.dispspace = 5;    % display error for every 5 iterations
    end
    idx = 1:option.dispspace:k;

    fprintf('\n');
    disp('Table: Error')
    colname = {'#Dof','||u-u_h||','||Du-Du_h||','||DuI-Du_h||','||uI-u_h||_{max}','eta'};
    disptable(colname,err.N(idx),[],err.L2(idx),'%0.5e',err.H1(idx),'%0.5e',...
          err.uIuhH1(idx),'%0.5e',err.uIuhMax(idx),'%0.5e',err.eta(idx),'%0.5e');
%
%     disp('Table: CPU time')
%     colname = {'#Dof','Assemble','Solve','Error','Mesh'};
%     disptable(colname,time.N,[],time.assemble,'%0.2e',time.solver,'%0.2e',...
%                       time.err,'%0.2e',time.mesh,'%0.2e');
    fprintf('\n');
end


%     MOD1(x,y) is like MOD(x,y), except that it returns a value between 1
%     and y, instead of between 0 and y-1.

function v = mod1(x,y)

v = mod(x-1,y)+1;


function v = fibreVolume(odf,h,r,radius,varargin)
% ratio of orientations with a certain orientation
%
% Description
% returns the ratio of mass of the odf that is within a certain
% distance from a given fibre
%
% Syntax
%   v = fibreVolume(odf,h,r,radius)
%
% Input
%  odf    - @SO3Fun
%  h      - @Miller
%  r      - @vector3d
%  radius - double
%
% Options
%  resolution - resolution of discretization
%
% See also
% SO3Fun/volume SO3Fun/entropy SO3Fun/textureindex

% check input
argin_check(h,{'Miller','vector3d'});
if isa(h,'Miller'), h = odf.CS.ensureCS(h);end
argin_check(r,'vector3d');
argin_check(radius,'double');

% get resolution
res = get_option(varargin,'RESOLUTION',min(2.5*degree,radius/50),'double');

% discretisation
sR = odf.CS.fundamentalSector;
S2G = equispacedS2Grid(sR,'resolution',res,varargin{:});
lS2G = length(S2G);
S2G = S2G(angle(h,Miller(S2G,odf.CS))<radius);

% estimate volume portion of odf space
f = length(S2G)/lS2G;

% eval odf
if f==0
  v = 0;
else
  v = min(1,mean(odf.radon(S2G,r)) * f);
end


function [DX] = spm_diff_dx(varargin)
% optimisation of finite difference for numerical differentiation
% FORMAT [dx] = spm_diff_dx(f,x,...,n)
% FORMAT [dx] = spm_diff_dx(f,x,...,n,V)
% FORMAT [dx] = spm_diff_dx(f,x,...,n,'q')
%
% f      - [inline] function f(x{1},...)
% x      - input argument[s]
% n      - arguments to differentiate w.r.t.
%
% dx     - 'best' step size
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_diff_dx.m 7143 2017-07-29 18:50:38Z karl $

% Stability of numerical gradients
%==========================================================================
global GLOBAL_DX

% line search of step sizes
%--------------------------------------------------------------------------
dh    = 1;
dx    = -8:dh:0;
nd    = numel(dx);
for i = 1:nd
    GLOBAL_DX = exp(dx(i));
    dxdp{i}   = spm_diff(varargin{:});
end
np    = size(dxdp{1},2);
for i = 1:(nd - 1)
    for j = 1:np
        dgdh     = spm_vec(dxdp{i}{j}) - spm_vec(dxdp{i + 1}{j});
        ssd(i,j) = mean(abs(dgdh/dh).^2);
    end
end

% graphics
%--------------------------------------------------------------------------
dx    = dx(1:end - 1);
mss   = mean(log(ssd),2);
[~,j] = min(mss);
DX    = dx(j);

% graphics
%--------------------------------------------------------------------------
if nargout, return, end

str   = sprintf('Log stability: dx = exp(%.1f)',DX);

subplot(2,2,1), plot(dx,mss,dx,log(ssd),':')
title('Log stability','Fontsize',16), xlabel('log(dx)')
axis square, spm_axis tight

subplot(2,2,2), imagesc(1:np,dx,log(ssd))
title('Log stability','Fontsize',16), xlabel('Paramter mode')
axis square, ylabel('log(dx)')

subplot(2,2,3), plot(log(ssd(j,:)))
title(str,'Fontsize',16), xlabel('Paramter mode')
axis square, spm_axis tight

if iscell(varargin{end})
    V = varargin{end};
    subplot(2,2,4), imagesc(V{1})
    title('Paramter modes','Fontsize',16), xlabel('Paramter mode')
    axis square, ylabel('parameter')
end


function Q = updateQTable(state, a, reward, Q, next_state, alpha, gamma)

	% Update values in the Q-table

    Q(state, a) = Q(state,a) + alpha*(reward + gamma* max(Q(next_state,:)) - Q(state,a));
end


%-------------------------------------------------------------------------%
%   University of Illinois at Urbana Champaign
%   Department of Mechanical Science and Engineering
%   Laboratory of Photonics Research on Bio/Nano Environment
%   Written by : Tung Yuen Lau
%   Advisor: Prof. Kimani Toussaint
%   Start date: FEB 16 2012
%   Descriptiont: This is a simple function to detect edges in a 3D matrix
%   Format: image_pyramid(3D matrix of stacked images)
%-------------------------------------------------------------------------%
function final = canny3D(im, filsize, sigma, th_up, th_low)

im = double(im);

hfil = floor(filsize/2);
[w,h,d] = size(im);
[x y z] = meshgrid(-hfil:hfil,-hfil:hfil,-hfil:hfil);
fil_x = exp(-x.^2/(2*sigma^2))./(sigma*sqrt(2*pi)); clear x;
fil_y = exp(-y.^2/(2*sigma^2))./(sigma*sqrt(2*pi)); clear y;
fil_z = exp(-z.^2/(2*sigma^2))./(sigma*sqrt(2*pi)); clear z;
f = fil_x .* fil_y .* fil_z; clear fil_x; clear fil_y; clear fil_z;
f = f/sum(abs(f(:)));
imfil = imfilter(im,f,'replicate'); clear f;
[imfil_x , imfil_y, imfil_z] = gradient(imfil); clear imfil;

%%
%   Thinning (non-maximum suppression)
im_sub = nonmax_sup(imfil_x,imfil_y,imfil_z,th_up, th_low);
clear im_th; clear imfil_theta_z;

final = im_sub;


close all;
clear all;
clc;
rng('default');
% Create the directory for storing images
[status_code,message,message_id] = mkdir('bin');

% Signal space
N = 1000;
% Number of measurements
M = 200;
K = 50;

omp_success = 0;
gomp_success = 0;
for nt=1:100
    % Sensing matrix
    Phi = spx.dict.simple.gaussian_dict(M, N);
    % Construct the signal generator.
    gen  = spx.data.synthetic.SparseSignalGenerator(N, K);
    % Generate bi-uniform signals
    x = gen.gaussian;
    % Measurement vectors
    y = Phi.apply(x);

    % OMP solver instance
    solver = spx.pursuit.single.OrthogonalMatchingPursuit(Phi, K);
    % Solve the sparse recovery problem
    omp_result = solver.solve(y);
    % Solution vector
    z = omp_result.z;
    omp_stats = spx.commons.sparse.recovery_performance(Phi, K, y, x, z);
    %fprintf('OMP\n');
    %spx.commons.sparse.print_recovery_performance(omp_stats);

    % GOMP solver instance
    L = 2;
    options.ls_method = 'chol';
    z = spx.fast.gomp(double(Phi), y, K, L, 1e-6, options);
    gomp_stats = spx.commons.sparse.recovery_performance(Phi, K, y, x, z);
    %fprintf('GOMP\n');
    %spx.commons.sparse.print_recovery_performance(gomp_stats);

    fprintf('K=%d, Trial: %d, OMP: %s, GOMP: %s\n', ...
        K, nt, spx.io.true_false_short(omp_stats.success), ...
        spx.io.true_false_short(gomp_stats.success));
    omp_success = omp_success  + omp_stats.success;
    gomp_success = gomp_success  + gomp_stats.success;
end
fprintf('TOTAL: OMP : %d, GOMP: %d\n', omp_success, gomp_success);


function halton_test01 ( )

%*****************************************************************************80
%
%% HALTON_TEST01 tests HALTON, HALTON_STEP_SET.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 January 2009
%
%  Author:
%
%    John Burkardt
%
  dim_max = 3;
  test_num = 4;

  step_vec = [ 0, 5, 1000, 1000000 ];

  fprintf ( 1, '\n' );
  fprintf ( 1, 'HALTON_TEST01\n' );
  fprintf ( 1, '  HALTON returns the next element of a Halton sequence.\n' );
  fprintf ( 1, '  HALTON_STEP_SET sets the step.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  In this test, we try several values of STEP.\n' );
  fprintf ( 1, '  We repeat the test for several dimensions.\n' );
  fprintf ( 1, '  We assume defaults for SEED, LEAP and BASE.\n' );

  for dim_num = 1 : dim_max

    for test = 1 : test_num

      halton_dim_num_set ( dim_num );
      n = 11;
      step = step_vec(test);
      halton_step_set ( step );
      seed(1:dim_num) = 0;
      halton_seed_set ( seed );
      for i = 1 : dim_num
        base(i) = prime ( i );
      end

      fprintf ( 1, '\n' );
      fprintf ( 1, '  DIM_NUM = %12d\n', dim_num );
      fprintf ( 1, '  N =    %12d\n', n );
      fprintf ( 1, '  STEP = %12d\n', step );
      i4vec_transpose_print ( dim_num, seed, '  SEED = ' );
      i4vec_transpose_print ( dim_num, base, '  BASE = ' );

      fprintf ( 1, '\n' );
      fprintf ( 1, '          STEP   Halton\n' );
      fprintf ( 1, '\n' );

      for j = 1 : n
        r = halton ( );
        fprintf ( 1, '  %12d  ', step+j-1 );
        for i = 1 : dim_num
          fprintf ( 1, '%12f  ', r(i) );
        end
        fprintf ( 1, '\n' );
      end

    end

  end

  return
end


function thickness = SC_ThicknessEstimator(blk, page, sccalib, step_du, step_dv)
%% Estimate Water-Equivalent Thickness (2D)
% Reference: Improved scatter correction using adaptive scatter kernel superposition
% Input:
%               Blk(u,v): Total intensity, i.e., I_0
%               BlkAirNorm:
%               Prm(u,v): Primary intensity, i.e., I_p
%               AirNorm: Primary intensity airnorm chamber value
%               sccalib: Scatter Calibration Structure
% Output:
%               thickness(u,v): Estimated object thickness, i.e., tau(x,y) in Reference
% Date: 2021-05-05
% Author: Yi Du (yi.du@hotmail.com)

% mu H2O = 0.02 /mm
muH2O = str2double(sccalib.CalibrationResults.Globals.muH2O.Text);

% unit mm
tmp = blk./page;
tmp(tmp<0)=0.0001;
thickness = log(tmp) /muH2O;

% fill holes by interpolation
thickness(thickness<0) = NaN;

thickness = single(inpaint_nans(double(thickness), 2));

%% Smooth the estimated thickness
% thickness(vv, uu, ntheta)
thickness = SC_SmoothThickness(thickness, sccalib, step_du, step_dv);

end


% calculate the cross product of vec1 and vec2 (scalar means in z axis)
function outputVector = cross2(inputVector1,inputVector2)
        RotMatCross = [0,-1;1,0];
        switch size(inputVector1,1)+size(inputVector2,1)
            case 2
                outputVector = zeros(1,size(inputVector1,2));
            case 3
                if size(inputVector1,1)==2
                    inputVector1Cross = -RotMatCross*inputVector1;
                    outputVector = inputVector1Cross.*inputVector2;
                else
                    inputVector2Cross = -RotMatCross*inputVector2;
                    outputVector = -inputVector2Cross.*inputVector1;
                end
            case 4
                inputVector1Cross = RotMatCross*inputVector1;
                outputVector = diag(inputVector1Cross'*inputVector2)';
            otherwise
                error('Varargin Error: Input dimension should be either 1xN or 2xN.')
        end
end


function [state_red,inv_state_red,n_g_red] = krylov_reduction(g0,g1,n_v,n_g,n_arnoldi,varargin)
% Reduce the dimensionality of state space using Krylov subspace method
%
% by SeHyoun Ahn, Sept 2016
%
% REFERENCE: Ahn, SeHyoun, Greg Kaplan, Benjamin Moll, Thomas Winberry, and
%    Christian Wolf. "When Inequality Matters for Macro and Macro Matters
%    for Inequality."
%
% PARAMETERS:
%    g0 = LHS matrix, only used to check it satisfies require form
%    g1 = Dynamics matrix
%    n_v = number of jump variables
%    n_g = number of state variables to be reduced
%    n_Z = number of state variables not being reduced
%    n_arnoldi = dimension of Krylov subspace
%    varargin(1) = other observables
%    varargin(2) = updating parameter for B_gv
%    varargin(3) = number of variables to be NOT reduced; it is assumed
%                  that the last varargin(3) variables are not being
%                  reduced, so reorder as necessary
%
% OUTPUTS:
%    state_red = tranformation to get from full grid to reduced states
%    inv_state_red = inverse transform
%    n_g_red = number of state variables after reduction
%
% SYNTAX:
% [state_red,inv_state_red,n_g_red] = krylov_reduction(g0,g1,n_v,n_g,n_arnoldi,varargin)

if nargin == 8
    observable = varargin{1};
    F = varargin{2};
    n_Z = varargin{3};
elseif nargin == 7
    observable = varargin{1};
    F = varargin{2};
    n_Z = 0;
elseif nargin == 6
    observable = varargin{1};
    F = [];
    n_Z = 0;
else
    observable = [];
    F = [];
    n_Z = 0;
end
n_p = size(g1,1) - n_v - n_g;
n_total = n_v + n_g;
n_g = n_g - n_Z;

%% Check to make sure that g0 is an identity matrix
%     This reducetion step assumes that g0 has been cleaned, so if
%     this part fails, make sure to run <clean_g.m>
if (max(max(abs(g0(1:n_total,1:n_total)-speye(n_total))))~=0)
    error('Make sure that g0 is normalized.');
end

% Slice Dynamics Equation into Different Parts
B_pv = -g1(n_total+1:n_total+n_p,n_total+1:n_total+n_p)\g1(n_total+1:n_total+n_p,1:n_v);
B_pg = -g1(n_total+1:n_total+n_p,n_total+1:n_total+n_p)\g1(n_total+1:n_total+n_p,n_v+1:n_v+n_g);
B_pZ = -g1(n_total+1:n_total+n_p,n_total+1:n_total+n_p)\g1(n_total+1:n_total+n_p,n_v+n_g+1:n_v+n_g+n_Z);
B_gg = g1(n_v+1:n_v+n_g,n_v+1:n_v+n_g);
B_gv = g1(n_v+1:n_v+n_g,1:n_v);
B_gp = g1(n_v+1:n_v+n_g,n_total+1:n_total+n_p);
% B_vp = g1(1:n_v,n_v+n_g+1:n_v+n_g+n_p);

%% Drop redundant Directions in B_pg
% In theory, since we do deflated block arnoldi, this step
%    might be redundant. Will be tested later.
obs = [B_pg;observable];
[~,d0,V_g] = svd(full(obs),'econ');
aux = diag(d0);
aux = aux/aux(1);
n_Bpg = sum(aux>10*eps);
V_g = bsxfun(@times,V_g(:,1:n_Bpg),aux(1:n_Bpg)');

% Compute Krylov Subspace
if isa(F,'function_handle')
    A = @(x) F(B_gv'*x)+B_gg'*x + B_pg'*(B_gp'*x);
elseif F
    A = @(x) F'*(B_gv'*x)+B_gg'*x + B_pg'*(B_gp'*x);
else
    A = @(x) B_gg'*x + B_pg'*(B_gp'*x);
end
[V_g,~] = deflated_block_arnoldi(A,V_g,n_arnoldi);
n_g_red = size(V_g,2);

% Build State-Space Reduction transform
state_red = sparse(n_v+n_g_red,n_total+n_p);
state_red(1:n_v,1:n_v) = speye(n_v);
state_red(n_v+1:n_v+n_g_red,n_v+1:n_v+n_g) = V_g';
state_red(n_v+n_g_red+1:n_v+n_g_red+n_Z,n_v+n_g+1:n_v+n_g+n_Z) = speye(n_Z);
%state_red(:,n_total+1:n_total+n_p) = 0;

% Build inverse transform
inv_state_red = sparse(n_total+n_p,n_v+n_g_red);
inv_state_red(1:n_v,1:n_v) = speye(n_v);
inv_state_red(n_v+1:n_v+n_g,n_v+1:n_g_red+n_v) = V_g;
inv_state_red(n_total+1:n_total+n_p,1:n_v) = B_pv;
inv_state_red(n_total+1:n_total+n_p,n_v+1:n_v+n_g_red) = B_pg*V_g;
inv_state_red(n_total+1:n_total+n_p,n_v+n_g_red+1:n_v+n_g_red+n_Z) = B_pZ;
inv_state_red(n_v+n_g+1:n_total,n_v+n_g_red+1:n_v+n_g_red+n_Z) = speye(n_Z);

n_g_red = n_g_red + n_Z;


%% LSHAPEAFEMQUADCURL quad curl equations on the Lshaped domain
%
%   LSHAPEAFEMQUADCURL computes ND0-(CR-P0)-(linear ND) nonconforming approximations
%   of the quad curl equations in the unit cube. The mesh is refined
%   adaptively guided by a residual-based estimator using a separate marking
%   strategy with two marking parameters for eta_1 which estimates the error
%   for w and eta_2 for phi.
%
% Copyright (C)  Long Chen. See COPYRIGHT.txt for details.

close all; clear;

%% Set up
maxN = 6e5;
maxIt = 24;
theta = 0.3;
theta1 = 0.5;
nDofMaxwell = zeros(maxIt,1);
nDofStokes = zeros(maxIt,1);
h = zeros(maxIt,1);
erru = zeros(maxIt,1);
erruL2 = zeros(maxIt,1);
errw = zeros(maxIt,1);
errphiL2 = zeros(maxIt,1);
errphi = zeros(maxIt,1);
etaTotal = zeros(maxIt,1);
etaw = zeros(maxIt,1);
etaphi = zeros(maxIt,1);
etau = zeros(maxIt,1);

%% Generate initial mesh
load meshLshape3.mat % a minimal Lshape mesh
bdFlag = setboundary3(node,elem,'Dirichlet');
for i = 1
    [node,elem,bdFlag] = uniformrefine3(node,elem,bdFlag);
end
[elem,bdFlag,HB] = label3(node,elem,'all',bdFlag);

%% PDE and options
gamma = 3+1/6; alpha = 2/3;
% gamma = 8/3; alpha = 2/3;
% gamma = 5/2; alpha = 1/2;
% gamma = 7/3; alpha = 1/3; % extreme case
pde = quadCurlDataLshape1(gamma,alpha);
% pde = quadCurlDataLshape2(gamma,alpha);
% pde = quadCurlDataLshape(gamma,alpha);
option.printlevel = 0;

%% AFEM cycles using only 1st Maxwell+ Stokes, 2nd Maxwell solved only for ref
for k = 1:maxIt
    fprintf('\n\n\nRefinement level %d\n', k);
    NT = size(elem,1);

    %% SOLVE the 1st Maxwell problem

    pdeCurl1.J = pde.quadcurlu;
    pdeCurl1.g_D = @(p) zeros(size(p,1),3);
    option.solver = 'direct';
    if NT > 2e4; option.solver = 'diag'; end
    fprintf('\n**************Solving the first Maxwell problem for w**************');
    soln.w = Maxwellsaddle(node,elem,bdFlag,pdeCurl1,option,HB);
%     soln.w = Maxwellsaddle(node,elem,bdFlag,pdeCurl1,option);
    fprintf('*********************************************************************\n');
    %% SOLVE the Stokes problem

    % RHS of Stokes
    [curlwh, volume, curlbasis] = curlu3(node,elem,soln.w);
    pdeStokes.f = curlwh;
    pdeStokes.g_D = pde.curlu;
    option.solver = 'diag';
    option.printlevel = 1;
    fprintf('\n**************Solving the Stokes problem for phi*******************\n');
    solnStokes = Stokes3CRP0(node,elem,bdFlag,pdeStokes,option,HB);
    fprintf('*********************************************************************\n');
    %% SOLVE the 2nd Maxwell problem (not used in the indicator for mesh refinement)

    % RHS os the 2nd Maxwell
    [elem2face,face] = dof3face(elem);
    NF = size(face,1);
    soln.phi = reshape(solnStokes.u,NF,3);

    phihCenter = zeros(NT,3); % at each elem center
    for j = 1:3 % each component
        phihj = soln.phi(:,j);
        phihj2elem = phihj(elem2face);
        phihCenter(:,j) = sum(phihj2elem,2)/4;
        % Crouzeix-Raviart shape function 1-3\lambda = 1/4 at center
    end

    [elem2edge,edge] = dof3edge(sort(elem,2)); % sort for edge element
    NE = size(edge,1);
    bt = zeros(NT,6);
    for j = 1:6 % 6 basis of the edge element
        bt(:,j) = dot(curlbasis(:,:,j),phihCenter,2).*volume;
    end
    fCurl = zeros(2*NE,1);
    fCurl(1:NE,:) = accumarray(elem2edge(:),bt(:),[NE 1]);

    % solve the last Maxwell problem
    option.solver = 'direct';
    if NE > 2e4; option.solver = 'diag'; end
    pdeCurl2.J = fCurl;
    pdeCurl2.g_D = pde.exactu;
    pdeCurl2.g = pde.g;
    fprintf('\n*****Solving the second Maxwell problem for u (for reference)*****');
    soln.u = Maxwell1saddle(node,elem,bdFlag,pdeCurl2,option,HB);
    fprintf('*********************************************************************\n');
    %% ESTIMATE
    soln.curlw = curlwh;
    nDofMaxwell(k) = 2*NE;
    nDofStokes(k) = 3*NF;

    option.includeU = true; % only use the indicator by w_h and phi_h
    option.scaling = false; % no scaling and separate marking
    [etaK, est] = estimatequadcurl(node,elem,soln,pde,option);

    hK = est.hK;
%     h = sqrt(sum(hK.^2)/NT);
    Dlambda = gradbasis3(node,elem);
    curlphi = curlu3CR(elem2face,soln.phi,Dlambda);
    [errphi(k), errphiK] = getL2error3(node,elem,pde.curlcurlu,curlphi);
    [errphiL2(k), errKphiL2] = getL2error3(node,elem,pde.curlu,soln.phi);
    etaTotal(k) = sqrt(sum(etaK.^2));
    curluh = curlu3(node,elem,soln.u);
    [erru(k), errK] = getL2error3(node,elem,pde.curlu,curluh);
    erruL2(k) = getL2error3ND1(node,elem,pde.exactu,soln.u);
%     est.eta1 = est.eta1.*hK;
%     est.eta1 = est.eta1*min(hK);
    etaw(k) = sqrt(sum((est.eta1).^2));
    etaphi(k) = sqrt(sum((est.eta2).^2));
    etau(k) = sqrt(sum((est.eta3).^2));

    fprintf('Total eta          = %g \n', etaTotal(k));
%     fprintf('Mesh size          = %g \n', max(hK));
    fprintf('# face             = %g \n', NF);
    fprintf('# edge             = %g \n', NE);
    fprintf('||phi_h - curl u|| = %g \n', errphiL2(k));
    %% Visualize
    figure(1);
    subplot(1,3,1)
    etawE2V = accumarray(elem(:),repmat(est.eta1,[4,1]),[size(node,1), 1]);
    showsolution3(node,elem,etawE2V,'z<0.25 ','EdgeColor','k','facecolor','flat');
    colorbar;
    title('eta for w')
    view(120,45)

    subplot(1,3,2)

    % errphiL2E2V = accumarray(elem(:),repmat(errphiL2K,[4,1]),[size(node,1), 1]);
    % showsolution3(node,elem,errphiL2E2V,'z<0.25 ','EdgeColor','k','facecolor','flat');

    etaphiE2V = accumarray(elem(:),repmat(est.eta2,[4,1]),[size(node,1), 1]);
    showsolution3(node,elem,etaphiE2V,'z<0.25 ','EdgeColor','k','facecolor','flat');
    colorbar;
    title('eta for phi')
    view(120,45)

    subplot(1,3,3)
%     errU2v = accumarray(elem(:),repmat(erruK,[4,1]), [size(node,1), 1]);
%     showsolution3(node,elem,errU2v,'z<0.25','EdgeColor','k','facecolor','flat');
    % errL2U2v = accumarray(elem(:),repmat(abs(erruL2K),[4,1]),[size(node,1), 1]);
    % showsolution3(node,elem,errL2U2v,'z<0.25 ','EdgeColor','k','facecolor','flat');
    errphiE2V = accumarray(elem(:),repmat(errphiK,[4,1]),[size(node,1), 1]);
    showsolution3(node,elem,errphiE2V,'z<0.25 ','EdgeColor','k','facecolor','flat');
    title('H^1 error for phi')
    colorbar;
    view(120,45)

    set(gcf,'color','w','Position', [100 600 1400 300])
    drawnow;

    %% MARK and REFINE
    if nDofStokes(k) > maxN; break; end
%
%     markedElem = mark(elem,etaK,theta);
%     markedElemC = mark(elem,est.elemRescurlwh,2/3*theta);
%     markedElem = unique([markedElem; markedElemC]);

    % markedElem = mark(elem,errKphiL2,theta); % cheating
    markedElem = mark2(elem,est.eta1,theta1,est.eta2,theta);

    fprintf('eta1(marked)^2/eta1^2 = %g \n', sum(est.eta1(markedElem).^2)/sum(est.eta1.^2));
    fprintf('eta2(marked)^2/eta2^2 = %g \n', sum(est.eta2(markedElem).^2)/sum(est.eta2.^2));
    if k < maxIt
        [node,elem,bdFlag,HB] = bisect3(node,elem,markedElem,bdFlag,HB);
    end

end

%%
close all;
figure(1);
nDofMaxwell = nDofMaxwell(1:k);
nDofStokes = nDofStokes(1:k);
erru = erru(1:k);
errphiL2 = errphiL2(1:k);
etaTotal = etaTotal(1:k);
erruL2 = erruL2(1:k);
etaw = etaw(1:k);
etaphi = etaphi(1:k);
etau = etau(1:k);
errphi = errphi(1:k);
ITER_THRESH = ceil(k/2);
r1 = showrate(nDofMaxwell,erru,ITER_THRESH,'k-o');
r2 = showrate(nDofStokes,errphiL2,ITER_THRESH,'r-o');
% r3 = showrate(nDofMaxwell+nDofStokes,etaTotal,ITER_THRESH,'b-*');
r3 = showrate(nDofMaxwell,erruL2,ITER_THRESH,'b-*');
r4 = showrate(nDofMaxwell/2,etaw,ITER_THRESH,'color',[0.7,0.2,0.7],'marker','*');
r5 = showrate(nDofStokes,etaphi,ITER_THRESH,'color',[0.2,0.8,0.7],'marker','*');
r6 = showrate(nDofMaxwell,etau,ITER_THRESH,'color',[0.7,0.8,0.2],'marker','*');
r7 = showrate(nDofStokes,errphi,ITER_THRESH,'g-o');
set(gca,'xscale','log','yscale','log');
T = title('Convergence');
XL = xlabel('$\#$ DoFs');
YL = ylabel('Error Magnitudes');
L = legend('$\Vert  \nabla\times(u-u_h)\Vert$', ...
    ['$(\# \mbox{edge})^{' num2str(r1) '}$'],...
    '$\Vert  \nabla\times u - \phi_h\Vert$', ...
    ['$(\# \mbox{face})^{' num2str(r2) '}$'],...
        '$\Vert u - u_h\Vert$', ...
    ['$(\# \mbox{edge})^{' num2str(r3) '}$'],...
     '$\eta_1(w_h)$', ['$(\# \mbox{edge})^{' num2str(r4) '}$'],...
    '$\eta_2(w_h, \phi_h)$', ['$(\# \mbox{face})^{' num2str(r5) '}$'],...
    '$\eta_3(\phi_h, u_h)$', ['$(\# \mbox{edge})^{' num2str(r6) '}$'],...
    '$|\nabla\times u-\phi_h|_{1,h}$', ['$(\# \mbox{face})^{' num2str(r7) '}$'],...
'LOCATION','southwest');

%     '$\eta(w_h,\phi_h)$', ...
%     ['$(\# \mbox{DoF})^{' num2str(r3) '}$'],...

set([XL,YL,L],'Interpreter','latex','FontSize', 16);
set(T,'Interpreter','latex','FontSize',20);
set(gca,'TickLabelInterpreter', 'latex');
grid on;
% set(gcf,'color','w','Position', [100 200 300 600])
set(gcf,'color','w','Position',[613 598 820 820])
drawnow;

%% sanity check
if nDofMaxwell<1e4
    figure(2);
    subplot(1,2,1);
    option.scale = 2;
    option.plot = 'quiver3';
    center = (node(elem(:,1),:) + node(elem(:,2),:) + ...
        node(elem(:,3),:) + node(elem(:,4),:))/4;
    showvector3(center,pde.curlu(center),option);
    subplot(1,2,2);
    curluh = curlu3(node,elem,soln.u);
    showvector3(center,curluh,option);

    set(gcf,'color','w','Position', [500 600 750 300])
    drawnow;
end


function laguerre_polynomial_test ( )

%*****************************************************************************80
%
%% LAGUERRE_POLYNOMIAL_TEST tests the LAGUERRE_POLYNOMIAL library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 March 2012
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'LAGUERRE_POLYNOMIAL_TEST:\n' );
  fprintf ( 1, '  MATLAB version.\n' );
  fprintf ( 1, '  Test the LAGUERRE_POLYNOMIAL library.\n' );

  laguerre_polynomial_test01 ( );
  laguerre_polynomial_test02 ( );
  laguerre_polynomial_test03 ( );
  laguerre_polynomial_test04 ( );
  laguerre_polynomial_test05 ( );
  laguerre_polynomial_test06 ( );

  p = 5;
  b = 0.0;
  laguerre_polynomial_test07 ( p, b );

  p = 5;
  b = 1.0;
  laguerre_polynomial_test07 ( p, b );

  p = 5;
  e = 0;
  laguerre_polynomial_test08 ( p, e );

  p = 5;
  e = 1;
  laguerre_polynomial_test08 ( p, e );
%
%  Make some plots.
%
  a = 0.0;
  b = 5.0;
  index = [ 0, 1, 2, 3, 4, 5, 10 ];
  filename = 'l_polynomial.png';
  l_polynomial_plot ( a, b, index, filename );

  a = 0.0;
  b = 5.0;
  index = [ 0, 1, 2, 3, 4, 5, 10 ];
  index2 = [ 1, 1, 1, 1, 1, 1, 1 ];
  filename = 'lm1_polynomial.png';
  lm_polynomial_plot ( a, b, index, index2, filename );

  a = 0.0;
  b = 5.0;
  index = [ 0, 1, 2, 3, 4, 5, 10 ];
  index2 = [ 2, 2, 2, 2, 2, 2, 2 ];
  filename = 'lm2_polynomial.png';
  lm_polynomial_plot ( a, b, index, index2, filename );

  a = 0.0;
  b = 5.0;
  index =  [ 0,   1,   2,   3,   4,   5,   10 ];
  index2 = [ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ];
  filename = 'lf05_function.png';
  lf_function_plot ( a, b, index, index2, filename );

  close
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'LAGUERRE_POLYNOMIAL_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function [prob,sol,fmin] = bilp_prob(varargin)
%BILP_PROB  Return an OPTI BILP
%
%   prob = bilp_prob(no) return a pre-built optiprob of a saved BILP.
%
%   [prob,sol,fmin] = bilp_prob(no) returns the optimum solution and
%   function eval at the optimum
%
%   no = bilp_prob() returns the number of problems available for testing.

%   (C) 2011 Jonathan Currie (I2C2)

%Check if just returning no problems
if(nargin < 1)
    prob = 2; sol = []; fmin = [];
    return;
else
    no = varargin{1};
end

%Big switch yard
switch(no)
    case 1
        f = -[6 5]';
        A = [-3,5; 6,4; 3, -5; -6, -4];
        b = [6;9;1;3];
        xint = 'BB';
        prob = optiprob('f',f,'ineq',A,b,'int',xint);
        sol = [0;1];
        fmin = -5;

    case 2
        f = -[9 5 6 4]';
        A = [6 3 5 2; 0 0 1 1; -1 0 1 0; 0 -1 0 1];
        b = [9; 1; 0; 0];
        xint = 'BBBB';
        prob = optiprob('f',f,'ineq',A,b,'int',xint);
        sol = [1;1;0;0];
        fmin = -14;

    otherwise
        error('Problem not available or not implemented yet');
end


function [C, H, W, M] = FindLargestRectangles(I, crit, minSize)
% finds largest rectangle regions within all points set to 1.
% input: I       - B/W boolean matrix or output of FindLargestSquares
%        minSize - [height width] - minimum width and height on regions of
%                  interest (used to restrict final choise)
%        crit    - Optimazation Criteria parameters to optimize:
%                   crit(1)*height + crit(2)*width + crit(3)*height*width
% output:
%         C    - value of the optimization criteria "crit" calculated for
%                each pixel
%         W, H - for each pixel I(r,c) return height and width of the largest
%                all-white rectangle with its upper-left corner at I(r,c)
%         M    - Mask the largest all-white rectangle of the image

if (nargin<2)
  crit = [1 1 0];
end
if (nargin<3)
  minSize = [1 1];
end
p = crit;
[nR nC] = size(I);
if (minSize(1)<1), minSize(1)= floor(minSize(1)*nR); end
if (minSize(2)<1), minSize(2)= floor(minSize(2)*nC); end
if (max(I(:)) - min(I(:))==1),
  S = FindLargestSquares(I);
else
  S = I;
end
n = max(S(:));
W = S; % make a carbon copy of the matrix data
H = S;
C = ((p(1)+p(2)) + p(3)*S) .* S; % p(1)*width + p(2)*height + p(3)*height*width for height=width=S;
d = round((3*n)/4);
minH = max(min(minSize(1), d),1);
minW = max(min(minSize(2), d),1);

%% look for rectangles with width>height
hight2width = zeros(n+1,1);  % Store array with largest widths aviable for a given height
for r = 1 : nR               % each row is processed independently
  hight2width(:) = 0;        % reset the List
  for c = nC: -1 : 1         % go through all pixels in a row right to left
    s = S(r,c);              % s is a size of a square with its corner at (r,c)
    if (s>0)                 % if pixel I(r,c) is true
      MaxCrit = C(r,c);      % initialize the Max Criteria using square
      for hight = s:-1:1     % go through all possible width&hight combinations. Start with more likely to be the best
        width = hight2width(hight); % look up width for a given hight
        width = max(width+1,s);
        hight2width(hight) = width;
        Crit = p(1)*hight + p(2)*width + p(3)*width*hight;
        if (Crit>MaxCrit),   % check if it produces larger Criteria
          MaxCrit = Crit;    % if it does than save the results
          W(r,c)  = width;
          H(r,c)  = hight;
        end % if Crit
      end % for hight
      C(r,c)  = MaxCrit;
    end % if s
    hight2width((s+1):end) = 0;    % hights>s will not be aviable for the next pixel
  end % for c
end
clear hight2width

%% look for rectangles with width<height
width2hight = zeros(n+1,1);  % Store array with largest widths aviable for a given height
for c = 1 : nC               % each column is processed independently
  width2hight(:) = 0;        % reset the List
  for r = nR: -1 : 1         % go through all pixels in a column bottom to top
    s = S(r,c);              % s is a size of a square with its corner at (r,c)
    if (s>0)                 % if pixel I(r,c) is true
      MaxCrit = C(r,c);      % initialize the Max Criteria using square
      for width = s:-1:1     % go through all possible width&hight combinations. Start with more likely to be the best
        hight = width2hight(width); % look up hight for a given width
        hight = max(hight+1,s);
        width2hight(width) = hight;
        Crit = p(1)*hight + p(2)*width + p(3)*width*hight;
        if (Crit>MaxCrit),   % check if it produces larger Criteria
          MaxCrit = Crit;    % if it does than save the results
          W(r,c)  = width;
          H(r,c)  = hight;
        end % if Crit
      end % for width
      C(r,c)  = MaxCrit;
    end % if s
    width2hight((s+1):end) = 0;    % hights>s will not be aviable for the next pixel
  end % for r
end

%% Create container mask
CC = C;
CC( H<minH | W<minW ) = 0; % first try to obey size restrictions
[~, pos] = max(CC(:));
if (isempty(pos)), [~, pos] = max(C(:)); end % but when it fails than drop them
[r c] = ind2sub(size(C), pos);
M = false(size(C));
M( r:(r+H(r,c)-1), c:(c+W(r,c)-1) ) = 1;


function [theta_gibbs,sigma_gibbs,sigmatilde_gibbs,sig_gibbs]=panel5gibbs(y,Y,Xtilde,Xdot,N,n,T,d,theta0,Theta0,alpha0,delta0,It,Bu,pick,pickf)

% compute first  preliminary elements
% compute alphabar
alphabar=N*n*T+alpha0;
% compute the inverse Theta0
invTheta0=sparse(diag(1./diag(Theta0)));
% initiate the Gibbs sampler
% initiate the counting of iterations
count=1;
pickcount=1;
% initiate the record matrices
theta_gibbs=zeros(d,It-Bu);
sigmatilde_gibbs=zeros((N*n)^2,It-Bu);
sig_gibbs=zeros(1,It-Bu);
sigma_gibbs=zeros((N*n)^2,It-Bu);

% step 1: compute initial values
% initial value for theta (use OLS values)
theta=(Xtilde*Xtilde')\(Xtilde*y);
% initial value for sigmatilde (use residuals form OLS values)
eps=y-Xtilde'*theta;
eps=reshape(eps,T,N*n);
sigmatilde=eps'*eps;
% initiate value for the sigma, the scaling term for the errors
sig=1;
% initiate value for the matrix sigma, the residual variance-covariance matrix
sigma=sig*sigmatilde;
% initiate value for eyesigma
% compute the inverse of sigma
C=bear.trns(chol(bear.nspd(sigma),'Lower'));
invC=C\speye(N*n);
invsigma=invC*invC';
% then compute eyesigma
eyesigma=kron(speye(T),invsigma);
% finally, initiate eyetheta
eyetheta=kron(speye(T),theta);

hbar = bear.parfor_progressbar(It-Bu,'Progress of Panel BVAR Gibbs Sampler.');  %create the progress bar

% run the Gibbs sampler
while count<=It

% step 2: obtain sigmatilde
% compute Sbar
Sbar=(1/sig)*(Y-Xdot*eyetheta)*(Y-Xdot*eyetheta)';
sigmatilde=bear.iwdraw(Sbar,T);

% step 3: obtain sig
% compute the inverse of sigmatilde
C=bear.trns(chol(bear.nspd(sigmatilde),'Lower'));
invC=C\speye(N*n);
invsigmatilde=invC*invC';
% compute deltabar
deltabar=trace((Y-Xdot*eyetheta)*(Y-Xdot*eyetheta)'*invsigmatilde)+delta0;
% draw sig
sig=bear.igrandn(alphabar/2,deltabar/2);

% step 4: compute sigma and eyesigma
sigma=sig*sigmatilde;
C=bear.trns(chol(bear.nspd(sigma),'Lower'));
invC=C\speye(N*n);
invsigma=invC*invC';
eyesigma=kron(speye(T),invsigma);

% step 5: obtain theta
% compute Thetabar
invThetabar=full((Xtilde*eyesigma*Xtilde'+invTheta0));
C=bear.trns(chol(bear.nspd(invThetabar),'Lower'));
invC=C\speye(d);
Thetabar=invC*invC';
% compute thetabar
thetabar=Thetabar*(Xtilde*eyesigma*y+invTheta0*theta0);
% draw theta
theta=thetabar+chol(bear.nspd(Thetabar),'lower')*mvnrnd(zeros(d,1),eye(d))';

% step 6: obtain eyetheta
eyetheta=kron(speye(T),theta);

   % record phase
   % if the burn-in sample phase is not yet over
   if count<=Bu
   % simply add 1 to the iteration count
   count=count+1;
   % on the other hand, if the burn-in sample phase is over
   elseif count>Bu
   % adding one iteration to the count will depend on wether post-burn selection applies
      % if there is no post burn selection
      if pick==0
      % record the draw
      theta_gibbs(:,count-Bu)=theta;
      sigmatilde_gibbs(:,count-Bu)=bear.vec(sigmatilde);
      sig_gibbs(1,count-Bu)=sig;
      sigma_gibbs(:,count-Bu)=bear.vec(sigma);
      % and add one to the count
      count=count+1;
      % if there is post burn selection, only one draw over 'fpick' draws will be retained
      elseif pick==1
         % if the iteration does not correspond to fpick, don't record the results, don't increase the regular count, but do increase pickcount by 1
         if pickcount~=pickf
         pickcount=pickcount+1;
         % on the other hand, if the iteration does correspond to fpick
         elseif pickcount==pickf
         % do record the results
         theta_gibbs(:,count-Bu)=theta;
         sigmatilde_gibbs(:,count-Bu)=bear.vec(sigmatilde);
         sig_gibbs(1,count-Bu)=sig;
         sigma_gibbs(:,count-Bu)=bear.vec(sigma);
         % then increase the regular count by 1 and re-initialise pickcount
         count=count+1;
         pickcount=1;
         end
      end
   end

   hbar.iterate(1);   % update progress by one iteration

end

close(hbar);   %close progress bar


function cdf = stdnormal_cdf (x)
% For each component of x, compute the CDF of the standard normal
% distribution at x.

% Description: CDF of the standard normal distribution

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
% Copyright (C) 1995-2011 Kurt Hornik
% Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:       KH <Kurt.Hornik@wu-wien.ac.at>
%  Contributors:     ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   This program 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 program 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 program.  If not, see <http://www.gnu.org/licenses/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

if (nargin ~= 1)
    error('Requires one input arguments.');
end

if (numel(x) == 0)
    error ('stdnormal_cdf: X must not be empty');
end

cdf = erfc (x / (-sqrt(2))) / 2;


function Idenoised = nsf(I)
% noise supression function(NSF-Eq.(6)in the paper) is used to denoise the enhanced image.
warning off;
I = double(I);
h = fspecial('gaussian');
I = imfilter(I,h);
[m,n] = size(I);
[count,x] = hist(I(:),100);
[d,ind] = max(count);
t = 2;
x1 = x(1:ind+t);
count1 = count(1:ind+t);
coeffs = create_Fit(x1,count1);

for i = 1:m
    for j = 1:n
        [d,ind] = min(abs(I(i,j)-x));
        g(i,j) = shrinkage(I(i,j),ind,count,coeffs);
    end
end

Idenoised = I.* g;
end

function g = shrinkage(x,k,count,coeffs)
%             (1-w)*p(x|noise)
% g = 1 - -----------------------------
%          w*p(x|edge)+(1-w)*p(x|noise)

a1 = coeffs(1);
b1 = coeffs(2);
c1 = coeffs(3);

if x < b1
    g = 0.05;
else
    p1 = a1*exp(-((x-b1)^2/c1^2));

    p = count(k);
    g = abs(1 - (p1/p));
end
end


function [MPa] = ftH2O2MPa(ftH2O)
% Convert pressure from feet of water column at 4 degrees to megapascals
% Chad Greene 2012
MPa = ftH2O*0.00298907;


function net = glminit(net, prior)
%GLMINIT Initialise the weights in a generalized linear model.
%
%	Description
%
%	NET = GLMINIT(NET, PRIOR) takes a generalized linear model NET and
%	sets the weights and biases by sampling from a Gaussian distribution.
%	If PRIOR is a scalar, then all of the parameters (weights and biases)
%	are sampled from a single isotropic Gaussian with inverse variance
%	equal to PRIOR. If PRIOR is a data structure similar to that in
%	MLPPRIOR but for a single layer of weights, then the parameters are
%	sampled from multiple Gaussians according to their groupings (defined
%	by the INDEX field) with corresponding variances (defined by the
%	ALPHA field).
%
%	See also
%	GLM, GLMPAK, GLMUNPAK, MLPINIT, MLPPRIOR
%

%	Copyright (c) Ian T Nabney (1996-2001)

errstring = consist(net, 'glm');
if ~isempty(errstring);
  error(errstring);
end
if isstruct(prior)
  sig = 1./sqrt(prior.index*prior.alpha);
  w = sig'.*randn(1, net.nwts);
elseif size(prior) == [1 1]
  w = randn(1, net.nwts).*sqrt(1/prior);
else
  error('prior must be a scalar or a structure');
end

net = glmunpak(net, w);


function [id,dist] = find(S3G,ori,varargin)
% return indece and distance of all nodes within a eps neighborhood
%
% Syntax
%   % find the closes point
%   [ind,dist] = find(SO3G,ori)
%
%   % find points with a radius
%   [ind,dist] = find(SO3G,ori,radius)
%
%   % find cube corners
%   cubeInd = find(SO3G,ori,'cube')
%
% Input
%  SO3G   - @homochoricSO3Grid
%  ori    - @orientation
%  radius - double
%
% Output
%  ind  - index of the closes grid point
%  cubeInd - Nx8 list of indeces of the cube corners containing ori
%  dist - misorientation angle
%

% project oris to fundamental Region
ori = project2FundamentalRegion(ori, S3G.CS, S3G.SS);

% translate input (ori) into cubochoric coordinates
xyz = quat2cube(ori);

% N intervals of length hres along each edge of the cube
N = round(2 * pi / S3G.res);
hres = pi^(2/3) / N;

if nargin == 2 % closest point

    % calculate grid index along each axis of the cube
    % let the grid have N points along each axis
    % then xyz/hres takes values in [-N/2,N/2]
    % 0 is included in the grid iff N is odd
    % so xyz/hres+N/2-1/2 takes values in -1/2,...,N-1/2
    % after rounding this should yield values in 0,...,N-1
    sub  = mod(round(xyz/hres + N/2 - 0.5),N) + 1;    % [ix, iy, iz] each from 1 to N
    id = sub2ind(S3G,sub(:,1),sub(:,2),sub(:,3));

    if nargout == 2
        dist = zeros(size(id));     % initialize distances
        dist(id>0) = angle(ori.subSet(id>0), S3G.subSet(id(id>0)), 'noSymmetry');
    end

    % project those not beeing in fR again --> Quaternion Projected
    if any(id==0)

        % take outside grid points
        subxyz = hres * (sub(id==0,:) - (N+1)/2);

        % and project them back into the fundamental region
        q2 = project2FundamentalRegion(cube2quat(subxyz),S3G.CS,S3G.SS);

        % find closest grid point
        xyz2 = quat2cube(q2);
        sub2 = mod(round(xyz2/hres + N/2 - 0.5),N) + 1;

        % insert eventually new found neighbors on grid into id
        id2 = sub2ind(S3G,sub2(:,1),sub2(:,2),sub2(:,3));

        % get indice of zeros in id
        iszero = find(~id);

        % compute distances where id is zero and id2 isnt zero
        % (new found valid neighbors)
        if nargout == 2
            dist(iszero(id2>0)) = angle(ori.subSet(iszero(id2>0)), S3G.subSet(id2(id2>0)));
        end

        % plug in new found indice
        id(~id) = id2;

    end

    % if still not in fR, then search for best neighbor (of 8 surrounding)
    % notice that at least one of those 8 neighbors will lie in S3G
    if any(id==0)

        % get indice of surrounding vertices of the whole grid for those points
        % who dont have a valid nearest neighbor yet
        % for more info see docu of getS3Gvertices
        idx = getS3GVertices(S3G, xyz(id==0,:));

        % initialize set of nearest neighbors all as invalid
        S3Gvertices = rotation.nan(sum(id==0), 8);

        % and only overwrite this ones where idx > 0 (valid neighbor found)
        S3Gvertices(idx>0) = S3G.subSet(idx(idx>0));

        % calculate distances ...
        d = angle(repmat(ori(id==0), 1, 8), S3Gvertices, 'noSymmetry');

        % ... to find the nearest point
        [dmin, idmin] = min(d, [], 2);

        % overwrite the distance, if 2 outputs
        if nargout == 2
            dist(id==0) = dmin;
        end

        % overwrite new found indice
        % all indice now have a valid value ~= 0 (>= 1 of 8 neighbors in fR)
        id(id==0) = idx(sub2ind(size(idx), [1:sum(id==0)]', idmin));

    end

elseif ischar(varargin{1}) % cube c

    % get indice of surrounding vertices of the whole grid for those points
    % who dont have a valid nearest neighbor yet
    % for more info see docu of getS3Gvertices
    id = getS3GVertices(S3G, xyz);

    % calculate coordinate-wise distances to the floor corner
    % (attained by rounding coordinates down to the grid)
    % care that it mathers if the grid is odd or even since we then have to
    % round towards multiples of hres or the same shifted by hres/2
    dist = mod((N+1)/2*hres+xyz,hres);

else % neighborhood

end

end


function EB=EBCM(I_prop1)
[m,n]=size(I_prop1);
h_sob=fspecial('sobel');
I_prop1_norm=double(I_prop1./255);
I_filt_norm=imfilter(I_prop1_norm,h_sob,'replicate');
gij_xij=(I_prop1_norm).*(I_filt_norm);
h_avg=fspecial('average'); %%%default size is 3 by 3
I_filt_avg=imfilter(I_filt_norm,h_avg,'replicate');
gij_xij_avg=imfilter(gij_xij,h_avg,'replicate');
eij=(gij_xij_avg./(I_filt_avg+0.0001));
cij=abs(I_prop1_norm-eij)./abs(I_prop1_norm+eij+0.0001);
cij_u=sum(sum(uint8(round(cij*255))));
EB=cij_u/(m*n);
end


% Flush out the MATLAB.
close all;
clc;
clear all;

% Read the desired image file.
ImageData=imread('auto.pnm');

% Display the original image.
figure,imshow(ImageData);
title(' Original Image: ');

% Take the input of the sigma from user.
SigmaValue = input('Enter the Sigma = ');

% Gaussian Filter implementation.
OutputImage = imgaussfilt(ImageData,SigmaValue);

% Display the output image.
figure, imshow(OutputImage);
title(' Final Image: ');

% Add noise to oriiginal image.
ImageDataNoise = imnoise(ImageData,'Salt & Pepper', 0.04);

% Display the original image with noise.
figure,imshow(ImageDataNoise);
title(' Original Image with noise: ');

% Gaussian Filter implementation.
OutputImageWithNoise = imgaussfilt(ImageDataNoise,SigmaValue);

% Display the output image.
figure,imshow(OutputImageWithNoise);
title(' Final Image(with noise): ');


function nx= sizeXrec(i,P)
% returns the number of k-ToM's hidden sates
% function nx = sizeXrec(i,P)
% Marie Devaine wrote this in November 2015 (comments: JD).
% The formula follows from an analysis of the recursive sequence.
% IN:
%   - i: k-ToM's sophistication level
%   - P: total nb of evol/obs params
% OUT:
%   - nx: number of k-ToM's hidden sates

if i==0
    nx = 2;
else
    i_1 = i-1;
    if i_1>0
        power2 = exp(((i_1-1):-1:0).*log(2));
        S = 2^i + power2*((1:i_1)*(3*P+2)-1)';
    else
        S = 2;
    end
    nx = S+ i*(3*P+2)-1;
end
end


function title = p04_title ( )

%*****************************************************************************80
%
%% P04_TITLE returns the title of problem p04.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 August 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string TITLE, the title of the problem.
%
  title = 'f(x) = atan ( 40 * x - 15 )';

  return
end


function [ft2] = mi22ft2(mi2)
% Convert area from square miles to square feet.
% Chad A. Greene 2012
ft2 = mi2*27878400;


function [ w, success ] = quad_form( x, Q, v, w )

%QUAD_FORM quadratic form.
%   QUAD_FORM(x,Q) is real(x'*Q*x) = x'*((Q+Q')/2)*x.
%   QUAD_FORM(x,Q,v,w) is real(x'*(Q*x+v)+w).
%
%   x must be a row or column vector, and Q must either be a scalar or
%   a square matrix with the same number of rows as x. If supplied, v must
%   be a scalar or a vector of the same size as x, and w must be a scalar.
%   If x is a row vector, then x (and v) are Hermitian transpoed before
%   evaluation.
%
%   NOTE: The use of QUAD_FORM can often be replaced by a call to NORM. For
%   example, if Q is positive definite, then the constraint
%       quad_form(x,Q) <= 1
%   is equivalent to
%       norm(sqrtm(Q)*x) <= 1
%   Generally speaking, the NORM version will be more reliable and more
%   accurate, so we encourage you to make similar conversions whenever
%   possible. We *strongly* discourage the QP-era practice of converting
%   NORM expressions into quadratic forms.
%
%   Disciplined convex programming information:
%       QUAD_FORM(x,Q,v,w) is neither convex nor concave in x and (Q,v)
%       jointly, so at least one of the two must be constant.
%
%       If (Q,v) is constant, then QUAD_FORM is convex if Q is positive
%       semidefinite, and concave if Q is negative semidefinite. An error
%       is generated if Q is indefinite (unless x is also constant).
%       QUAD_FORM is nonmonotonic in x, so x must be affine.
%
%       If x is constant, then QUAD_FORM is affine in Q, v, and w. The
%       signs of x will govern whether the elements of Q, v, and w may
%       be convex, concave, or affine.

tol = 16 * eps;
tolLDL = 4 * eps;
if nargin < 4,
    w = 0;
    if nargin < 3,
        v = 0;
    end
end

sx = size( x );
if length( sx ) ~= 2 || all( sx ~= 1 ),
    cvx_throw( 'The first argument must be a vector.' );
end
nx = prod( sx );

sQ = size( Q );
if length( sQ ) ~= 2 || sQ( 1 ) ~= sQ( 2 ),
    cvx_throw( 'The second argument must be a scalar or a square matrix.' );
elseif sQ( 1 ) ~= 1 && sQ( 1 ) ~= nx,
    cvx_throw( 'The size of Q is incompatible with the size of x.' );
end

if nargin < 3,
    v = sparse( sx(1), sx(2) );
elseif ~isequal( size( v ), sx ),
    cvx_throw( 'The size of v is incompatible with the size of x.' );
end

if nargin < 4,
    w = 0;
elseif numel(w) ~= 1 || ~isreal(w),
    cvx_throw( 'The fourth argument must be a real scalar.' );
end

if sx(1) ~= nx,
    x = x';
    v = v';
end

success = true;
cvx_optval = [];
if cvx_isconstant( x ),
    x = cvx_constant( x );
    cvx_optval = real( x' * Q * x ) + sum( real( v' * x ) ) + w;
    return
elseif ~cvx_isconstant( Q ) || ~cvx_isconstant( v ),
    cvx_throw( 'Either x or (Q,v) must be constant.' );
elseif ~cvx_isaffine( x ),
    cvx_throw( 'First argument must be affine.' );
end

Q = cvx_constant( Q );
Q = 0.5 * ( Q + Q' );
v = cvx_constant( v );
dQ = diag( Q );

if nnz( Q ) == 0,
    cvx_optval = real( v' * x ) + w;
    return
end

if sQ( 1 ) == 1,
    x = x + 0.5 * ( v / Q );
    w = w - 0.25 * ( v' * v ) / Q;
    if ~isreal( x ), x = abs( x ); end
    w = real( Q ) * sum_square( x ) + w;
    return
end

while true,

    %
    % Remove zero rows and columns from Q. If a diagonal element of Q is
    % zero but there are elements on that row or column that are not,
    % then we know that neither Q nor -Q is PSD.
    %

    dQ = diag( Q );
    trQ = sum( dQ );
    if ~all( dQ ),
        nnzQ = nnz( Q );
        tt = dQ ~= 0;
        Q = Q( tt, tt );
        if nnz( Q ) ~= nnzQ,
            success = false;
            break
        end
        dQ = dQ( tt );
        w = w + real( v( ~tt, : )' * cvx_subsref( x, ~tt, ':' ) );
        v = v( tt, : );
        x = cvx_subsref( x, tt, ':' );
        sx = length( x );
    end

    %
    % Determine the sign of the elements of Q. If they are not all of
    % the same sign, then neither Q nor -Q is PSD. Note that trQ has
    % preserved the sign of our quadratic form, so setting Q=-Q here
    % in the concave case does not cause a problem.
    %

    dQ = dQ > 0;
    if ~all( dQ ),
        if any( dQ ),
            success = false;
        else
            Q = -Q;
        end
    end

    %
    % We've had to modify this portion of the code because MATLAB has
    % removed support for the CHOLINC function.
    %
    % First, try a Cholesky. If it successfully completes its
    % factorization without fail, we accept it without question. If
    % it terminates early, we perform a numerical test to see if the
    % result still approximates the square root to good precision.
    %
    % If Cholesky fails, then we assume the matrix is either rank
    % deficient or indefinite. For sparse matrices, we perform an LDL
    % factorization, and remove the contributions of any 2x2 blocks,
    % negative 1x1 blocks, and near-zero 1x1 blocks on the diagonal.
    % If there are no such blocks, we accept it without question; if
    % so, we perform the same numerical test. If the test fails, we
    % assume, for sparse matrices, at least, that the matrix is
    % indefinite.
    %
    % If the matrix is dense, our final test is an eigenvalue
    % decomposition, the most expensive but the most accurate.
    %

    spQ = nnz(Q) <= 0.1 * nx * nx;
    if spQ,
        Q = sparse( Q );
        [ R, p, prm ] = chol( Q, 'upper', 'vector' );
        if any( diff(prm) ~= 1 ),
            R( :, prm ) = R; %#ok
        end
    else
        Q = full( Q );
        [ R, p ] = chol( Q, 'upper' );
        if p > 1,
            R = [ R , R' \ Q(1:p-1,p:end) ]; %#ok
        end
    end
    valid = p == 0;
    if ~valid,
        tolQ = tol * norm( Q, 'fro' );
        if p > 1,
            valid = norm( Q - R' * R, 'fro' ) < tolQ;
        end
    end
    if ~valid && spQ,
        [ R, DD, prm ] = ldl( sparse( Q ), 'upper', 'vector' );
        if nnz( R ) > max( sx, 0.1 * sx * ( sx + 1 ) / 2 ), spQ = false; end
        tt = diag(DD,1) == 0;
        tt = [ tt ; true ] & [ true ; tt ] & ( diag(DD) > tolLDL * trQ );
        DD = diag(DD);
        R  = bsxfun( @times, sqrt( DD(tt,:) ), R(tt,:) );
        if any( diff(prm) ~= 1 ), R( :, prm ) = R; end
        valid = all( tt ) || norm( Q - R' * R, 'fro' ) < tolQ;
    end
    if ~valid && ~spQ,
        [ V, D ] = eig( full( Q ) );
        if nnz( V ) <= max( length(V), 0.1 * numel(V) ), V = sparse(V); end
        D = diag( D );
        if any( D(2:end) < D(1:end-1) ),
            [D,ndxs] = sort(D);
            V = V(:,ndxs);
        end
        valid = D(1) > -tol * D(end);
        if valid,
            nzero = nnz( cumsum(D) < tol * abs(trQ) );
            V = V(:,nzero+1:end);
            D = sqrt(D(nzero+1:end));
            R = diag(sparse(D)) * V';
        end
    end
    if ~valid,
        success = false;
        break;
    end

    %
    % Scale so that the mean eigenvalue of (1/alpha)*R'*R is one.
    % Hopefully this will minimize scaling issues.
    %

    alpha = trQ / size(R,1);
    w = w + alpha * sum_square_abs( ( R * x ) / sqrt(alpha) ) + real( v' * x );
    break;

end

if ~success && nargout == 1,
    cvx_throw( 'Disciplined convex programming error:\n    The second argument must be positive or negative semidefinite.' );
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [posterior,prior] = p2p(hh, shrinkage,prior0,olsreg,F,G,Fo,positions_nylags,position_constant)
%
%********************************************************
% Conjugate Prior: MN-IW for Direct Methods
%********************************************************

% settings
if isempty(position_constant) == 0
    nx = 1;
else
    nx = 0;
end

ny       = size(G,2);
nylags   = size(F,1);
iIminusF = inv(eye(nylags) - F);

% constructing the prior mean
Fhh        = F^hh;
Fohh       = (iIminusF * (eye(nylags)-Fhh)) * Fo;
if hh < 40
    priorSigmaScale  = zeros(ny);
    for j = 0 : hh
        priorSigmaScale = priorSigmaScale + G' * F^(hh-j)* G * prior0.Sigma.scale * G' * F^(hh-j)' * G;
    end
else
    % solves x-a*x*a'=b for b (and then x) symmetrical
    % function [x,info]=lyapunov_symm(a,b)
    [priorSigmaScale0,~] = lyapunov_symm(F,G*prior0.Sigma.scale*G' - F^(hh+1)* G * prior0.Sigma.scale * G' * F^(hh+1)');
    % max(max(abs(priorSigmaScale-G'*priorSigmaScale0*G)))
    priorSigmaScale      = G'*priorSigmaScale0*G;
end

prior.BetaMean   = [Fhh(1:ny,:)'; Fohh(1 : ny,1)'];
prior.BetaVar    = prior0.Phi.cov * 1/ shrinkage;

prior.df  = prior0.Sigma.df;            % usually number of regressors minus the 2
prior.XXi = inv( prior.BetaVar );       % V^{-1}
prior.S   = priorSigmaScale;            % Sigma0

% retrieve the OLS
B_   = olsreg.beta([positions_nylags position_constant], :);
XX_  = olsreg.X(:,[positions_nylags position_constant])' * olsreg.X(:,[positions_nylags position_constant]);
E_   = olsreg.error;
XXp_ = XX_ + prior.XXi;

% construct the posterior
posterior.df     = olsreg.N - nylags - nx + prior0.Sigma.df;
posterior.XXi    = inv( XXp_ );
posterior.PhiHat = posterior.XXi * (XX_ * B_ + prior.XXi * prior.BetaMean);
posterior.S     =  ...
    E_'* E_ + priorSigmaScale + prior.BetaMean' * prior.XXi * prior.BetaMean + ...
    B_' * XX_ * B_ - posterior.PhiHat' * XXp_ * posterior.PhiHat;
% FF    = prior.Sigma.scale + (posterior1.PhiHat - prior1.BetaMean)'* prior1.XXi * (posterior1.PhiHat - prior1.BetaMean) ...
%     + posterior1.E_'* posterior1.E_;

posterior.B_   = B_ ;
posterior.XX_  = XX_;       %olsreg.X(:,[positions_nylags position_constant])' * olsreg.X(:,[positions_nylags position_constant]);
posterior.E_   = E_;        %olsreg.error';
posterior.XXp_ = XXp_;      %XX_ + prior.XXi;
posterior.U_   = olsreg.Y - olsreg.X(:,[positions_nylags position_constant]) * posterior.PhiHat;% posterior errors;


function [cha, chp] = convexhullProps(grains)
% Area of the convex hull of grains
% Note: this is only reasonable for smooth and sufficiently large grains
%
%
% Syntax
%   [cha, chp] = convexhullArea(grains)
%
% Input
%  grains - @grain2d
%
% Output
%  cha - area of convex hull
%  chp - perimeter of covex hull
%
%

p = zeros(size(grains));

% store this in local variables for speed reasons
X = grains.V(:,1);
Y = grains.V(:,2);

poly = grains.poly;
% remove inclusions
incl = grains.inclusionId;
for i = find(incl>0).'
  poly{i} = poly{i}(1:end-incl(i));
end

% compute convex hull perimeters
for id = 1:length(grains)

  % extract coordinates
  xGrain = X(poly{id});
  yGrain = Y(poly{id});

  % compute convex hull
  ixy = convhull(xGrain,yGrain);

  % area
  cha(id) = polySgnArea(xGrain(ixy),yGrain(ixy));

  % perimeter
  chp(id) = sum(sqrt(...
    (xGrain(ixy(1:end-1)) - xGrain(ixy(2:end))).^2 + ...
    (yGrain(ixy(1:end-1)) - yGrain(ixy(2:end))).^2));

end


 function st = newfft(om_in, Nd_in, varargin)
%function st = newfft(om, Nd, [options])
%|
%| New version of NUFFT (pun intended) that uses real interpolation kernels.
%| (The original NUFFT code used complex interpolation needlessly.)
%|
%| This returns a "strum" object with methods for both forward and adjoint
%| d-dimensional NUFFT operations.
%| The forward operation is:
%| X(om_m) = \sum_{n=0}^{N-1} x[n] exp(-1i * om_m * n) for m=1,...,M
%| The adjoint operation is:
%| x_adj[n] = \sum_{m=1}^M X(om_m) exp(+1i * om_m * n) for n=0,...,N-1
%| Note that the adjoint is not the "inverse" NUFFT in general.
%|
%| This routine has numerous options for investigative purposes, but is
%| designed so that the default options should be very good choices.
%| Providing the frequencies and the image size and should suffice.
%| Reducing the neighborhood size 'Jd' (default 6) and/or reducing the
%| over-sampled DFT size 'Kd' (default 2*Nd) may be useful for acceleration.
%|
%| in
%|	om [M,d]	"digital" frequencies in radians (can be empty!)
%|			(if empty, then user must provide 'om' to methods)
%|	Nd [d]		image dimensions (N1,N2,...,Nd)
%|
%| options
%|	'Jd' [d]	# of neighbors used (in each direction). (default: 6)
%|	'Kd' [d]	FFT sizes (should be >= Nd). (default: 2*Nd)
%|	n_shift [d]	n = 0-n_shift to N-1-n_shift (default: 0)
%|		Like fft(), the NUFFT expects the signals to be x(0,0), ...
%|		Use n_shift = [N1/2, N2/2, ...] for x(-N1/2,-N2/2,...), ...
%|
%|	'mode'	char	how to compute the NUFFT (default: 'table1')
%|			'exact'	slow FT
%|			'table0' table with nearest neighbor interpolation
%|			'table1' table with linear interpolation (default)
%|			'gg' gaussian factorization of Greengard & Lee 04 (todo)
%|			'sparse' precompute large sparse matrix
%|				caution: this option may require lots of memory!
%|				(this option used internally to make tables too)
%|			recommended: table0 or table1 to save memory.
%|
%|	'oversample' int table oversampling factor (default: 2^9 for table1)
%|	'gram' 0|1	if 1, precompute additional terms needed for gram matrix
%|	'printmem' 0|1	if 1, print memory usage
%|	'phasing' char	'real' : new real kernels (strongly recommended default)
%|			'complex' : original nufft.m complex kernels
%|			'none' : no phase (straw man; table uses it internally)
%|			'flipreal' : real kernels with sign flips (unsupported)
%|	'dotime' char	report cpu time? (default: '')
%|
%|	'ktype'	char	type of interpolation kernel (default: 'minmax:kb')
%|
%| ktype options:
%|	'diric'		Dirichlet interpolator (exact only if Jd = Kd)
%|	'linear'	linear interpolator (a terrible straw man)
%|	'minmax:kb'	minmax interpolator with excellent KB scaling!
%|	'minmax:tuned'	minmax interpolator, somewhat numerically tuned scaling
%|	'minmax:unif'	minmax with uniform scaling factors (not recommended)
%|	'minmax:user'	minmax interpolator with user parameters required:
%|				'alpha', {alpha}, 'beta', {beta}
%|	'kb:minmax'	kaiser-bessel (KB) interpolator (minmax best alpha, m)
%|	'kb:beatty'	KB with parameters from Beatty et al T-MI Jun 2005
%|	'kb:user'	KB with user-specified KB parameters required:
%|				'kb_m', [m] 'kb_alf', [alpha]
%|	@kernel		user-provided inline interpolation kernel(k,J)
%|			(or a cell array of kernels, one for each dimension)
%|			example ..., 'table', 2^11, 'minmax:kb'
%|			where 2^11 is the table over-sampling factor.
%|
%| out
%|	st	strum object with several methods including the following:
%|		st.fft(x, [om])
%|		st.adj(Xo, [om])
%|		st.p		[M, *Kd]	sparse interpolation matrix
%|						(or empty if table-based)
%|		st.sn		[(Nd)]		scaling factors
%|		st.Nd,Jd,Kd,om	copies of inputs
%|
%| *Nd is shorthand for prod(Nd).
%| (Nd) is shorthand for (N1,N2,...,Nd)
%|
%| Copyright 2007-6-3, Jeff Fessler, The University of Michigan

if nargin == 1 && streq(om_in, 'test'), newfft_test, return, end
if nargin < 2, ir_usage, end

cpu etic

% inputs
st.om = om_in; % [M,d] frequency samples
st.Nd = Nd_in; % [d] signal dimentions
st.dd = length(st.Nd); % dimensionality of input space (usually 2 or 3)

% defaults
st.gram = false;
st.Jd = 6 * ones(1, st.dd);
st.Kd = 2 * st.Nd;
st.n_shift = zeros(1, st.dd);
st.mode = 'table1';
st.oversample = []; % aka Ld for table mode
st.order = []; % for table mode
st.ktype = 'kb:minmax';
st.kb_m = []; % [dd] KB parameters
st.kb_alf = [];
st.alpha = {}; % [dd] minmax parameters
st.beta = {};
st.tol = 0;
st.printmem = false;
st.is_kaiser_scale = false;
st.phasing = 'real'; % use new real table by default
st.dotime = '';

% options
st = vararg_pair(st, varargin);
dotime = st.dotime; st = rmfield(st, 'dotime');

st.phase_before = []; % place holders
st.phase_after = [];
st.flips = [];

% special cases of input sampling pattern
if ischar(st.om)
	st.om = nufft_samples(st.om, st.Nd);
end

% checks
if st.dd ~= length(st.Jd) || st.dd ~= length(st.Kd)
	error 'inconsistent dim'
end
if st.dd ~= length(st.n_shift)
	fail('n_shift needs %d columns', st.dd)
end

if ~isempty(st.om) && st.dd ~= size(st.om,2)
	fail('omega needs %d columns', st.dd)
end

if st.gram, fail 'todo: gram not done', end

if any(st.Kd < st.Nd), warning 'Kd < Nd unlikely to work.  Try Kd=2*Nd', end

%
% "midpoint" of scaling factors
%
switch st.phasing
case 'real'
	st.Nmid = floor(st.Nd / 2); % new
otherwise
	st.Nmid = (st.Nd - 1) / 2; % old
end

%
% different interpolation modes
%
switch st.mode

case 'exact' % exact interpolation for testing
	st = strum(st, { ...
		'fft', @newfft_exact_for, '(x, [om])';
		'adj', @newfft_exact_adj, '(X, [om])';
		'p', @newfft_exact_p, '([om])';
		'sn', @(st) ones(st.Nd), '()';
		});

case {'table0', 'table1'} % precomuted interpolator table
	st = newfft_table_init(st);

	% set up phase corrections not included in table initialization
	if streq(st.phasing, 'real') || streq(st.phasing, 'flipreal')
		st.phase_before = newfft_phase_before(st.Kd, st.Nmid);
		st.phase_after = @(om) newfft_phase_after(om, st.Nmid, st.n_shift);
		if ~isempty(st.om) % phase that goes after interpolation:
			st.phase_after = st.phase_after(st.om);
		end
	end

case 'gg' % greengard's gaussian
	error 'todo: gg'
	st = strum(st, { ...
		'fft', @newfft_gg_for, '(x, [om])';
		'adj', @newfft_gg_adj, '(X, [om])';
		'p', @newfft_gg_p, '([om])';
		'sn', @newfft_gg_sn, '()';
		});

case 'sparse' % interpolator based on a sparse matrix
	if isempty(st.om), error 'sparse mode requires "om"', end
	st = newfft_init_sparse(st);

otherwise
	fail('unknown mode %s', st.mode)
end

if ~isempty(dotime)
	tmp = whos('st');
	tmp = num2str(tmp.bytes);
	tmp = ['newfft setup ' st.mode ' ' st.phasing(1) ' ' tmp ' ' dotime];
	cpu('etoc', tmp)
end

%
% newfft_init_sparse()
%
% create an interpolator based on a sparse matrix.
% this matrix will be large for intersting problem sizes, so this
% mode is not recommended.  but it is supported in part because it
% is needed for generating samples of the interpolator for the table mode.
%
function st = newfft_init_sparse(st)

om = st.om;

%
% different interpolation kernel mechanisms
%
ktype = st.ktype;

switch class(ktype)
case 'cell' % cell array of kernel functions: {kernel1, kernel2, ..., kernelD}
	if isa(ktype{1}, 'inline') || isa(ktype{1}, 'function_handle')
		if length(ktype) ~= dd, error 'wrong # of kernels', end
		st.kernel = ktype;
		ktype = 'inline';
	else
		error 'cell array should be inline kernels!?'
	end

case {'inline', 'function_handle'} % single inline kernel for all dimensions
	for id = 1:st.dd
		st.kernel{id} = ktype; % all same
	end
	ktype = 'inline';

case 'char'
	% a string that describes the type of interpolator, see below

otherwise
	fail('unknown kernel type %s', class(ktype))
end

%
% interpolator set up
%
Nd = st.Nd;
Jd = st.Jd;
Kd = st.Kd;
dd = st.dd;
is_kaiser_scale = false;

switch ktype
case 'inline'
	% already did it above

case 'diric' % exact interpolator
	if any(Jd ~= Kd), warn 'diric inexact unless Jd=Kd', end
	ktype = 'inline';
	for id = 1:dd
		N = Nd(id);
		K = Kd(id);
		if 1 && streq(st.phasing, 'real')
			N = 2 * floor((K+1)/2) - 1; % trick
		end
		st.kernel{id} = @(k,J) N / K * nufft_diric(k, N, K, true);
	end

case 'linear' % linear interpolator straw man
	ktype = 'inline';
	kernel = inline('(1 - abs(k/(J/2))) .* (abs(k) < J/2)', 'k', 'J');
	for id = 1:dd
		st.kernel{id} = kernel;
	end

case 'kb:beatty' % KB with Beatty et al parameters
	is_kaiser_scale = true;
	if ~isempty(st.kb_alf) || ~isempty(st.kb_m)
		warn 'kb_alf and kb_m ignored'
	end
	K_N = Kd ./ Nd;
	st.kb_alf = pi * sqrt( Jd.^2 ./ K_N.^2 .* (K_N - 1/2).^2 - 0.8 );
%	pr st.kb_alf ./ Jd % approximately 2.34 for K_N = 2
	st.kb_m = zeros(1,dd);
	for id = 1:dd
		st.kernel{id} = kaiser_bessel('inline', Jd(id), ...
				st.kb_alf(id), st.kb_m(id));
	end

case 'kb:minmax' % KB with minmax-optimized parameters
	is_kaiser_scale = true;

	if ~isempty(st.kb_alf) || ~isempty(st.kb_m)
		warn 'kb_alf and kb_m ignored'
	end
	for id = 1:dd
		[st.kernel{id} st.kb_alf(id) st.kb_m(id)] = ...
			kaiser_bessel('inline', Jd(id));
	end

case 'kb:user' % KB with user-defined parameters
	is_kaiser_scale = true;

	if isempty(st.kb_alf) || isempty(st.kb_m)
		fail 'kb_alf and kb_m required'
	end
	if (length(st.kb_alf) ~= dd) || (length(st.kb_m) ~= dd)
		fail('#alpha=%d #m=%d vs dd=%d', ...
			length(st.kb_alf), length(st.kb_m), dd)
	end
	for id = 1:dd
		st.kernel{id} = kaiser_bessel('inline', Jd(id), ...
				st.kb_alf(id), st.kb_m(id));
	end

case 'minmax:kb' % minmax interpolator with KB scaling factors
	for id = 1:dd
		[st.alpha{id}, st.beta{id}] = ...
			nufft_alpha_kb_fit(Nd(id), Jd(id), Kd(id), ...
				'Nmid', st.Nmid(id));
	end

case 'minmax:tuned' % minmax with numerically "tuned" scaling factors
	for id = 1:dd
		[st.alpha{id}, st.beta{id}, ok] = ...
			nufft_best_alpha(Jd(id), 0, Kd(id)/Nd(id));
		if ~ok, error 'unknown J,K/N', end
	end

case 'minmax:user' % minmax interpolator with user-provided scaling factors
	if isempty(st.alpha) || isempty(st.beta)
		error 'user must provide alpha/beta'
	end
	if length(st.alpha) ~= dd || length(st.beta) ~= dd
		error 'alpha/beta size mismatch'
	end

case 'minmax:unif' % minmax with straw man uniform scaling factors
	for id = 1:dd
		st.alpha{id} = 1;
		st.beta{id} = 0;
	end

otherwise
	fail('unknown kernel type %s', ktype)
end

%
% scaling factors: "outer product" of 1D vectors
%
st.sn = 1;
for id=1:dd
	if 1 && streq(st.ktype, 'linear')
		tmp = newfft_scale_tri(Nd(id), Jd(id), Kd(id), st.Nmid);
	elseif streq(st.ktype, 'diric')
		tmp = ones(Nd(id),1);
	elseif is_kaiser_scale
		nc = [0:Nd(id)-1]' - st.Nmid(id);
		tmp = 1 ./ kaiser_bessel_ft(...
			nc/Kd(id), Jd(id), st.kb_alf(id), st.kb_m(id), 1);
	elseif streq(ktype, 'inline')
		tmp = 1 ./ nufft_interp_zn(0, Nd(id), Jd(id), Kd(id), ...
			st.kernel{id}, st.Nmid(id));
	else
		tmp = nufft_scale(Nd(id), Kd(id), ...
			st.alpha{id}, st.beta{id}, st.Nmid(id));
	end
	tmp = reale(tmp);
	st.sn = st.sn(:) * tmp';
end
if length(Nd) > 1
	st.sn = reshape(st.sn, Nd);	% [(Nd)]
else
	st.sn = st.sn(:);	% [(Nd)]
end

%
% [J?,M] interpolation coefficient vectors.  will need kron of these later
%
for id=1:dd
	N = Nd(id);
	J = Jd(id);
	K = Kd(id);
	if isfield(st, 'kernel')
		[c, arg] = ...
		nufft_coef(om(:,id), J, K, st.kernel{id});	% [J?,M]
	else
		alpha = st.alpha{id};
		beta = st.beta{id};
		T = nufft_T(N, J, K, st.tol, alpha, beta);	% [J?,J?]
		[r, arg] = ...
		nufft_r(om(:,id), N, J, K, alpha, beta);	% [J?,M]
		c = T * r;
		clear T r
	end

	%
	% indices into oversampled FFT components
	%
	koff = nufft_offset(om(:,id), J, K);	% [M,1] to leftmost near nbr
	k0 = outer_sum([1:J]', koff');	% [J?,M] arbitrary integers
	kd{id} = mod(k0, K);	% [J?,M] {0,...,K?-1} (DFT indices)

	gam = 2*pi/K;

	switch st.phasing
	case {'real', 'none'}
		phase = 1;
	case 'complex'
		phase_scale = 1i * gam * (N-1)/2;
		phase = exp(phase_scale * arg);	% [J?,M] linear phase
	case 'flipreal'
		isodd = @(n) mod(n,2) == 1;
		phase = ones(size(k0)); % [J?,M]
		flip = isodd((kd{id} - k0) / K * (N-1)); % sign flip every K
		phase(flip) = -1; % sign flip (if N is even)
	otherwise
		fail('unknown phasing %s', st.phasing)
	end
	ud{id} = phase .* c;		% [J?,M]

end % id
clear c arg gam phase phase_scale koff k0 N J K

% st.M = size(om,1);
M = size(om,1);

%
% build sparse matrix that is [M,*Kd]
% with *Jd nonzero entries per frequency point
%
if st.printmem
	printm('Needs at least %g Gbyte RAM', prod(Jd)*M*8/2^30*2)
end

kk = kd{1};	% [J1,M]
uu = ud{1};	% [J1,M]
for id = 2:dd
	Jprod = prod(Jd(1:id));
	tmp = kd{id} * prod(Kd(1:(id-1)));
	kk = block_outer_sum(kk, tmp);		% outer sum of indices
	kk = reshape(kk, Jprod, M);
	uu = block_outer_prod(uu, ud{id});	% outer product of coefficients
	uu = reshape(uu, Jprod, M);
end % now kk and uu are [*Jd, M]

%
% handle phase shifts
%
uu = conj(uu); % [*Jd,M] ala Hermitian transpose of interpolation coefficients
switch st.phasing
case 'complex'
	phase = exp(1i * (om * st.n_shift(:))).';	% [1,M]
	uu = uu .* phase(ones(1,prod(Jd)),:);	% [*Jd,M]
	if streq(st.mode, 'table', 5) % moved from newfft_table_init.m to here
		st.phase_after = @(om) exp(1i * (om * col(st.n_shift))); % [M,1]
	end
case {'real', 'flipreal'}
	st.phase_before = newfft_phase_before(Kd, st.Nmid);
	if ~isempty(st.om) % precompute phase that goes after interpolation
		st.phase_after = newfft_phase_after(st.om, st.Nmid, st.n_shift);
	else
		st.phase_after = @(om) newfft_phase_after(om, st.Nmid, st.n_shift);
	end
case 'none'
	% do nothing
otherwise
	error 'bug'
end

mm = repmat(1:M, prod(Jd), 1); % [*Jd,M]
st.p = sparse(mm(:), 1+kk(:), uu(:), M, prod(Kd)); % [M, *Kd] sparse matrix
% sparse object, to better handle single precision operations!
st.p = Gsparse(st.p, 'odim', [M 1], 'idim', [prod(Kd) 1]);

st = strum(st, { ...
	'fft', @newfft_approx_for, '(x, [om])';
	'adj', @newfft_approx_adj, '(X, [om])';
	});

%
% in
%	x1	[J1,M]
%	x2	[J2,M]
% out
%	y	[J1,J2,M]	y(i1,i2,m) = x1(i1,m) + x2(i2,m)
%
function y = block_outer_sum(x1, x2)
[J1 M] = size(x1);
[J2 M] = size(x2);
xx1 = reshape(x1, [J1 1 M]);	% [J1,1,M] from [J1,M]
xx1 = xx1(:,ones(J2,1),:);	% [J1,J2,M], emulating ndgrid
xx2 = reshape(x2, [1 J2 M]);	% [1,J2,M] from [J2,M]
xx2 = xx2(ones(J1,1),:,:);	% [J1,J2,M], emulating ndgrid
y = xx1 + xx2;			% [J1,J2,M]

function y = block_outer_prod(x1, x2)
[J1 M] = size(x1);
[J2 M] = size(x2);
xx1 = reshape(x1, [J1 1 M]);	% [J1,1,M] from [J1,M]
xx1 = xx1(:,ones(J2,1),:);	% [J1,J2,M], emulating ndgrid
xx2 = reshape(x2, [1 J2 M]);	% [1,J2,M] from [J2,M]
xx2 = xx2(ones(J1,1),:,:);	% [J1,J2,M], emulating ndgrid
y = xx1 .* xx2;			% [J1,J2,M]

%
% newfft_phase_before()
% phase factor that gets multiplied by DFT (before interpolation)
%
function phase = newfft_phase_before(Kd, Nmid)

phase = 0;
for id = 1:length(Kd)
	tmp = 2 * pi * [0:Kd(id)-1] / Kd(id) * Nmid(id);
	phase = outer_sum(phase, tmp); % [(Kd)] when done
end
phase = exp(1i * phase);

%
% newfft_phase_after()
% phase factor that multiplies the DTFT (after interpolation)
%
function phase = newfft_phase_after(om, Nmid, n_shift)

phase = exp(1i * (om * col(n_shift - Nmid))); % [M,1]

%
% newfft_scale_tri()
% scale factors when kernel is 'linear'
% tri(u/J) <-> J sinc^2(J x)
%
function sn = newfft_scale_tri(N, J, K, Nmid)
nc = [0:N-1] - Nmid;
fun = @(x) J * nufft_sinc(J * x / K).^2;
cent = fun(nc);
sn = 1 ./ cent;

% try the optimal formula
tmp = 0;
LL = 3;
for ll=-LL:LL
	tmp = tmp + abs(fun(nc - ll*K)).^2;
end
sn = cent ./ tmp;

%
% newfft_test_time()
% compare compute times of real vs complex, sparse vs table
%
function newfft_test_time

Nd = [1 1] * 2^8;
[tmp om] = mri_trajectory('radial', {}, Nd, Nd);
pr length(om)
rng(0)
x0 = rand([Nd 1]);

arg = {om, Nd, 'dotime', ' '};
s0r = newfft(arg{:}, 'mode', 'table0');
s0c = newfft(arg{:}, 'mode', 'table0', 'phasing', 'complex');
s1r = newfft(arg{:}, 'mode', 'table1');
ssr = newfft(arg{:}, 'mode', 'sparse');
ssc = newfft(arg{:}, 'mode', 'sparse', 'phasing', 'complex');

tmp = @(st) newfft_test_time_one(st, x0, 2);
tmp(s0r)
tmp(s0c)
tmp(s1r)
tmp(ssr)
tmp(ssc)

function newfft_test_time_one(st, x0, nn)
st.fft(x0); % warm up
tmp = [st.mode ' ' st.phasing(1)];
cpu etic
for ii=1:nn
	st.fft(x0); % trial
end
cpu('etoc', tmp)

%
% newfft_test()
%
function newfft_test

newfft_test_time
prompt

modes = {'sparse', 'table0', 'table1'};

phasings = {'complex', 'real'};
% 'flipreal' no longer needed thanks to floor(N/2)
% 'none' is for internal table only

Nd_list = [20 10 8];
for id=0:3
	if id == 0
		Nd = 1 + Nd_list(1); % test odd case
	else
		Nd = Nd_list(1:id);
	end
	dd = length(Nd);

	rng(0)
	om = 3 * 2 * pi * (rand(100,length(Nd)) - 0.5);
%	om = sort(om);
%	om = linspace(-1,1,601)' * 3*pi;
%	om = [-8:8]'/2 * pi;
	%om = 'epi';
	x0 = rand([Nd 1]);
%	x0 = zeros([Nd 1]); x0(1) = 1; % unit vector for testing
%	x0 = ones([Nd 1]);

	% exact
	st_e = newfft(om, Nd, 'mode', 'exact');
	Xe = st_e.fft(x0);
	xe = st_e.adj(Xe);
	if 0
		pe = st_e.p;
		equivs(pe * x0(:), Xe)
		equivs(reshape(pe' * Xe, [Nd 1]), xe)
	end

	ktypes = {{'linear', 'Jd', 2*ones(1,dd)}, ...
		'minmax:unif', ...
		{'minmax:user', 'alpha', num2cell(ones(1,dd)), ...
			'beta', num2cell(0.5 * ones(1,dd))}, ...
		{'diric', 'Jd', 2*Nd-0, 'oversample', []}, ...
		'minmax:kb', 'minmax:tuned', ...
		'kb:minmax', 'kb:beatty', ...
		{'kb:user', 'kb_m', 0*Nd, 'kb_alf', 2.34 * 6 + 0*Nd}
		};

	for ii=4:length(ktypes) % skip poor ones
		ktype = ktypes{ii};
		if ~iscell(ktype), ktype = {ktype}; end

	for jj=1:length(modes)
	for ip=1:length(phasings)
		sc = newfft(st_e.om, st_e.Nd, 'phasing', 'complex', ...
			'mode', 'table0', 'ktype', ktype{:});

		st = newfft(st_e.om, st_e.Nd, 'phasing', phasings{ip}, ...
			'mode', modes{jj}, 'ktype', ktype{:});

		if streq(st.phasing, 'complex') && streq(st.mode, 'table1')
			continue
		end

%		pr minmax(st.sn)
		pad = @(s,n) [s blanks(n-length(s))];
		key = [sprintf('%2d ', st.Jd(1)) st.ktype];
		key = [st.mode ' ' num2str(id) st.phasing(1) ' ' pad(key,16)];
		Xs = st.fft(x0);
		max_percent_diff(Xe, Xs, key)
%		plot(abs(Xe), abs(Xs), 'o'), prompt

		xs = st.adj(Xe);
		max_percent_diff(xe, xs, key)
	end % ip
	end % jj
	end % ii
end


function blas2_test06 ( )

%*****************************************************************************80
%
%% BLAS2_TEST06 tests DTRMV.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 April 2014
%
%  Author:
%
%    John Burkardt
%
  m = 5;
  lda = m;
  n = m;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'BLAS2_TEST06\n' );
  fprintf ( 1, '  For a triangular matrix A,\n' );
  fprintf ( 1, '  DTRMV computes y := A * x or y := A'' * x\n' );

  for test = 1 : 2

    uplo = 'U';

    if ( test == 1 )
      trans = 'N';
    else
      trans = 'T';
    end

    diag = 'N';

    for j = 1 : n
      for i = 1 : j
        a(i,j) = i + j;
      end
      for i = j + 1 : m
        a(i,j) = 0.0;
      end
    end

    incx = 1;
    for i = 1 : n
      x(i) = i;
    end

    x = dtrmv ( uplo, trans, diag, n, a, lda, x, incx );

    if ( trans == 'N' )
      r8vec_print ( n, x, '  Result y = A * x' );
    else
      r8vec_print ( n, x, '  Result y = A'' * x' );
    end

  end

  return
end


% signed velocity in the direction of the closest fly, according to type
function [data,units] = compute_veltoward(trx,n,type)

flies = trx.exp2flies{n};
nflies = numel(flies);
data = cell(1,nflies);

for i1 = 1:nflies,
  fly1 = flies(i1);

  % fly closest to fly1 according to type
  closestfly = trx(fly1).(['closestfly_',type]);

  % velocity of fly1
  dx1 = diff(trx(fly1).x_mm,1,2);
  dy1 = diff(trx(fly1).y_mm,1,2);
  x_mm1 = trx(fly1).x_mm;
  y_mm1 = trx(fly1).y_mm;

  % loop over all flies
  for i2 = 1:nflies,

    fly2 = flies(i2);
    if i1 == i2, continue; end

    % frames where this fly is closest
    idx = find(closestfly(1:end-1) == fly2);

    % don't use the last frame of fly2
    off = trx(fly1).firstframe - trx(fly2).firstframe;
    idx(idx+off == trx(fly2).nframes) = [];

    if isempty(idx), continue; end

    % unit vector in direction of fly2 from fly1
    off = trx(fly1).firstframe - trx(fly2).firstframe;
    dx2 = trx(fly2).x_mm(off+idx)-x_mm1(idx);
    dy2 = trx(fly2).y_mm(off+idx)-y_mm1(idx);
    dz2 = sqrt(dx2.^2 + dy2.^2);
    dx2 = dx2 ./ dz2;
    dy2 = dy2 ./ dz2;
    dx2(dz2==0) = 0;
    dy2(dz2==0) = 0;

    % project velocity of fly1 onto this vector
    data{i1}(idx) = dx1(idx).*dx2 + dy1(idx).*dy2;

  end
end

units = parseunits('mm/s');


function sphere_grid_test06 ( )

%*****************************************************************************80
%
%% SPHERE_GRID_TEST06 tests SPHERE_LL_LINES.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 October 2012
%
%  Author:
%
%    John Burkardt
%
  lat_num = 3;
  long_num = 4;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'SPHERE_GRID_TEST06\n' );
  fprintf ( 1, '  SPHERE_LL_LINES computes gridlines\n' );
  fprintf ( 1, '  on a sphere in 3D.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of latitudes is  %d\n', lat_num );
  fprintf ( 1, '  Number of longitudes is %d\n', long_num );

  line_num = sphere_ll_line_num ( lat_num, long_num );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of line segments is %d\n', line_num );

  line = sphere_ll_lines ( lat_num, long_num, line_num );

  i4mat_transpose_print ( 2, line_num, line, '  Grid line vertices:' );

  return
end


function test_min_test04 ( )

%*****************************************************************************80
%
%% TEST_MIN_TEST04 compares the eact and approximate second derivatives.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 February 2009
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST_MIN_TEST04\n' );
  fprintf ( 1, '  For each problem, compare the eact and\n' );
  fprintf ( 1, '  approximate second derivatives at the starting point.\n' );
%
%  Get the number of problems.
%
  problem_num = p00_problem_num ( );

  for problem = 1 : problem_num

    title = p00_title ( problem );

    fprintf ( 1, '\n' );
    fprintf ( 1, '  Problem %d\n', problem );
    fprintf ( 1, '  %s\n', title );

    x = p00_start ( problem );

    fprintf ( 1, '\n' );
    fprintf ( 1, '  X:\n' );
    fprintf ( 1, '  %e\n', x );

    f2 = p00_f2 ( problem, x );

    fprintf ( 1, '  F"(X) (exact):\n' );
    fprintf ( 1, '  %e\n', f2 );

    f2_dif = p00_f2_dif ( problem, x );

    fprintf ( 1, '  F"(X) (difference):\n' );
    fprintf ( 1, '  %e\n', f2_dif );

  end

  return
end


function B=rotmat(A,n,dim)
%ROTMAT  Rotate matrix along specified dimension.
%   ROTMAT(X), returns X.
%   ROTMAT(X,N), moves elements in matrix X with N steps in
%      a wrapping/rotating fashion. Rotation will be done row-wise.
%      Positive N will mean that elements are moved towards higher
%      row indicies. Last element(s) will be moved to the first row,
%      aso. Negative N will make the elements move upwards towards
%      lower row indicies. First element(s) will be moved to the last
%      row, aso. If N is zero or empty, no rotation will occur
%      and X will be returned.
%   ROTMAT(X,N,DIM), rotates matrix elements along dimension DIM.
%      If DIM is a singleton dimension, X will be returned.
%      Likewise if DIM < 1 or DIM > ndims(X), nothing will happen.
%      N must be scalar valued.
%
%   Examples:
%      X=rand(3,3,3)          %X is 3x3x3.
%      rotmat(X,1)            %rotates one step along rows.
%      rotmat(X,-2)           %rotates two steps along rows, opposite direction.
%      rotmat(X,1,2)          %rotates one step along columns.
%      rotmat(X,1,3)          %rotates one step along third dimension.
%
%   See also DELMAT, INSMAT, SHIFTMAT, REPMAT, RESHAPE, FLIPDIM.

% Copyright (c) 2003-10-28, B. Rasmus Anthin.
% Revision 2003-10-29.
% GPL license, freeware.

error(nargchk(1,3,nargin))
if nargin<2, n=0;end                    %do nothing
if isempty(n), n=0;end
if prod(size(n))~=1, error('N must be a scalar.'),end
n=round(n);
if nargin<3, dim=1;end                  %rotate row vectors
if dim<1, dim=ndims(A)+1;end            %if less than one, do nothing
dims=[dim:max(ndims(A),dim) 1:dim-1];
if dims(1)<=ndims(A) & n
   A=permute(A,dims);                             %move dimension to front
   sizA=size(A);                                  %get dimension sizes
   A=reshape(A,[sizA(1) prod(sizA(2:end))]);      %reshape to a 2-D matrix
   n=rem(n-1,sizA(1))+1;                          %wrapping
   idx=1:sizA(1);                                 %the row indices
   if n<0
      idx=[idx(1-n:end) idx(1:-n)];               %rotate row indices (negative rotation)
   else
      idx=[idx(end-n+1:end) idx(1:end-n)];        %rotate row indices (positive rotation)
   end
   B=A(idx,:);
   B=reshape(B,[size(B,1) sizA(2:end)]);          %back to previous shape minus removed vectors
   B=ipermute(B,dims);                            %replace dimensions to initial location
else
   B=A;
end


function element_node = grid_q9_element ( nelemx, nelemy )

%*****************************************************************************80
%
%% GRID_Q9_ELEMENT produces a grid of 9 node quadrilaterals.
%
%  Example:
%
%    Input:
%
%      NELEMX = 3, NELEMY = 2
%
%    Output:
%
%      ELEMENT_NODE =
%         1,  3, 17, 15,  2, 10, 16,  8,  9;
%         3,  5, 19, 17,  4, 12, 18, 10, 11;
%         5,  7, 21, 19,  6, 14, 20, 12, 13;
%        15, 17, 31, 29, 16, 24, 30, 22, 23;
%        17, 19, 33, 31, 18, 26, 32, 24, 25;
%        19, 21, 35, 33, 20, 28, 34, 26, 27.
%
%  Grid:
%
%   29---30---31---32---33---34---35
%    |    .    |    .    |    .    |
%    |    .    |    .    |    .    |
%   22 . 23 . 24 . 25 . 26 . 27 . 28
%    |    .    |    .    |    .    |
%    | 4  .    | 5  .    | 6  .    |
%   15---16---17---18---19---20---21
%    |    .    |    .    |    .    |
%    |    .    |    .    |    .    |
%    8 .  9 . 10 . 11 . 12 . 13 . 14
%    |    .    |    .    |    .    |
%    | 1  .    | 2  .    | 3  .    |
%    1----2----3----4----5----6----7
%
%  Reference Element Q9:
%
%    |
%    1  4--7--3
%    |  |     |
%    |  |     |
%    S  8  9  6
%    |  |     |
%    |  |     |
%    0  1--5--2
%    |
%    +--0--R--1-->
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 April 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NELEMX, NELEMY, the number of elements along the
%    X and Y directions.  The number of elements generated will be
%    NELEMX * NELEMY.
%
%    Output, integer ELEMENT_NODE(9,NELEMX*NELEMY), the nodes that form
%    each element.
%

%
%  Node labeling:
%
%    NW----N----NE
%     |          |
%     W    C     E
%     |          |
%    SW----S----SE
%
  element = 0;

  for j = 1 : nelemy
    for i = 1 : nelemx

      sw = 2 * ( j - 1 )  * ( 2 * nelemx + 1 ) + 2 * ( i - 1 ) + 1;
      w  = sw +               2 * nelemx + 1;
      nw = sw +         2 * ( 2 * nelemx + 1 );

      s  = sw + 1;
      c  = sw + 1 +               2 * nelemx + 1;
      n  = sw + 1 +         2 * ( 2 * nelemx + 1 );

      se = sw + 2;
      e  = sw + 2 +               2 * nelemx + 1;
      ne = sw + 2 +         2 * ( 2 * nelemx + 1 );

      element = element + 1;

      element_node(1,element) = sw;
      element_node(2,element) = se;
      element_node(3,element) = ne;
      element_node(4,element) = nw;
      element_node(5,element) = s;
      element_node(6,element) = e;
      element_node(7,element) = n;
      element_node(8,element) = w;
      element_node(9,element) = c;

    end
  end

  return
end