function Q=quatMult(quat2,quat1,handed)
%%QUATMULT  Multiply two quaternions together. Quaternions are an extension
%           of complex numbers. The type of product performed here is
%           deemed the Grassman product. Unit-magnitude quaternions are
%           often used to represent rotations and the multiplication
%           quat2*quat1 is the orientation obtained by rotating by quat1
%           and then rotating by quat2. Quaternion multiplication is not
%           commutative. The quaternions can be either left or
%           right-handed.
%
%INPUTS:quat2 A 4XN set of N quaternions, where the first element in each
%             column is the scalar part of the quaternion (sometimes called
%             q0 or q4) and the next three elements are the (hypercomplex)
%             vector part. That is, the hypercomplex quaternion given by
%             quat2(:,1) can be written in hypercomplex, non-vector form
%             as quat2(1,1)+i*quat2(2,1)+j*quat2(3,1)+k*quat2(4,1), where
%             i, j, and k are all roots of -1. When considering unit
%             quaternions, this means that it has the form
%             [cos(theta/2);sin(theta/2)u'], where theta is an angle and u
%             is a 3X1 unit vector.
%       quat1 A 4XN set of N quaternions that are to be left-multiplied by
%             the corresponding quaternions in quat2.
%     handed The handedness of the quaternions. If omitted or an empty
%            matrix is passed,, it is assumed that the quaternions are
%            right-handed (the standard). Possible values are
%            'right' The default if omitted. The quaternion multiplication
%                    is assumed right-handed (standard).
%            'left'  The quaternion multiplication is assumed left-handed.
%                    This is used in someplaces, including the reference
%                    from Shuster, below.
%
%OUTPUTS: Q   The 4XN matrix of quaternions products such that
%             Q(:,i)=quat2(:,i)*quat1(:,1), where the multiplication
%             operation is quaternion multiplication.
%
%Properties of quaternions including multiplication are described in [1].
%Details of rotation using unit quaternions are given in [2].
%
%The difference in multiplication between right-handed and left-handed
%quaternions lies in the sign used for the cross product.
%
%A quaternion of the form q(1)+i*q(2)+j*q(3)+k*q(4) that obeys right-handed
%multiplication rules supports the following rules for multiplication of i,
%j, and k, where an item in a row is multiplied by an item in the column to
%get the result:
%  i,  j, k
%i -1, k,-j
%j -k,-1, i
%k  j,-i,-1
%On the other hand, left-handed multiplication rules flip the signs of the
%off-diagonal terms:
%  i,  j, k
%i -1,-k, j
%j  k,-1,-i
%k -j, i,-1
%
%REFERENCES:
%[1] Weisstein, Eric W. "Quaternion." From MathWorld--A Wolfram Web
%    Resource. http://mathworld.wolfram.com/Quaternion.html
%[2] M. D. Shuster, "A survey of attitude representations," The Journal of
%    the Astronautical Sciences, vol. 41, no. 4, pp. 439-517, Oct.-Dec.
%    1993.
%
%September 2014 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

%The number of quaternions.
N=size(quat2,2);

if(nargin<3||isempty(handed))
    handed='right';
end

Q=zeros(4,N);
%The handedness switches the sign of the cross product
switch(handed)
    case 'right'
        for curQuat=1:N
            s1=quat1(1,curQuat);
            v1=quat1(2:4,curQuat);
            s2=quat2(1,curQuat);
            v2=quat2(2:4,curQuat);

            Q(:,curQuat)=[s1*s2-dot(v1,v2);
                          s1*v2+s2*v1+cross(v2,v1)];
        end
    case 'left'
        %Flip the algebra to left-handed for the formula below.
         for curQuat=1:N
            s1=quat1(1,curQuat);
            v1=quat1(2:4,curQuat);
            s2=quat2(1,curQuat);
            v2=quat2(2:4,curQuat);

            Q(:,curQuat)=[s1*s2-dot(v1,v2);
                          s1*v2+s2*v1-cross(v2,v1)];
        end
    otherwise
        error('Invalid handedness provided.')
end
end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function [x, c, funVal, ValueL]=mtLogisticC(A, y, z, opts)
%
%%
% Function mtLogisticC:
%      Logistic Loss for Multi-task Learning
%             with the (group) L1/Lq-norm Constraint
%
%% Problem
%
%  min \sum_i - weight_i * log (p_i) + z * sum_j ||x^j||_q
%
%  p_i= 1/ (1+ exp(-y_i (x_l' * a_i + c_l) ) ) denotes the probability
%
%  a_i denotes a training sample,
%      and a_i' corresponds to the i-th row of the data matrix A
%
%  x^j denotes the j-th row of x
%  x_l denotes the l-th column of x, for the l-th task
%  c_l is the intercept for the l-th task
%
%  y_i (either 1 or -1) is the response
%
%  weight_i denotes the weight for the i-th sample
%  In this implementation, we assume weight_{il}=1/m
%
%  For the case that the multi tasks share the same data
%  matrix, please refer to the functions:
%            mcLeastR and mcLogisticR.
%
%% Input parameters:
%
%  A-         Matrix of size m x n
%                A can be a dense matrix
%                         a sparse matrix
%                         or a DCT matrix
%  y -        Response vector (of size m x 1)
%  z -        L1/Lq norm regularization parameter (z >=0)
%  opts-      Optional inputs (default value: opts=[])
%
%% Output parameters:
%  x-         The obtained weight of size n x k
%  c-         The obtained intercept if size 1 x k
%  funVal-    Function value during iterations
%
%% Copyright (C) 2009-2010 Jun Liu, and Jieping Ye
%
% You are suggested to first read the Manual.
%
% For any problem, please contact with Jun Liu via j.liu@asu.edu
%
% Last modified on February 19, 2010.
%
%% Related papers
%
% [1]  Jun Liu, Shuiwang Ji, and Jieping Ye, Multi-Task Feature Learning
%      Via Efficient L2,1-Norm Minimization, UAI, 2009
%
% [2]  Jun Liu, Lei Yuan, Songcan Chen and Jieping Ye, Multi-Task Feature Learning
%      Via Efficient L2,1-Norm Minimization, Technical Report ASU, 2009.
%
%% Related functions:
%
%  sll_opts, initFactor, pathSolutionLeast
%  mtLeastR, mtLeastC, mtLogisticR, ep21d
%
%%

%% Verify and initialize the parameters
%%
if (nargin <4)
    error('\n Inputs: A, y, z, and opts.ind should be specified!\n');
end

[m,n]=size(A);

if (length(y) ~=m)
    error('\n Check the length of y!\n');
end

if (z<=0)
    error('\n z should be positive!\n');
end

opts=sll_opts(opts); % run sll_opts to set default values (flags)

%% Detailed initialization
%%

% Initialize ind and q
if ~isfield(opts,'ind')
    error('\n In mtLeastR, .ind should be specified');
else
    ind=opts.ind;
    k=length(ind)-1;

    if ind(k+1)~=m
        error('\n Check opts.ind');
    end
end

% Initialize q
if (~isfield(opts,'q'))
    q=2; opts.q=2;
else  % currently, we only implement q=2
    q=opts.q;
    if (q~=2)
        error('\n Currently, we only implement the case q=2');
    end
end

%% Normalization

% Please refer to sll_opts for the definitions of mu, nu and nFlag
%
% If .nFlag =1, the input matrix A is normalized to
%                     A= ( A- repmat(mu, m,1) ) * diag(nu)^{-1}
%
% If .nFlag =2, the input matrix A is normalized to
%                     A= diag(nu)^{-1} * ( A- repmat(mu, m,1) )
%
% Such normalization is done implicitly
%     This implicit normalization is suggested for the sparse matrix
%                                    but not for the dense matrix
%

if (opts.nFlag~=0)
    if (isfield(opts,'mu'))
        mu=opts.mu;
        if(size(mu,2)~=n)
            error('\n Check the input .mu');
        end
    else
        mu=mean(A,1);
    end

    if (opts.nFlag==1)
        if (isfield(opts,'nu'))
            nu=opts.nu;
            if(size(nu,1)~=n)
                error('\n Check the input .nu!');
            end
        else
            nu=(sum(A.^2,1)/m).^(0.5); nu=nu';
        end
    else % .nFlag=2
        if (isfield(opts,'nu'))
            nu=opts.nu;
            if(size(nu,1)~=m)
                error('\n Check the input .nu!');
            end
        else
            nu=(sum(A.^2,2)/n).^(0.5);
        end
    end

    ind_zero=find(abs(nu)<= 1e-10);    nu(ind_zero)=1;
    % If some values in nu is typically small, it might be that,
    % the entries in a given row or column in A are all close to zero.
    % For numerical stability, we set the corresponding value to 1.
end

if (~issparse(A)) && (opts.nFlag~=0)
    fprintf('\n -----------------------------------------------------');
    fprintf('\n The data is not sparse or not stored in sparse format');
    fprintf('\n The code still works.');
    fprintf('\n But we suggest you to normalize the data directly,');
    fprintf('\n for achieving better efficiency.');
    fprintf('\n -----------------------------------------------------');
end

%% Starting point initialization

p_flag=(y==1);                  % the indices of the postive samples

for i=1:k
    ind_i=(ind(i)+1):ind(i+1);  % indices for the i-th group

    m1(1,i)=sum(p_flag(ind_i));      % the total number of the positive samples
    m2(1,i)=length(ind_i)-m1(1,i);   % the total number of the negative samples
end

% initialize a starting point
if opts.init==2
    x=zeros(n,k); c=zeros(1,k);
else
    if isfield(opts,'x0')
        x=opts.x0;
        if ( size(x,1)~=n || size(x,2)~=k )
            error('\n Check the input .x0');
        end
    else
        x=zeros(n,k);
    end

    if isfield(opts,'c0')
        c=opts.c0;

        if ( length(c)~=k )
            error('\n Check the input .c0');
        end
    else
        c=log(m1./m2);
    end
end

Ax=zeros(m,1); % m x 1
% compute Ax: Ax_i= A_i * x_i
for i=1:k
    ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
    m_i=ind(i+1)-ind(i);          % number of samples in the i-th group

    if (opts.nFlag==0)
        Ax(ind_i,1)=A(ind_i,:)* x(:,i);
    elseif (opts.nFlag==1)
        invNu=x(:,i)./nu; mu_invNu=mu * invNu;
        Ax(ind_i,1)=A(ind_i,:)*invNu -repmat(mu_invNu, m_i, 1);
    else
        Ax(ind_i,1)=A(ind_i,:)*x(:,i)-repmat(mu*x(:,i), m, 1);
        Ax(ind_i,1)=Ax./nu(ind_i,1);
    end
end

%% The main program
% The Armijo Goldstein line search schemes

if (opts.lFlag==0)

    lambda0=0;
    % a guess of the root

    bFlag=0; % this flag tests whether the gradient step only changes a little

    L=1/m; % the intial guess of the Lipschitz continuous gradient

    % assign xp with x, and Axp with Ax
    xp=x; Axp=Ax; xxp=zeros(n,k);
    cp=c;         ccp=zeros(1,k);

    alphap=0; alpha=1;

    for iterStep=1:opts.maxIter
        % --------------------------- step 1 ---------------------------
        % compute search point s based on xp and x (with beta)
        beta=(alphap-1)/alpha;    s=x + beta* xxp;   sc=c + beta* ccp;

        % --------------------------- step 2 ---------------------------
        % line search for L and compute the new approximate solution x

        % compute the gradient (g) at s
        As=Ax + beta* (Ax-Axp);

        % aa= - diag(y) * (A * s + sc)
        vec_sc=zeros(m,1);
        for i=1:k
            ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
            vec_sc(ind_i,1)=sc(i);
        end
        aa=- y.*(As+ vec_sc);

        % fun_s is the logistic loss at the search point
        bb=max(aa,0);
        fun_s= sum(sum ( log( exp(-bb) +  exp(aa-bb) ) + bb ) ) / m;

        % compute prob=[p_1;p_2;...;p_m]
        prob=1./( 1+ exp(aa) );

        % b= - diag(y) * (1 - prob)
        b= -y.*(1-prob) / m;

        gc=zeros(1,k);                     % the gradient of c
        for i=1:k
            ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
            gc(1,k)=sum(b(ind_i));
        end

        % compute g= AT b, the gradient of x
        for i=1:k
            ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group

            if (opts.nFlag==0)
                tt =A(ind_i,:)'*b(ind_i,1);
            elseif (opts.nFlag==1)
                tt= A(ind_i,:)'*b(ind_i,1) - sum(b(ind_i,1)) * mu';
                tt=tt./nu(ind_i,1);
            else
                invNu=b(ind_i,1)./nu(ind_i,1);
                tt=A(ind_i,:)'*invNu - sum(invNu)*mu';
            end

            g(:,i)= tt;
        end

        % copy x and Ax to xp and Axp
        xp=x;    Axp=Ax;
        cp=c;

        while (1)
            % let s walk in a step in the antigradient of s to get v
            % and then do the L1/Lq-norm regularized projection
            v=s-g/L; c= sc- gc/L;

            % L1/Lq-norm regularized projection
            [x, lambda, zf_step]=ep21d(v, n, k, z, lambda0);
            lambda0=lambda;

            v=x-s;  % the difference between the new approximate solution x
            % and the search point s

            % compute Ax: Ax_i= A_i * x_i
            for i=1:k
                ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
                m_i=ind(i+1)-ind(i);          % number of samples in the i-th group

                if (opts.nFlag==0)
                    Ax(ind_i,1)=A(ind_i,:)* x(:,i);
                elseif (opts.nFlag==1)
                    invNu=x(:,i)./nu; mu_invNu=mu * invNu;
                    Ax(ind_i,1)=A(ind_i,:)*invNu -repmat(mu_invNu, m_i, 1);
                else
                    Ax(ind_i,1)=A(ind_i,:)*x(:,i)-repmat(mu*x(:,i), m, 1);
                    Ax(ind_i,1)=Ax./nu(ind_i,1);
                end
            end

            % aa= - diag(y) * (A * x + c)
            vec_sc=zeros(m,1);
            for i=1:k
                ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
                vec_sc(ind_i,1)=c(i);
            end
            aa=- y.*(Ax+ vec_sc);

            % fun_s is the logistic loss at the search point
            bb=max(aa,0);
            fun_x= sum(sum ( log( exp(-bb) +  exp(aa-bb) ) + bb ) ) / m;

            r_sum=(norm(v,'fro')^2 + norm(c-sc,2)^2) / 2;
            l_sum=fun_x - fun_s - sum(sum(v.* g)) - (c-sc)* gc';

            if (r_sum <=1e-20)
                bFlag=1; % this shows that, the gradient step makes little improvement
                break;
            end

            % the condition is fun_x <= fun_s + <v, g> + <c ,gc>
            %                           + L/2 * (<v,v> + <c-sc,c-sc> )
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                % fprintf('\n L=%5.6f',L);
            end
        end

        % --------------------------- step 3 ---------------------------
        % update alpha and alphap, and check whether converge
        alphap=alpha; alpha= (1+ sqrt(4*alpha*alpha +1))/2;

        ValueL(iterStep)=L;

        xxp=x-xp;   ccp=c-cp;

        funVal(iterStep)=fun_x;

        if (bFlag)
            % fprintf('\n The program terminates as the gradient step changes the solution very small.');
            break;
        end

        switch(opts.tFlag)
            case 0
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <= opts.tol)
                        break;
                    end
                end
            case 1
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <=...
                            opts.tol* funVal(iterStep-1))
                        break;
                    end
                end
            case 2
                if ( funVal(iterStep)<= opts.tol)
                    break;
                end
            case 3
                norm_xxp=norm(xxp,'fro');
                if ( norm_xxp <=opts.tol)
                    break;
                end
            case 4
                norm_xp=norm(xp,'fro');    norm_xxp=norm(xxp,'fro');
                if ( norm_xxp <=opts.tol * max(norm_xp,1))
                    break;
                end
            case 5
                if iterStep>=opts.maxIter
                    break;
                end
        end
    end
end

%% Adaptive line search scheme

if (opts.lFlag==1)

    lambda0=0;
    % a guess of the root

    bFlag=0; % this flag tests whether the gradient step only changes a little

    L=1/m; % the intial guess of the Lipschitz continuous gradient

    % assign xp with x, and Axp with Ax
    xp=x; Axp=Ax; xxp=zeros(n,k);
    cp=c;             ccp=zeros(1,k);
    % t is the upper bound of absolute value of x

    gamma=1;
    % we shall set the value of gamma = L,
    % and L is appropriate for the starting point

    for iterStep=1:opts.maxIter
        while (1)
            if (iterStep~=1)
                alpha= (-gamma+ sqrt(gamma*gamma + 4* L * gamma)) / (2*L);
                beta= (gamma - gamma* alphap) / (alphap * gamma + alphap* L * alpha);
                % beta is the coefficient for generating search point s

                s=x + beta* xxp;   sc=c + beta* ccp;
                As=Ax + beta* (Ax-Axp);
            else
                alpha= (-1+ sqrt(5)) / 2;  beta=0;
                s=x; sc= c;
                As=Ax;
            end

            % aa= - diag(y) * (A * s + sc)
            vec_sc=zeros(m,1);
            for i=1:k
                ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
                vec_sc(ind_i,1)=sc(i);
            end
            aa=- y.*(As+ vec_sc);

            % fun_s is the logistic loss at the search point
            bb=max(aa,0);
            fun_s= sum(sum ( log( exp(-bb) +  exp(aa-bb) ) + bb ) ) / m;

            % compute prob=[p_1;p_2;...;p_m]
            prob=1./( 1+ exp(aa) );

            % b= - diag(y) * (1 - prob)
            b= -y.*(1-prob) / m;

            gc=zeros(1,k);                     % the gradient of c
            for i=1:k
                ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
                gc(1,k)=sum(b(ind_i));
            end

            % compute g= AT b, the gradient of x
            for i=1:k
                ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group

                if (opts.nFlag==0)
                    tt =A(ind_i,:)'*b(ind_i,1);
                elseif (opts.nFlag==1)
                    tt= A(ind_i,:)'*b(ind_i,1) - sum(b(ind_i,1)) * mu';
                    tt=tt./nu(ind_i,1);
                else
                    invNu=b(ind_i,1)./nu(ind_i,1);
                    tt=A(ind_i,:)'*invNu - sum(invNu)*mu';
                end

                g(:,i)= tt;
            end

            % let s walk in a step in the antigradient of s to get v
            % and then do the L1/Lq-norm regularized projection
            v=s-g/L; cnew= sc- gc/L;

            % projection
            [xnew, lambda, zf_step]=ep21d(v, n, k, z, lambda0);
            lambda0=lambda;

            v=xnew-s;  % the difference between the new approximate solution x
            % and the search point s

            % compute Axnew = A *xnew: Ax_i= A_i * xnew_i
            for i=1:k
                ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
                m_i=ind(i+1)-ind(i);          % number of samples in the i-th group

                if (opts.nFlag==0)
                    Axnew(ind_i,1)=A(ind_i,:)* xnew(:,i);
                elseif (opts.nFlag==1)
                    invNu=xnew(:,i)./nu; mu_invNu=mu * invNu;
                    Axnew(ind_i,1)=A(ind_i,:)*invNu -repmat(mu_invNu, m_i, 1);
                else
                    Axnew(ind_i,1)=A(ind_i,:)*xnew(:,i)-repmat(mu*xnew(:,i), m, 1);
                    Axnew(ind_i,1)=Axnew./nu(ind_i,1);
                end
            end

            % aa= - diag(y) * (A * x + c)
            vec_sc=zeros(m,1);
            for i=1:k
                ind_i=(ind(i)+1):ind(i+1);     % indices for the i-th group
                vec_sc(ind_i,1)=cnew(i);
            end
            aa=- y.*(Axnew+ vec_sc);

            % fun_x is the logistic loss at the new approximate solution
            % xnew
            bb=max(aa,0);
            fun_x= sum(sum ( log( exp(-bb) +  exp(aa-bb) ) + bb ) ) / m;

            r_sum=(norm(v,'fro')^2 + norm(cnew-sc,2)^2) / 2;
            l_sum=fun_x - fun_s - sum(sum(v.* g)) - (cnew-sc)* gc';

            if (r_sum <=1e-20)
                bFlag=1; % this shows that, the gradient step makes little improvement
                break;
            end

            % the condition is fun_x <= fun_s + <v, g> + <c ,gc>
            %                           + L/2 * (<v,v> + <c-sc,c-sc>  + <t-s_t, t-s_t>)
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                % fprintf('\n L=%5.6f',L);
            end
        end

        gamma=L* alpha* alpha;    alphap=alpha;
        % update gamma, and alphap

        ValueL(iterStep)=L;

        tao=L * r_sum / l_sum;
        if (tao >=5)
            L=L*0.8;
        end
        % decrease the value of L

        xp=x;     Axp=Ax;
        x=xnew;   Ax=Axnew;
        cp=c;      c=cnew;
        % update x, t, c, and Ax

        xxp=x-xp;  ccp=c-cp;

        funVal(iterStep)=fun_x;

        if (bFlag)
            % fprintf('\n The program terminates as the gradient step changes the solution very small.');
            break;
        end

        switch(opts.tFlag)
            case 0
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <= opts.tol)
                        break;
                    end
                end
            case 1
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <=...
                            opts.tol* funVal(iterStep-1))
                        break;
                    end
                end
            case 2
                if ( funVal(iterStep)<= opts.tol)
                    break;
                end
            case 3
                norm_xxp=norm(xxp,'fro');
                if ( norm_xxp <=opts.tol)
                    break;
                end
            case 4
                norm_xp=norm(xp,'fro');    norm_xxp=norm(xxp,'fro');
                if ( norm_xxp <=opts.tol * max(norm_xp,1))
                    break;
                end
            case 5
                if iterStep>=opts.maxIter
                    break;
                end
        end
    end
end


%Tristan Ursell
%Relative Noise Transform
%(c) November 2012
%
%Iout=relnoise(Iin,sz,sigma);
%Iout=relnoise(Iin,sz,sigma,'field');
%[Iout,Ivar]=relnoise(Iin,sz,sigma,...);
%[Iout,Ivar,Imean]=relnoise(Iin,sz,sigma,...);
%
%Iin = the input image, of any numerical class.
%
%sz = (3 < sz < min(size(Iin))) is the size of the filter block used to
%calculate means and variances.  This value must be odd.
%
%sigma (sigma > 0) is the weighting parameter that defines the standard
%deviation relative to the filter block's standard deviation around which
%the center pixel will be Gaussian weighted. Setting sigma = 1 weights the
%current pixel using the STD of the current filter block. Lower values
%bring the current pixel closer to the mean, while high values are more
%tolerant of variations.  As sigma -> Inf, Iout = Iin.
%
%The field 'plot' will create an output plot comparing this transform to
%the original image, a Gaussian blur with STD = sz/2, and median filter
%with block size equal to sz.  At first glance, this filter appears similar
%to a median transform, but it does a better job of preserving local
%intensity extrema.  Comparison with the median filter requires the Image
%Processing Toolbox, but the rest of the script does not.
%
%The field 'disk' or 'square' will choose between using a disk or square
%filter block shape, where sz is the disk diameter or square side length.
%The default is square.
%
%The field 'custom' may be followed by a user-defined logical matrix or
%strel, e.g. relnoise(Iin,sz,sigma,'custom',strel('line',30,45)).  In this
%case 'sz' will be unused.
%
%Iout is the transformed output image.
%
%Ivar is the variance of the pixel intensities in the filter block at every
%point in the image -- essentially the spatially varying variance of the
%image.
%
%Imean is the mean smoothed image using the filter block, equivalent to a
%convolution averaging filter with the specified neighborhood.
%
%see also: wiener2  filter2
%
%Example:
%
%Iin=imread('spot_test.tif');
%
%Iout=relnoise(Iin,3,0.5,'square','plot');
% %OR
%Iout=relnoise(Iin,3,0.5,'custom',strel('line',30,0),'plot');
%
%figure;
%subplot(1,2,1)
%imagesc(Iout-double(Iin))
%title('What was removed from the original image.')
%axis equal tight
%box on
%
%subplot(1,2,2)
%imagesc(abs(fftshift(fft(Iout-double(Iin)))))
%title('FFT of difference between original and filtered images.')
%axis equal tight
%box on
%

function [varargout]=relnoise(Iin,sz,sigma,varargin)

%Nans
Inan=isnan(Iin);
if sum(Inan(:))>0
    error('Input matrix contains NaNs.')
end

%convert type
Iin=double(Iin);

%check filter size
if or(sz<1,sz>min(size(Iin)))
    error('The filter size is out of bounds.')
end

if mod(sz,2)~=1
    error('The filter size must be an odd integer.')
end

%parse field input
f1=find(strcmp('plot',varargin),1);
f2=find(strcmp('disk',varargin),1);
f3=find(strcmp('custom',varargin),1);

%choose plot option
if ~isempty(f1)
    plotq=1;
else
    plotq=0;
end

%choose filter type
if ~isempty(f3)
    hood_temp=varargin{f3+1};
    if strcmp(class(hood_temp),'strel')
        hood=hood_temp.getnhood;
    else
        hood=hood_temp;
    end

    sz=round(mean(size(hood)));
elseif ~isempty(f2)
    %disk filter block
    Xdisk = ones(sz,1)*(-(sz-1)/2:(sz-1)/2);
    Ydisk = (-(sz-1)/2:(sz-1)/2)'*ones(1,sz);
    Zdisk = sqrt(Xdisk.^2 + Ydisk.^2);

    hood=zeros(sz,sz);
    hood(Zdisk<=(sz-1)/2)=1;
else
    %square filter block
    hood=ones(sz,sz);
end

%convert hood class
hood=single(hood);

%calcualte means and variances
hood_sz=sum(hood(:));

%perform convolultion and normalization
Imean0=conv2(Iin,hood,'same')/hood_sz;
Inorm=conv2(ones(size(Iin)),hood,'same')/hood_sz;
Imean=Imean0./Inorm;
Ivar=conv2(Iin.^2,hood,'same')./Inorm*1/hood_sz-Imean.^2;

%compute weight matrix
W=exp(-(Iin-Imean).^2./(2*sigma^2*Ivar));

%correct for zero variance pixels
W(Ivar==0)=0;

%compute output image
if sigma==0
    Iout=Imean;
else
    Iout=Iin.*W+(1-W).*Imean;
end

%handle outputs
if nargout==1
    varargout{1}=Iout;
elseif nargout==2
    varargout{1}=Iout;
    varargout{2}=Ivar;
elseif nargout==3
    varargout{1}=Iout;
    varargout{2}=Ivar;
    varargout{3}=Imean;
elseif nargout==0
else
    error('Incorrect number of output arguments.')
end

%plot comparisons
if plotq==1

    figure;
    subplot(2,2,1)
    imagesc(Iin)
    xlabel('X')
    ylabel('Y')
    box on
    axis equal tight
    title('Original Image')

    subplot(2,2,2)
    imagesc(Iout)
    xlabel('X')
    ylabel('Y')
    box on
    axis equal tight
    title(['Relative Noise Reduction (this filter), size = ' num2str(sz) ', sigma = ' num2str(sigma)])

    subplot(2,2,3)
    %look for image processing toolbox
    boxes=ver;
    gotit=strfind([boxes.Name],'Image Processing Toolbox');
    if ~isempty(gotit)
        Iout2=medfilt2(Iin,[sz,sz],'symmetric');
    else
        disp('Sorry, you do not have the Image Processing Toolbox.')
        disp('The medfilt2 comparison image cannot be generated.')
        disp('Disabling `plot` will stop this message.')
        Iout2=Imean;
    end
    imagesc(Iout2)
    xlabel('X')
    ylabel('Y')
    box on
    axis equal tight

    if ~isempty(gotit)
        title(['Median Filter of size ' num2str(sz)])
    else
        title(['Mean Filter of size ' num2str(sz)])
    end

    %construct Gaussian filter (without Image Processing Toolbox)
    sz2=round(3/2*sz);
    Xgauss = ones(sz2,1)*(-(sz2-1)/2:(sz2-1)/2);
    Ygauss = (-(sz2-1)/2:(sz2-1)/2)'*ones(1,sz2);
    Zgauss = exp(-(Xgauss.^2+Ygauss.^2)/(2*(sz/2)^2));
    Zgauss = Zgauss/sum(Zgauss(:));
    Iout3=conv2(Iin,Zgauss,'same');

    subplot(2,2,4)
    imagesc(Iout3)
    xlabel('X')
    ylabel('Y')
    box on
    axis equal tight
    title(['Gaussian Blur with STD = ' num2str(sz/2)])
    pause(0.1)
end


function [errRadians] = hyperSam(a, b)
% HYPERSAM Computes the spectral angle error (in radians) between two vectors
%
% Usage
%   [errRadians] = hyperSam(a, b)
% Inputs
%   a - Vector 1.
%   b - Vector 2.
% Outputs
%   errRadians - angle between vectors a and b in radians

[p,N] = size(a);
errRadians = zeros(1,N);
for k=1:N
    tmp = a(:,k);
    errRadians(k) = acos(dot(tmp, b)/ (norm(b) * norm(tmp)));
end
return;


function x = project_exp(v)
% PROJECT_EXP    Project points onto the exponential cone.
%
%   When v is a 1 x 3 vector, project_exp(v) is the projection
%   of v onto the exponential cone. When v is an n x 3 vector,
%   project_exp(v) projects each row of v onto the cone
%   in a vectorized fashion.
%
%   For reference, the exponential cone and its dual are given by
%     Kexp   = { (x,y,z) | ye^(x/y) <= z, y > 0 }
%     Kexp^* = { (u,v,w) | u < 0, -ue^(v/u) <= ew } cup { (0,v,w) | v,w >= 0 }

    r = v(:,1); s = v(:,2); t = v(:,3);
    x = nan(size(v));

    % v in cl(Kexp)
    idx = ( (s.*exp(r./s) <= t & s > 0) | (r <= 0 & s == 0 & t >= 0) );
    x(idx,:) = v(idx,:);

    % -v in Kexp^*
    idx = ( (-r < 0 & r.*exp(s./r) <= -exp(1).*t) | (-r == 0 & -s >= 0 & -t >= 0) );
    x(idx,:) = 0;

    % special case with analytical solution
    idx = (r < 0 & s < 0);
    x(idx,:) = v(idx,:);
    x(idx,2) = max(x(idx,2),0);
    x(idx,3) = max(x(idx,3),0);

    % minimize ||x - v||^2 subject to se^{r/s} = t via primal-dual Newton method
    % these components are computed serially, so much slower
    idx = find(isnan(x(:,1)));

    g     = @(w)   w(2)*exp(w(1)/w(2)) - w(3);
    gradg = @(w)   [ exp(w(1)/w(2)); exp(w(1)/w(2))*(1 - w(1)/w(2)); -1 ];

    alpha = 0.001; beta = 0.5;

    for i = 1:length(idx)
        disp('newton')
        u = v(idx(i),:)';
        u(2) = max(u(2),1); u(3) = max(u(3),1);
        y = 1; % dual variable

        r = @(w,z) [ w - v(idx(i),:)' + z*gradg(w); g(w) ];

        for iter = 1:100
            KKT = [ eye(3)+y*hessg(u), gradg(u) ; gradg(u)', 0 ];
            z = KKT \ -r(u,y);
            du = z(1:3);
            dy = z(4);

            % backtracking line search
            t = 1;
            ustep = u + t*du; ystep = y + t*dy;
            while ustep(2) < 0 || (norm(r(ustep, ystep)) > (1 - alpha*t)*norm(r(u, y)))
                t = beta*t;
                ustep = u + t*du; ystep = y + t*dy;
            end

            u = ustep; y = ystep;

            if abs(g(u)) < 1e-8 && norm(r(u,y)) <= 1e-8
                x(idx(i),:) = u;
                break;
            end
        end
    end
end

function h = hessg(w)
    r = w(1); s = w(2); t = w(2);
    h = exp(r/s)*[ 1/s,    -r/s^2,   0;
                   -r/s^2, r^2/s^3,  0;
                   0,      0,        0 ];
end


% Check whether a graph is regular, i.e. whether every node has the same degree.
%
% INPUTS: adjacency matrix, nxn
% OUTPUTS: Boolean, 0 or 1
%
% Note: Defined for unweighted graphs only.
% GB: last updated, Sep 23, 2012

function S=isRegular(adj)

S=false;

degs=sum(adj>0); % remove weights and sum columns

if degs == degs(1)*ones(size(degs)); S = true; end


function y = negLogLogitTransform(x, transform)

% NEGLOGLOGITTRANSFORM Constrains a parameter to be positive.
% FORMAT
% DESC contains commands to constrain parameters to be positive via
% log(1+exp(x)).
% ARG x : input argument.
% ARG y : return argument.
% ARG transform : type of transform, 'atox' maps a value into
% the transformed space (i.e. makes it positive). 'xtoa' maps the
% parameter back from transformed space to the original
% space. 'gradfact' gives the factor needed to correct gradients
% with respect to the transformed parameter.
%
% SEEALSO : expTransform, sigmoidTransform
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005, 2006, 2007

% OPTIMI

y = zeros(size(x));
limVal = 36;
switch transform
 case 'atox'
  index = find(x<-limVal);
  y(index) = eps;
  x(index) = NaN;
  index = find(x<limVal);
  y(index) = log(1+exp(x(index)));
  x(index) = NaN;
  index = find(~isnan(x));
  y(index) = x(index);
 case 'xtoa'
  index = find(x<limVal);
  y(index) = log(exp(x(index))-1);
  index = find(x>=limVal);
  y(index) = x(index);
 case 'gradfact'
  index = find(x>limVal);
  y(index) = 1;
  index = find(x<=limVal);
  y(index) = 1-exp(-x(index));
end


function p_mendousse = mendousse(x, t, source_freq, p0, c0, rho0, BonA, alpha_0)
%MENDOUSSE   Compute Mendousse's solution for nonlinear wave propagation in viscous media.
%
% DESCRIPTION:
%       mendousse calculates the propagation of a monofrequency plane wave
%       source in a thermoviscous medium with absorption given by
%       alpha_0*f^2. The solution is taken from Eq. (264) in Chapter 4 of
%       Nonlinear acoustics by Hamilton and Blackstock (2008). The infinite
%       sum is adaptively truncated when the moving average of the previous
%       five sum terms is smaller than a predefined convergence percentage
%       (0.01 percent by default).
%
% USAGE:
%       p_mendousse = mendousse(x, t, source_freq, p0, c0, rho0, BonA, alpha_0)
%
% INPUTS:
%       x           - position [m]
%       t           - time [s]
%       source_freq - frequency of plane wave [Hz]
%       p0          - source pressure [Pa]
%       c0          - medium sound speed [m/s]
%       rho0        - medium density [kg/m^3]
%       BonA        - nonlinearity parameter B/A
%       alpha_0     - absorption coefficient [dB/(MHz^2 cm)]
%
% OUTPUTS:
%       p_mendousse - calculated pressure field
%
% ABOUT:
%       author      - Bradley Treeby
%       date        - 21st February 2011
%       last update - 17th June 2011
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave 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 Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

% stop the summation when the current term contributes less than this amount
CONVERGENCE_PERCENTAGE = 0.01;

% minimum number of sum terms to use
MIN_NUM_SUM_TERMS = 20;

% number of pressure values to use in the moving average
MOVING_AV = 5;

% calculate the mach number
mach_num = p0/(rho0*c0^2);

% calculate the nonlinearity coefficient
beta = 1 + BonA/2;

% convert the absorption to nepers per meter
alpha_0 = db2neper(alpha_0, 2);

% calculate the absorption parameter
alpha = alpha_0*(2*pi*source_freq)^2;

% calculate the Goldberg number
goldberg_num = beta*mach_num*2*pi*source_freq/(c0*alpha);

% preallocate output variable
p_mendousse = zeros(1, length(x));

% calculate series
for loop_index = 1:length(x)

    % ---------------------------------------------------------------------
    % compute numerator summation
    % ---------------------------------------------------------------------

    % initialise loop variables
    p_term1 = 0;                    % pressure
    sum_term_contrib = 1;           % percentage contribution of current sum term
    n = 1;                          % summation index variable
    p_prev = zeros(1, MOVING_AV);   % moving average variable

    % loop the sum until it reaches an acceptable level of convergence
    while (sum_term_contrib > CONVERGENCE_PERCENTAGE) || (n < MIN_NUM_SUM_TERMS)

        % compute next sum term and add to the total
        p_term1 = p_term1 + (-1)^(n + 1) * n * besseli(n, goldberg_num/2) * exp(-n^2*alpha*x(loop_index)) * sin(n*2*pi*source_freq*t(loop_index));

        % update moving average of the contribution of sum term in a fifo
        % paradigm
        p_prev = circshift(p_prev, [0, 1]);
        p_prev(1) = p_term1;
        sum_term_contrib = 100*abs((p_term1 - mean(p_prev))/p_term1);

        % update summation variable
        n = n + 1;

    end

    % ---------------------------------------------------------------------
    % compute denominator summation
    % ---------------------------------------------------------------------

    % initialise loop variables
    p_term2 = 0;                    % pressure
    sum_term_contrib = 1;           % percentage contribution of current sum term
    n = 1;                          % summation index variable
    p_prev = zeros(1, MOVING_AV);   % moving average variable

    % loop the sum until it reaches an acceptable level of convergence
    while (sum_term_contrib > CONVERGENCE_PERCENTAGE) || (n < MIN_NUM_SUM_TERMS)

        % compute next sum term and add to the total
        p_term2 = p_term2 + (-1)^(n) * besseli(n, goldberg_num/2) * exp(-n^2*alpha*x(loop_index)) * cos(n*2*pi*source_freq*t(loop_index));

        % update moving average of the contribution of sum term in a fifo
        % paradigm
        p_prev = circshift(p_prev, [0, 1]);
        p_prev(1) = p_term2;
        sum_term_contrib = 100*abs((p_term2 - mean(p_prev))/p_term2);

        % update summation variable
        n = n + 1;

    end

    % ---------------------------------------------------------------------
    % apply scaling parameters and store the value of p
    % ---------------------------------------------------------------------

    % check if the numerator is zero
    if p_term1 ~= 0
        p_term1 = 4*p_term1./goldberg_num;
    else
        p_term1 = 0;
    end
    p_mendousse(loop_index) = p_term1 / (besseli(0, goldberg_num/2) + 2*p_term2);

end

% scale output by p0
p_mendousse = p0.*p_mendousse;


function [A,M] = assemblematrix3(node,elem,lumpflag)
%% ASSEMBLEMATRIX3 matrix for diffusion and reaction
%
% [A,M] = ASSEMBLEMATRIX3(node,elem) return the stiffness matrix and the
% mass matrix.
%
% [A,M] = ASSEMBLEMATRIX3(node,elem,1) return the stiffness matrix and the
% lumped mass matrix. Note that in the output M is a vector not a matrix. A
% sparse diagonal matrix using M as diaongal can be obtained by
% spdiags(M,0,N,N);
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

N = size(node,1);
A = sparse(N,N);
M = sparse(N,N);

%% Compute geometric quantities and gradient of local basis
[Dphi,volume] = gradbasis3(node,elem);

%% Assemble stiffness matrix
for i = 1:4
    for j = i:4
        Aij = dot(Dphi(:,:,i),Dphi(:,:,j),2).*volume;
        ii = double(elem(:,i));
        jj = double(elem(:,j));
        if (j==i)
            A = A + sparse(ii,jj,Aij,N,N);
        else
            A = A + sparse([ii;jj],[jj;ii],[Aij; Aij],N,N);
        end
        if (nargout > 1) && (~exist('lumpflag','var') || lumpflag == 0 )
            if (j==i)
                M = M + sparse(ii,jj,volume/10,N,N);
            else
                M = M + sparse([ii;jj],[jj;ii],[volume/20; volume/20],N,N);
            end
        end
    end
end

%% Assemble mass matrix by mass lumping
if exist('lumpflag','var') && lumpflag==1 && nargout > 1
    M = accumarray(elem(:),[volume;volume;volume;volume]/4,[N,1]);
end


function S = oblateSurfaceArea(elli, varargin)
%OBLATESURFACEAREA  Approximated surface area of an oblate ellipsoid.
%
%   S = oblateSurfaceArea(R1,R2)
%
%   Example
%   oblateSurfaceArea
%
%   See also
%   geom3d, ellipsoidSurfaceArea, prolateSurfaceArea
%

% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2015-07-03,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2015 INRA - Cepia Software Platform.

%% Parse input argument

if size(elli, 2) == 7
    R1 = elli(:, 4);
    R2 = elli(:, 5);

elseif size(elli, 2) == 1 && ~isempty(varargin)
    R1 = elli(:, 1);
    R2 = varargin{1};
end

assert(R1 < R2, 'First radius must be smaller than second radius');

% surface theorique d'un ellipsoide oblate
% cf http://fr.wikipedia.org/wiki/Ellipso%C3%AFde_de_r%C3%A9volution
e = sqrt(R2.^2 - R1.^2) ./ R2;
S = 2 * pi * R2.^2 + pi * R1.^2 * log((1 + e) ./ (1 - e)) ./ e;


function timer_cputime_test02 ( )

%*****************************************************************************80
%
%% TEST02 times the vectorized EXP routine.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 December 2005
%
%  Author:
%
%    John Burkardt
%
  n_log_min = 12;
  n_log_max = 22;
  n_min = 2^n_log_min;
  n_max = 2^n_log_max;
  n_rep = 5;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST02\n' );
  fprintf ( 1, '  Time vectorized operations:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '    y(1:n) =        x(1:n)  \n' );
  fprintf ( 1, '    y(1:n) = PI *   x(1:n)  \n' );
  fprintf ( 1, '    y(1:n) = sqrt ( x(1:n) )\n' );
  fprintf ( 1, '    y(1:n) = exp  ( x(1:n) )\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Data vectors will be of minimum size %d\n', n_min );
  fprintf ( 1, '  Data vectors will be of maximum size %d\n', n_max );
  fprintf ( 1, '  Number of repetitions of the operation: %d\n', n_rep );

  for func = 1 : 4

    for i_rep = 1 : n_rep

      for n_log = n_log_min : n_log_max

        n = 2^n_log;

        x = rand(n,1);

        time1 = cputime;

        if ( func == 1 )
          y(1:n) = x(1:n);
        elseif ( func == 2 )
          y(1:n) = pi * x(1:n);
        elseif ( func == 3 )
          y(1:n) = sqrt ( x(1:n) );
        elseif ( func == 4 )
          y(1:n) = exp ( x(1:n) );
        end

        time2 = cputime;

        delta(n_log,i_rep) = time2 - time1;

      end

    end

    fprintf ( 1, '\n' );
    fprintf ( 1, 'Test02 Results:\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, 'Vector Size  Rep #1        Rep #2        ' );
    fprintf ( 1, 'Rep #3        Rep #4        Rep #5\n' );
    fprintf ( 1, '\n' );

    for n_log = n_log_min : n_log_max
      n = 2^n_log;
      fprintf ( 1, '%10d', n );
      for j = 1 : n_rep
        fprintf ( 1, '%14f', delta(n_log,1:n_rep) );
      end
      fprintf ( 1, '\n' );
    end

  end

  return
end


% Chapter 3 - Complex Iterative Maps.
% Program 3a - Julia Sets.
% Copyright Birkhauser 2013. Stephen Lynch.

% Plot the Julia set J(0,1.1) (Figure 3.1(d)).
clear
k=15;niter=2^k;
x=zeros(1,niter);y=zeros(1,niter);
x1=zeros(1,niter);y1=zeros(1,niter);
a=0;b=1.1;
x(1)=real(0.5+sqrt(0.25-(a+1i*b)));
y(1)=imag(0.5+sqrt(0.25-(a+1i*b)));
% Check that the point is unstable.
isunstable=2*abs(x(1)+1i*y(1))

hold on
for n=1:niter
    x1=x(n);y1=y(n);
    u=sqrt((x1-a)^2+(y1-b)^2)/2;v=(x1-a)/2;
    u1=sqrt(u+v);v1=sqrt(u-v);
    x(n+1)=u1;y(n+1)=v1;
    if y(n)<b
        y(n+1)=-y(n+1);
    end
    if rand < .5
       x(n+1)=-u1;y(n+1)=-y(n+1);
    end
end

fsize=15;
plot(x,y,'k.','MarkerSize',1)
set(gca,'XTick',-1.6:0.4:1.6,'FontSize',fsize)
set(gca,'YTick',-1.2:0.4:1.2,'FontSize',fsize)
xlabel('Re z','FontSize',fsize)
ylabel('Im z','FontSize',fsize)
hold off

% End of Program 3a.


#!/usr/bin/octave -q
% Copyright 2018 Marc René Schädler
%
% This file is part of the mobile hearing aid prototype project
% The the mobile hearing aid prototype project 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.
%
% The mobile hearing aid prototype project 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 the mobile hearing aid prototype project. If not, see http://www.gnu.org/licenses/.

close all
clear
clc

[signal, fs] = audioread('/tmp/inout.wav');

analysis_length = 100; % ms

analysis_samples = floor(fs.*analysis_length./1000);
analysis_frames = size(signal,1)./analysis_samples;

level_in = -inf*ones(analysis_frames,2);
level_out = -inf*ones(analysis_frames,2);

freq_in = zeros(analysis_frames,2);
freq_out = zeros(analysis_frames,2);

analysis_window = hanning(analysis_samples);
analysis_window = analysis_window ./ sqrt(mean(analysis_window.^2));

for i=1:analysis_frames
  in1 = signal(1+(i-1).*analysis_samples:i.*analysis_samples,1) .* analysis_window;
  in2 = signal(1+(i-1).*analysis_samples:i.*analysis_samples,2) .* analysis_window;
  out1 = signal(1+(i-1).*analysis_samples:i.*analysis_samples,3) .* analysis_window;
  out2 = signal(1+(i-1).*analysis_samples:i.*analysis_samples,4) .* analysis_window;

  level_in(i,1) = 10*log10(mean(in1.^2));
  level_in(i,2) = 10*log10(mean(in2.^2));
  level_out(i,1) = 10*log10(mean(out1.^2));
  level_out(i,2) = 10*log10(mean(out2.^2));

  [~, maxidx_in1] = max(abs(fft(in1)));
  [~, maxidx_in2] = max(abs(fft(in2)));
  [~, maxidx_out1] = max(abs(fft(out1)));
  [~, maxidx_out2] = max(abs(fft(out2)));

  freq_in(i,1) = (maxidx_in1-1)./analysis_samples.*fs;
  freq_in(i,2) = (maxidx_in2-1)./analysis_samples.*fs;
  freq_out(i,1) = (maxidx_out1-1)./analysis_samples.*fs;
  freq_out(i,2) = (maxidx_out2-1)./analysis_samples.*fs;
end

freq_bins = logspace(log10(88.4),log10(16000),16);
freq_color = hsv(length(freq_bins)).*0.8;

figure('Position',[0 0 800 800],'Visible','on');
sample_levels = [-80 -60 -40 -20 0];

for i=1:2
  subplot(2,2,i);
  plot([0 0],[-100 10],'k');
  hold on;
  plot([-100  10],[  0   0],'k');
  plot([-100  10],[-100 10],'k');
  plot([-100 -10],[ -80 10],'k--');
  plot([-100 -30],[ -60 10],'k--');
  plot([-100 -50],[ -40 10],'k--');
  plot([-100 -70],[ -20 10],'k--');
  plot([-100 -90],[   0 10],'k--');

  out_mean = nan(length(freq_bins),length(sample_levels));

  h = [];
  for j=1:length(freq_bins)
    if j == 1
      freq_mask = freq_in(:,i) >= freq_bins(j)  & freq_in(:,i) < freq_bins(j+1);
    elseif j==length(freq_bins)
      freq_mask = freq_in(:,i) >= freq_bins(j-1) & freq_in(:,i) < freq_bins(j);
    else
      freq_mask = freq_in(:,i) >= freq_bins(j-1) & freq_in(:,i) < freq_bins(j+1);
    end
    x = level_in(freq_mask,i);
    y = level_out(freq_mask,i);
    validmask = x > -100 & y > -100 & ~isnan(x) & ~isnan(y) & ~isinf(x) & ~isinf(y);
    x = x(validmask);
    y = y(validmask);
    c = freq_color(j,:);
    if length(x) > 6
      p = polyfit(x,y,4);
      out_mean(j,:) = polyval(p,sample_levels);
    end
    scatter(x,y,20,c);
    if mod(j-1,2) == 0
      h(j) = plot(-90:10,polyval(p,-90:10),'Color',c);
    end
  end
  legend(h,num2str(round(freq_bins(2:2:end).')),'location','southeast');

  xlim([-100 10]);
  ylim([-100 10]);
  xlabel('Input / dB FS');
  ylabel('Output / dB FS');

  subplot(2,2,i+2);

  plot(log([50 16000]),[0 0],'k');
  hold on;

  level_color = hsv(length(sample_levels)).*0.8;

  h = [];
  for j=1:length(sample_levels)
    c = level_color(j,:);
    plot(log(freq_bins(1:end-1)),sample_levels(j).*ones(length(freq_bins)-1,1),'--','Color',c);
    h(j) = plot(log(freq_bins),out_mean(:,j),'-','Color',c);
  end

  xlim(log([50 16000]));
  ylim([-100 10]);
  xlabel('Frequency / Hz');
  ylabel('Levels / dB');
  set(gca,'xtick',log(freq_bins(2:2:end-1)));
  set(gca,'xticklabel',round(freq_bins(2:2:end-1)));
  legend(h,num2str(sample_levels.'),'location','southeast');
end

set(gcf,'PaperUnits','inches','PaperPosition',[0 0 8 8].*1.4);
print('-depsc2','-r300','inout.eps');


function ex9bvp
%EX9BVP  Example 9 of the BVP tutorial.
%   This boundary value problem is the subject of Chapter 8 of
%   C.C. Lin and L.A. Segel, Mathematics Applied to Deterministic
%   Problems in the Natural Sciences, SIAM, Philadelphia, 1988.
%   The ODEs
%
%      v' = (C - 1)/n
%      C' = (vC - min(x,1))/eta
%
%   are solved on the interval [0, lambda].  The boundary conditions
%   are v(0) = 0, C(lambda) = 1, and continuity of v(x) and C(x) at
%   x = 1.  Accordingly, this is a three-point BVP that must be
%   reformulated for solution with the two-point BVP solver BVP4C.
%   This reformulation involves introducing unknowns y_1(x) for v
%   and y_2(x) for C on the interval 0 <= x <= 1 and unknowns y_3(x)
%   for v and y_4(x) for C on 1 <= x <= lambda. A new independent
%   variable is introduced for the second interval, tau =
%   (x - 1)/(lambda - 1), so that it also ranges from 0 to 1. The
%   differential equations for the four unknowns are then solved
%   on the interval [0, 1].  The continuity conditions on v and C
%   become boundary conditions on the new unknowns.  A plot of v(x)
%   and C(x) on [0, lambda] involves plotting the new unknowns over
%   the subintervals.
%
%   The quantity of most interest is the emergent osmolarity Os =
%   1/v(lambda).  The parameters are related to another parameter
%   kappa by eta = lambda^2/(n*kappa^2).  Lin and Segel develop an
%   approximate solution for Os valid for "small" n.  Here the BVP is
%   solved for a range of kappa when lambda = 2 and n = 0.005.  The
%   computed Os is compared to the approximation of Lin and Segel.

% Copyright 1999, The MathWorks, Inc.

n = 5e-2;
lambda = 2;

options = [];   % place holder

sol = bvpinit(linspace(0,1,5),[1 1 1 1]);

fprintf(' kappa    computed Os  approximate Os \n')
for kappa = 2:5
  eta = lambda^2/(n*kappa^2);

  sol = bvp4c(@ex9ode,@ex9bc,sol,options,n,lambda,eta);

  K2 = lambda*sinh(kappa/lambda)/(kappa*cosh(kappa));
  approx = 1/(1 - K2);
  computed = 1/sol.y(3,end);
  fprintf('  %2i    %10.3f    %10.3f \n',kappa,computed,approx);
end

% v and C are computed separately on 0 <= x <= 1 and 1 <= x <= lambda.
% A change of independent variable is used for the second interval,
% which must then be undone to obtain the corresponding mesh.
x = [sol.x sol.x*(lambda-1)+1];
y = [sol.y(1:2,:) sol.y(3:4,:)];

clf reset
plot(x,y(1,:),x,y(2,:),'--')
legend('v(x)','C(x)')
title('A three-point BVP.')
xlabel(['\lambda = ',num2str(lambda),', \kappa = ',num2str(kappa),'.'])
ylabel('v and C')
shg

% --------------------------------------------------------------------------

function dydx = ex9ode(x,y,n,lambda,eta)
%EX9ODE  ODE function for Example 9 of the BVP tutorial.
dydx = [ (y(2) - 1)/n
         (y(1)*y(2) - x)/eta
         (lambda - 1)*(y(4) - 1)/n
         (lambda - 1)*(y(3)*y(4) - 1)/eta ];

% --------------------------------------------------------------------------

function res = ex9bc(ya,yb,n,lambda,eta)
%EX9BC  Boundary conditions for Example 9 of the BVP tutorial.
res = [ ya(1)
        yb(4) - 1
        yb(1) - ya(3)
        yb(2) - ya(4)];


function square_exactness_test01 ( )

%*****************************************************************************80
%
%% SQUARE_EXACTNESS_TEST01: product Gauss-Legendre rules for Legendre 2D integral.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 May 2014
%
%  Author:
%
%    John Burkardt
%
  a(1:2) = -1.0;
  b(1:2) = +1.0;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'SQUARE_EXACTNESS_TEST01\n' );
  fprintf ( 1, '  Product Gauss-Legendre rules for the 2D Legendre integral.\n' );
  fprintf ( 1, '  Density function rho(x) = 1.\n' );
  fprintf ( 1, '  Region: -1 <= x <= +1.\n' );
  fprintf ( 1, '  Region: -1 <= y <= +1.\n' );
  fprintf ( 1, '  Level: L\n' );
  fprintf ( 1, '  Exactness: 2*L+1\n' );
  fprintf ( 1, '  Order: N = (L+1)*(L+1)\n' );

  for l = 0 : 5

    n_1d = l + 1;
    n = n_1d * n_1d;
    t = 2 * l + 1;

    [ w, x, y ] = legendre_2d_set ( a, b, n_1d, n_1d );

    p_max = t + 1;
    legendre_2d_exactness ( a, b, n, x, y, w, p_max );

  end

  return
end


function varargout = harris(varargin)
% VL_HARRIS  Harris corner strength
%  H = VL_HARRIS(I,SI) computes the Harris corner strength of the image I
%  at ``integration'' scale SI.
%
%  The Harris strength [1] of a pixel is a statistic of the gradient
%  of the image integrated in a neighborhood of that pixel. This
%  neighborhood is a Gaussian window of variance SI.
%
%  In computing the Harris corner strength, there is a second scale
%  parameter, the ``derivation'' scale SD, which is the variance of
%  the Gaussian kernel used to pre-smooth the image I before computing
%  its gradient. SI and SD are independent parameters and VL_HARRIS(I,SI)
%  assumes that I is already smoothed at level SD.
%
%  VL_HARRIS(I,SI) uses Noble's variation [2] of the Harris score. If
%  SIGMAP and SIGMAM are respectively the biggest and smallest
%  eigenvalue of the structure tensor at a pixel, the score is given
%  by (SIGMAP*SIGMAM) / (SIGMAP+SIGMAM/2).  Let GAMMA = SIGMAM/SIGMAP
%  the ratio between the eigenvalues, which measures the degree of
%  anisotropy of the tensor and is always comprised in the range
%  [0,1].  Noble's score can be decomposed in two factors: the biggest
%  eigenvalue SIGMAP and the number
%
%    RHO = (2 GAMMA) / (GAMMA + 1).
%
%  RHO is another measure of isotropy that has value one for a
%  symmetric tensor and and zero for maximally anisotropic tensor.
%  [H,DETAILS] = VL_HARRIS(I,SIGMA) returns the additional structure
%  DETAILS with the following fields:
%
%    DETAILS.SIGMAP
%    DETAILS.RHO
%
%  VL_HARRIS(I,SI,ALPHA) uses Harris' original score [1], defined to be
%  SIGMAP*SIGMAM - ALPHA*(SIGMAP+SIGMAM)^2. This can be decomposed in
%  the factors SIGMAP^2 (note the square) and
%
%    RHO = GAMMA - ALPHA (1+GAMMA)^2.
%
%  Note that RHO is equal to -ALPHA for a maximally anisotropic
%  tensor. Typically ALPHA=0.04 and this is what is used by
%  VL_HARRIS(I,SI,[]).
%
%  REMARK. The gradient of the image I, used to compute the structure
%  tensor, is computed using central differencies. This means that a
%  function line [+1,-1,+1,...] has null Harris' score. This is
%  generally assumed to be a sampling artifact, and might be
%  avoided by oversampling the image.
%
%  EXAMPLE::
%    To extacts Harris points from image I:
%      idx = vl_localmax( vl_harris( vl_imsmooth( I, sd ), si ) ) ;
%      [i,j] = ind2sub( size(I), idx )
%
%  REFERENCES::
%    [1] C. Harris and M. Stephens, "A combined corner and edge detector,"
%    in Proceedings of The Fourth Alvey Vision Conference, pp. 147-151,
%    1988.
%
%    [2] J. A. Noble, "Finding corners, "Image Vision Computing, vol. 6,
%    no. 2, pp. 121-128, 1988.
%
%  See also: VL_HELP().
[varargout{1:nargout}] = vl_harris(varargin{:});


% -------------------------------------------------------------------------
% runduffsr.m
% Numerically solve the driven duffing oscillator with noise. Compute
% the averaged signal and noise amplitude spectra for varing noise
% strength. Plot signal-to-noise vs noise strength and time-series, phase
% space, well occupation distributions, and amplitude spectra for four
% chosen noise strengths.
% Dependencies: duff.m and noise.m
% -------------------------------------------------------------------------

clear all

tic % start timer

global p w

% -------------------------------------------------------------------------

X0 = [0 0]'; % initial conditions
t0 = 0; % initial time
tf = 1000; % final time
dt = 0.05; % time step
T = (t0:dt:tf); % time vector
options = [];

f = (1:length(T))/(length(T)*dt); % frequency
f = f(1:(ceil(length(T)/2))); % first half of frequency axis

win = hann(length(T)); % hanning window

wmax = 10; % noise cut-off frequency
alpha = 0.5; % strength of non-linear term
beta = 1; % strength of linear term
gam = 0.5; % damping strength
A = 0.38; % driving amplitude
w0 = 0.09; % driving frequency

N = 1000; % number of terms in noise sum

d = 0.05:0.05:2; % noise strength

% noise strength values for plots
dc = [0.1 0.5 1 2];

dw0 = w0*0.25; % integration range (w0+/- 25%)

M = 4; % number of terms in average (>= 2)

% initialize arrays
x = zeros(length(T),length(dc));
v = zeros(length(T),length(dc));
lc = zeros(1,length(dc));

Fd = zeros((1+length(T))/2,M);
Fdn = zeros((1+length(T))/2,M);

Sd = zeros((1+length(T))/2,length(d));
Sdn = zeros((1+length(T))/2,length(d));

Pd = zeros(1,length(d));
Pdn = zeros(1,length(d));

% -------------------------------------------------------------------------

for l = 1:length(d) % loop over noise strength array

n = d(l);

for j = 1:M % average amplitudes

p = unifrnd(0,2*pi,1,N); % random phases in noise
w = unifrnd(0,wmax,1,N); % random frequencies in noise

% numerically solve duffing oscillator
[t,y]=ode23(@duff,T,X0,options,gam,alpha,beta,A,w0,n);

% create x and v vectors at various noise strengths (d = 0.1,0.5,1.5,4)
% and get index for plots
if j == 1
    for i = 1:length(dc)
        if n == dc(i)
            x(:,i) = y(:,1);
            v(:,i) = y(:,2);
            lc(i) = l;
            break
        end
    end
end

% compute positive fft of windowed time-dependent signal and noise
% amplitudes
Fdtemp = fft(win.*y(:,1))/length(t); % signal fft
Fdntemp = fft(sqrt(n)*win.*noise(t)')/length(t); % noise fft

Fd(:,j) = Fdtemp(1:(ceil(length(t)/2))); % positive half of signal fft
Fdn(:,j) = Fdntemp(1:(ceil(length(t)/2))); % positive half of noise frequency

clear Fdtemp Fdntemp

end

% average frequency dependent signal and noise amplitude
Sd(:,l) = sum(abs(Fd'))/M; % averaged signal amplitude
Sdn(:,l) = sum(abs(Fdn'))/M; % averaged noise amplitude

i = 1;

% find signal and noise amplitude around driving frequency
for k = 1:length(f)
    if 2*pi*f(k) >= w0-dw0 && 2*pi*f(k) <= w0+dw0
        fr(i) = 2*pi*f(k); % frequency
        fd(i) = Sd(k,l); % signal amplitude
        fdn(i) = Sdn(k,l); % noise amplitude
        i = i + 1;
    end
end

% integrate signal and noise amplitude around driving frequency
Pd(l) = trapz(fr,fd); % signal "power"
Pdn(l) = trapz(fr,fdn); % noise "power"

clear fr fd fdn

end

% calculate and smooth snr (dB)
SNR = smooth(10*log(Pd./Pdn),0.1);

% -------------------------------------------------------------------------

figure(1) % plot snr vs noise strength
plot(d,SNR,'-ob')
xlabel('d'); ylabel('SNR (dB)');

% plots for various noise strengths (d = 0.1,0.5,1.5,4)
figure(2) % plot time-series
subplot(4,1,1)
plot(t,x(:,1))
xlabel('t'); ylabel('x');
subplot(4,1,2)
plot(t,x(:,2))
xlabel('t'); ylabel('x');
subplot(4,1,3)
plot(t,x(:,3))
xlabel('t'); ylabel('x');
subplot(4,1,4)
plot(t,x(:,4))
xlabel('t'); ylabel('x');

figure(3) % plot phase-space
subplot(2,2,1)
plot(x(:,1),v(:,1))
xlabel('x'); ylabel('v');
subplot(2,2,2)
plot(x(:,2),v(:,2))
xlabel('x'); ylabel('v');
subplot(2,2,3)
plot(x(:,3),v(:,3))
xlabel('x'); ylabel('v');
subplot(2,2,4)
plot(x(:,4),v(:,4))
xlabel('x'); ylabel('v');

figure(4) % plot histogram of well distribution
subplot(2,2,1)
hist(x(:,1),100)
xlabel('x');
subplot(2,2,2)
hist(x(:,2),100)
xlabel('x');
subplot(2,2,3)
hist(x(:,3),100)
xlabel('x');
subplot(2,2,4)
hist(x(:,4),100)
xlabel('x');

figure(5) % plot noise subtracted amplitude spectra
plot(2*pi*f,Sd(:,lc(1))-Sdn(:,lc(1)),2*pi*f,Sd(:,lc(2))-Sdn(:,lc(2)),...
     2*pi*f,Sd(:,lc(3))-Sdn(:,lc(3)),2*pi*f,Sd(:,lc(4))-Sdn(:,lc(4)))
legend('d = 0.1','d = 0.6','d = 1.8','d = 2.4')
xlabel('\omega'); ylabel('|A|');

toc % end timer