function [accel,C,S]=EGM08EarthAccel(rVec,accelOptions,M,TT1,TT2,effectsToInclude,EOP,C,S)
%%EGM08EARTHACCEL Get acceleration due to gravity from the Earth. This can
%            be a simple J2 model in a generic (not rigorously defined)
%            Earth-centered Earth-fixed (ECEF) or Earth-centered inertial
%            (ECI) coordinate system, or it can be more rigorously
%            defined in the International Terrestrial Reference System
%            (ITRS) or the Geocentric Celestial Reference System (GCRS),
%            accounting for effects such as polar motion, tides, and the
%            drift of the coefficients over time. The EGM2008 acceleration
%            model is used for parameters.
%
%INPUTS: rVec A 3XN (or 6XN) set of vectors of position (and velocity) in
%             meters in the same coordinate system as desired for the
%             output as specified by the parameter accelOptions. This is
%             the set of N positions where the acceleration due to the
%             Earth's gravity is desired. The velocity component is only
%             used if accelOptions specified an Earth-fixed coordinate
%             system. Specifically, if accelOptions is 0, 3, or 5. If a 3XN
%             vector is provided, but the velocity component is required,
%             the extra three elements are taken to be all zeros.
% accelOptions An optional parameter indicating the coordinate system and
%             options for the acceleration. Possible values are
%             0 (The default if omitted) The acceleration is found in a
%               generic ECEF coordinate system using either a Keplerian
%               model (if M=1) the J2 gravitational model (if M=2, the
%               default) with J2 given by the corresponding coefficient
%               from the zero-tide EGM2008 model without correcting for
%               polar motion, other tides, or the drift of the coefficients
%               over time. It is assumed that the rotation axis is aligned
%               with the z axis. Being an accelerating coordinate system,
%               Newtonian corrections for the Coriolis effect are used.
%               Values M>=3 are invalid. No Earth orientation parameters
%               are used. The time is also not used and neither is the
%               effectsToInclude nor C and S.
%             1 The same as 0 but in a generic Earth-centered inertial
%               coordinate system, meaning that the Coriolis effect is not
%               taken into account.
%             2 The acceleration is found using the first M elements of the
%               EGM2008 model in GCRS coordinates. The additional effects
%               accounted for (beyond just using a zero-tide model) are
%               determined by the effectsToInclude boolean vector. If C and
%               S are not provided, then the getEGMGravCoeffs function is
%               used. Earth orientation parameters are used, including the
%               length-of-day (LOD) parameter for the rotation rate of the
%               Earth.
%             3 The same as 2 but in ITRS coordinates, meaning that a
%               Newtonian Coriolis term is added to the coefficients,
%               because it is an accelerating coordinate system.
%           M The number of terms in the EGM2008 model to include. If
%             accelOptions=0 or accelOptions=1, then M chooses between
%             Keplerian, or J2 models. Otherwise, the number indicates
%             the highest order of the full EGM2008 model used. If omitted,
%             or an empty matrix is passed, a default value of 2 is used
%             for accelOptions=0 or 1 and a default of 3 is used for
%             accelOptions=2 or 3. If Inf or another number larger than the
%             highest coefficient order in the EGM2008 model is passed,
%             then the total number of coefficients in the EGM2008 model is
%             used.
%     TT1,TT2 Two parts of a Julian date given in terrestrial time (TT).
%             The units of the date are days. The full date is the sum of
%             both terms. The date is broken into two parts to provide more
%             bits of precision. It does not matter how the date is split.
%             The date is only used for accelOptions=2-3. Otherwise it can
%             be omitted or empty matrices can be passed.
% effectsToInclude A boolean vector indicating which effects are to be
%             included (if accelOptions>1). If an element of the vector is
%             1, that means that the effect will be taken into account. If
%             omitted, the default is [1;1;0;0;0]; The elements of the
%             vector are:
%             1) The drift of the low-order coefficients over time, as
%                given by the getGravCoeffOffset4Drift function.
%             2) The effects of polar motion on the coefficients, as given
%                by the getAdjustedGravCoeffs4PolarMotion function. They
%                are added after tidal effects (if any).
%             3) The effects of solid Earth tides as given by the
%                gravSolidTideOffset function.
%             4) The effects of pole tides as given by the
%                gravPoleTideOffset function.
%             5) The effects of ocean tides as given by the
%                gravOceanTideOffset function.
%         EOP A structure containing the Earth orientation parameters at
%             the given time. If omitted or an empty matrix is passed, the
%             values from the getEOP function are used. These are not used
%             if accelOptions=0 or 1. The elements of the structure are:
%             xpyp These are the polar motion coordinates in radians
%                  including the effects of tides and librations.
%             dXdY The celestial pole offsets with respect to the IAU
%                  2006/2000A precession/nutation model in radians.
%             deltaTTUT1 The difference between TT and UT1 in seconds
%              LOD The difference between the length of the day using TT
%                  and the length of the day in UT1. This is an
%                  instantaneous parameter (a derivative). The units are
%                  seconds.
%              C,S Optionally, the TIDE FREE EGM2008 coefficients with
%                  adjType=0 (the default) as obtained from the
%                  getEGMGravCoeffs function. Passing these saves a call to
%                  the getEGMGravCoeffs function and speeds up multiple
%                  calls to this function. These parameters are ignored if
%                  accelOptions=0 or 1.
%
%OUTPUTS: accel A 3XN matrix of the N accelerations due to gravity of the
%               Earth in meters per second squared in the specified
%               coordinate system (one for each input rVec).
%           C,S Values of the tide-free EGM2008 spherical harmonic
%               coefficients that can be passed to subsequent calls of this
%               function with the same options). Note that C and S are
%               modified (and then changed back), so care must be taken
%               with multithreading. Emptyt matrices are returned if
%               accelOptions=0 or accelOptions=1;
%
%For simple models, many parameters can be omitted.
%The J2 model in an ECEF system can be obtained using
%accel=EGM08EarthAccel(rVec)
%The function can be used for the Keplerian model in an ECEF system using
%accel=EGM08EarthAccel(rVec,0,1)
%or in an ECI system using
%accel=EGM08EarthAccel(rVec,1,1)
%The J2 model can be obtained in an ECI system using
%accel=EGM08EarthAccel(rVec,1,2)
%
%The J2 gravitational model is derived in Appendix E of [1].
%The Coriolis and centrifugal force models due to the use of non-inertial
%coordinate systems are derived from Appendix A of the same document.
%The various other effects are discussed in other sections.
%
%REFERENCES:
%[1] D. F. Crouse, "An Overview of Major Terrestrial, Celestial, and
%    Temporal Coordinate Systems for Target Tracking," Formal Report, Naval
%    Research Laboratory, no. NRL/FR/5344--16-10,279, 10 Aug. 2016, 173
%    pages.
%
%March 2015 David F. Crouse, Naval Research Laboratory, Washington D.C.
%incorporating elements from a Coriolis correction by David Karnick.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<2||isempty(accelOptions))
    accelOptions=0;
end

if(nargin<3||isempty(M))
    if(accelOptions==0||accelOptions==1)
        M=2;
    else
        M=3;
    end
end
%If someone passes a number greater than the total number of coefficients,
%then just limit it to the total number in the EGM2008 model.
M=min(2190,M);

%Universal gravitational constant times the mass of the Earth
GM=Constants.EGM2008GM;

%Semi-major axis of the Earth
a=Constants.EGM2008SemiMajorAxis;

%The rotation rate of the Earth in radians per second.
omega=Constants.EGM2008EarthRotationRate;

%Check for the easy cases Keplerian or J2.
if(accelOptions==0||accelOptions==1)
    r=rVec(1:3,:);%Positions
    if(size(rVec,1)>3)
        v=rVec(4:6,:);%Velocities.
    else
        v=zeros(3,size(rVec,2));
    end

    rMag=sqrt(sum(r.*r,1));

    %Newton's law for a point or sphere.
    aNewton=-bsxfun(@times,(GM./rMag.^2),bsxfun(@rdivide,r,rMag));

    switch(M)
        case 1%Simple Keplerian dynamics.
            accel=aNewton;
        case 2%The J2 dynamic model
            %Putting this in explicitly saves a call to getEGMGravCoeffs
            %for just one parameter. This is the zero-tide value.
            C20Bar=-0.484169317366974e-03;
            C20=C20Bar*sqrt(5);
            J2=-C20;

            temp=5*r(3,:).^2./rMag.^2;
            %First-order oblateness correction.
            aOblateness=-bsxfun(@times,((3*GM*a.^2*J2./(2*rMag.^5))),[r(1,:).*(1-temp);
                                                                     r(2,:).*(1-temp);
                                                                     r(3,:).*(3-temp)]);

            accel=aNewton+aOblateness;
        otherwise
            error('Invalid value of M for the chosen accelOptions value')
    end

    %If Coriolis terms should be added due to the rotation of the
    %Earth.
    if(accelOptions==0)
        %The rotation vector for the Earth is
        %Omega=[0;0;1]*omega;
        %and the Coriolis and centrifugal forces to add to accel are
        %aCoriolis=-2*bsxfun(@cross,Omega,v);
        %aCentrifugal=-bsxfun(@cross,Omega,bsxfun(@cross,Omega,r));

        %However, it is faster to add the components directly:
        accel(1,:)=accel(1,:)+2*omega*v(2,:)+omega^2*r(1,:);
        accel(2,:)=accel(2,:)-2*omega*v(1,:)+omega^2*r(2,:);
    end
    C=[];
    S=[];
    return;
end

%Get the spherical harmonic coefficients up to the requested order if they
%are not provided.
if(nargin<8||isempty(C))
    isTideFree=true;
    modelType=0;
    [C,S]=getEGMGravCoeffs(M,isTideFree,modelType);
end

if(nargin<6||isempty(effectsToInclude))
    effectsToInclude=[1;1;0;0;0];
end

if(nargin<7||isempty(EOP))
    [JulUTC1,JulUTC2]=TT2UTC(TT1,TT2);
    [xpyp,dXdY,~,deltaTTUT1,LOD]=getEOP(JulUTC1,JulUTC2);
else
    xpyp=EOP.dxdy;
    dXdY=EOP.dXdY;
    deltaTTUT1=EOP.deltaTTUT1;
    LOD=EOP.LOD;
end

%The second one is added after all of the others.
numDelta=sum(effectsToInclude)-effectsToInclude(2);
deltaC=cell(numDelta,1);
deltaS=cell(numDelta,1);

curDelta=1;
if(effectsToInclude(1)~=false)
    %Get the offsets to C and S due to the drift of the coefficients.
    [deltaC{curDelta},deltaS{curDelta}]=getGravCoeffOffset4Drift(TT1,TT2,0);
    curDelta=curDelta+1;
end

if(effectsToInclude(3)~=false)
    %Compute the offsets due to solid Earth tides.

    [TDB1,TDB2]=TT2TDB(TT1,TT2);%Get approximate TDB.
    %Sun Position with respect to Earth.
    SunGCRSPosVel=readJPLEphem(TDB1,TDB2,11,3);
    rSunITRS=GCRS2ITRS(SunGCRSPosVel(1:3),TT1,TT2,deltaTTUT1,xpyp,dXdY);

    %Moon position with respect to Earth.
    MoonGCRSPosVel=readJPLEphem(TDB1,TDB2,10,3);
    rMoonITRS=GCRS2ITRS(MoonGCRSPosVel(1:3),TT1,TT2,deltaTTUT1,xpyp,dXdY);

    [deltaC{curDelta},deltaS{curDelta}]=gravSolidTideOffset(rMoonITRS,rSunITRS,TT1,TT2);
    curDelta=curDelta+1;
end

if(effectsToInclude(4)~=false)
    [deltaC{curDelta},deltaS{curDelta}]=gravPoleTideOffset(TT1,TT2,xpyp);
    curDelta=curDelta+1;
end

if(effectsToInclude(5)~=false)
    [deltaC{curDelta},deltaS{curDelta}]=gravOceanTideOffset(TT1,TT2);
    curDelta=curDelta+1;
end

%Find out the total number of coefficients in C and S that need to be
%changed --this is the maximum number of elements in the deltas.
numCoeffChanged=0;
for curDelta=1:numDelta
    curLength=length(deltaC{curDelta});
    if(curLength>numCoeffChanged)
        numCoeffChanged=curLength;
    end
end

if(length(C)<numCoeffChanged)
    numCoeffChanged=length(C);
end

%Now, save the elements in C and S, so that they can be restored for the
%return value when the function exits.
CSaved=C(1:numCoeffChanged);
SSaved=S(1:numCoeffChanged);

%Now, add in all of the effects, except the effects of polar motion on the
%coefficients.
for curDelta=1:numDelta
    numOffset=length(deltaC{curDelta});
    num2Change=min(numOffset,numCoeffChanged);

    C(1:num2Change)=C(1:num2Change)+deltaC{curDelta}(1:num2Change);
    S(1:num2Change)=S(1:num2Change)+deltaS{curDelta}(1:num2Change);
end

%Add in the effects of polar motion. This just changes the C21 and S21
%elements, which would otherwise be zero.
if(effectsToInclude(2)~=false)
    [~,~,C,S]=getAdjustedGravCoeffs4PolarMotion(C,S,TT1,TT2,true);
end

%Now, get the acceleration due to gravity in ITRS coordinates WITHOUT the
%Coriolis effect. This can be rotated to GCRS coordinates, if needed or
%have Coriolis terms added, if staying in this coordinate system. This
%requires getting the position in ITRS, spherical coordinates.

if(accelOptions~=3)%If r is not already in ITRS coordinates
   %Convert r (and v if present) into ITRS coordinates
   rVec=GCRS2ITRS(rVec,TT1,TT2,deltaTTUT1,xpyp,dXdY,LOD);
end

%Convert the position components into spherical coordinates for the
%spherHarmonicEval function.
r=rVec(1:3,:);%Positions
rSpher=Cart2Sphere(r);

[~,accel]=spherHarmonicEval(C,S,rSpher,a,GM);

%Now, if the acceleration is supposed to be in ITRS coordinates, then add
%the Coriolis terms. Otherwise, rotate it into GCRS coordinates.
if(accelOptions==3)
    %The output is in (approximate) ITRS coordinates, compute the Coriolis
    %terms.
    v=rVec(4:6,:);%The velocity in ITRS coordinates.

    %Get the axis of rotation in ITRS coordinates. This is the z-axis in
    %TIRS coordinates.
    omegaAxis=TIRS2ITRS([0;0;1],TT2,TT2,xpyp);

    %Modify the value of omega to deal with the LOD Earth orientation
    %parameter. This Equation is in Section IIIB of Crouse. The 86400 is
    %the number of seconds in a Julian day.
    omega=omega*(1-LOD/86400);

    %The rotation vector for the Earth
    Omega=omegaAxis*omega;

    aCoriolis=-2*bsxfun(@cross,Omega,v);
    aCentrifugal=-bsxfun(@cross,Omega,bsxfun(@cross,Omega,r));
    accel=accel+aCoriolis+aCentrifugal;
else
    %Rotate the output into GCRS coordinates. This is just a rotation (as
    %one would apply to position components). Thus, we do not want to pass
    %it as if it were a velocity input to this function.
    accel=ITRS2GCRS(accel,TT1,TT2,deltaTTUT1,xpyp,dXdY,LOD);
end

%Finally, restore the adjusted elements of C and S in case they are to be
%returned.
C(1:numCoeffChanged)=CSaved;
S(1:numCoeffChanged)=SSaved;
%Undo any changes from the getAdjustedGravCoeffs4PolarMotion function.
C(4)=0;
S(4)=0;

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 fj=CF_SVj(xt,vt,tau,mu,a,uj,bj,rho,sig,phi)
%--------------------------------------------------------------------------
%PURPOSE: implements the CF fj of Heston. Uses Heston's notations.
%--------------------------------------------------------------------------

xj = bj - rho.*sig.*phi.*i;
dj = sqrt( xj.^2 - (sig.^2).*( 2.*uj.*phi.*i - phi.^2 ) );
gj = ( xj+dj )./( xj-dj );
D  = ( xj+dj )./(sig.^2).* ( 1-exp(dj.*tau) )./( 1-gj.*exp(dj.*tau)  ) ;
xx = ( 1-gj.*exp(dj.*tau) )./( 1-gj );
C  = mu.*phi.*i.*tau + a./( sig.^2 ) .* ( (xj+dj) .* tau - 2.*log(xx) );
fj = exp( C + D.*vt + i.*phi.*xt );


function [cost, x, A, info] = test01(n, usestore)
% function [cost, x, A] = test01(n, usestore)
% All intputs are optional.
%
% Typical call:
%
% profile clear; profile on;
% test1(10000, true);
% profile off; profile report;
%
% If activated (search for 'work!' in the code):
% 'work!' is printed each time a matrix-vector product with A is computed.
% Observe how setting 'usestore' to true of false affects the number of
% products.
%

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, Dec. 30, 2012.
% Contributors:
% Change log:

    clc;
    reset(RandStream.getDefaultStream);
    randnfoo = randn(123456, 1); %#ok<NASGU>

    if ~exist('n', 'var') || isempty(n)
        n = 1042;
    end

    if ~exist('usestore', 'var') || isempty(usestore)
        usestore = true;
    end

    % Define the problem data
%     A = randn(n);
    A = magic(n)/n^3;
    A = (A+A')/2;

    % Create the problem structure
    problem.M = spherefactory(n);

    if usestore
        % These functions use the store capability
        problem.cost = @(x, store)    objective(A, x, store);
        problem.grad = @(x, store)    gradient (A, x, store);
        problem.hess = @(x, h, store) hessian  (A, x, h, store);
    else
        % These functions do not use the store capability
%         problem.cost = @(x)    objective(A, x, struct());
%         problem.grad = @(x)    gradient (A, x, struct());
        problem.costgrad = @(x) costgrad(A, x);
        problem.hess = @(x, h) hessian  (A, x, h, struct());
    end

    % Check consistency of cost, grad and hess.
    debug = 0;
    if debug
        checkgradient(problem);
        pause;
        checkhessian(problem);
        pause;
    end

    % Define a few (optional) options
    options.maxtime = 20; % [seconds]
    options.storedepth = 25;
    options.tolgradnorm = 1e-8;
    options.maxinner = 200;

%     options.stopfun = @stopfun;
    function stop = stopfun(problem, x, info, last)
        if mod(last, 150) == 0
            plot([info.time], [info.cost]);
            xlim([0 options.maxtime]);
            drawnow;
        end
        stop = false;
    end

    options.statsfun = @statsfun;
    function stats = statsfun(problem, x, stats)
        stats.pt = problem.M.hash(x);
    end

    % Solve
    x0 = (1:n)'; x0 = x0/norm(x0);
%     options.linesearch = @linesearch;
    options.linesearch = @linesearch_adaptive;
%     options.ls_max_steps = 10;
%     [x cost info] = steepestdescent(problem, x0, options);
    [x cost info] = conjugategradient(problem, x0, options);
    [x cost info] = trustregions(problem, [], options);
%     [x cost info] = pso(problem, [], options);
%     [x cost info] = neldermead(problem, [], options);

%     figure;
%     subplot(1, 2, 1);
%     semilogy([info.iter], [info.gradnorm], '.-');
%     subplot(1, 2, 2);
%     semilogy([info.time], [info.gradnorm], '.-');

    if isfield(info, 'linesearch')
        figure;
        lsstats = [info.linesearch];
        lscostevals = [lsstats.costevals];
        hist(lscostevals, min(lscostevals):max(lscostevals));
        title('Histogram of cost evaluations per line search');
%         keyboard;
    end

%     keyboard;

end

function [val store] = objective(A, x, store)

    if ~isfield(store, 'Ax')
        store.Ax = A*x; % disp('work!');
    end
    Ax = store.Ax;

    if ~isfield(store, 'val')
        store.val = -.5*(x'*Ax);
    end

    val = store.val;

end

function [grad store] = gradient(A, x, store)

    if ~isfield(store, 'Ax') || ~isfield(store, 'val')
        [~, store] = objective(A, x, store);
    end
    Ax = store.Ax;
    val = store.val;

    grad = -(2*val*x + Ax);

end

function [hess store] = hessian(A, x, h, store)

    if ~isfield(store, 'val')
        [~, store] = objective(A, x, store);
    end
    val = store.val;

    Ah = A*h; % disp('work!');
    hess = -(2*val*h + Ah);
    hess = hess - (x'*hess)*x;         % projection

end

function [cost grad] = costgrad(A, x)
    Ax = A*x;
    cost = -.5*(x'*Ax);
    if nargout == 2
        grad = -(2*cost*x + Ax);
    end
end


function lpp_to_polynomial_test ( )

%*****************************************************************************80
%
%% LPP_TO_POLYNOMIAL_TEST tests LPP_TO_POLYNOMIAL.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 September 2014
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'LPP_TO_POLYNOMIAL_TEST:\n' );
  fprintf ( 1, '  LPP_TO_POLYNOMIAL is given a Legendre product polynomial\n' );
  fprintf ( 1, '  and determines its polynomial representation.\n' );

  m = 2;
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Using spatial dimension M = %d:\n', m );

  for rank = 1 : 11

    l = comp_unrank_grlex ( m, rank );

    o_max = prod ( floor ( ( l(1:m) + 2 ) / 2 ) );
    [ o, c, e ] = lpp_to_polynomial ( m, l, o_max );

    label = sprintf ( '  LPP #%d = L(%d,X)*L(%d,Y) =', rank, l(1), l(2) );

    fprintf ( 1, '\n' );
    polynomial_print ( m, o, c, e, label );

  end

  return
end


% Two-input NAND gate sizing (GP)
% Boyd, Kim, Patil, and Horowitz, "Digital circuit optimization
% via geometric programming"
% Written for CVX by Almir Mutapcic 02/08/06
% (a figure is generated)
%
% This is an example taken directly from the paper:
%
%   Digital circuit optimization via geometrical programming
%   by Boyd, Kim, Patil, and Horowitz
%   Operations Research 53(6): 899-932, 2005.
%
% Solves the problem of choosing device widths w_i for the given
% NAND2 gate in order to achive minimum Elmore delay for different
% gate transitions, subject to limits on the device widths,
% gate area, power, and so on. The problem is a GP:
%
%   minimize   D = max( D_1, ..., D_k )  for k transitions
%       s.t.   w_min <= w <= w_max
%              A <= Amax, etc.
%
% where variables are widths w.
%
% This code is specific to the NAND2 gate shown in figure 19
% (page 926) of the paper. All the constraints and the objective
% are hard-coded for this particular circuit.

%********************************************************************
% problem data and hard-coded GP specs (evaluate all transitions)
%********************************************************************
N = 4;       % number of devices
Cload = 12;  % load capacitance
Vdd = 1.5;   % voltage

% device specs
NMOS = struct('R',0.4831, 'Cdb',0.6, 'Csb',0.6, 'Cgb',1, 'Cgs',1);
PMOS = struct('R',2*0.4831, 'Cdb',0.6, 'Csb',0.6, 'Cgb',1, 'Cgs',1);

% maximum area and power specification
Amax = 24;
wmin = 1;

% varying parameters for the tradeoff curve
Npoints = 25;
Amax = linspace(5,45,Npoints);
Dopt = [];

disp('Generating the optimal tradeoff curve...')
need_sedumi = strncmpi(cvx_solver,'sdpt',4);
if need_sedumi,
    warning('This model does not converge with SDPT3... switching to SeDuMi.');
end
for k = 1:Npoints
    fprintf(1,'  Amax = %5.2f:', Amax(k));
    cvx_begin gp quiet
        if need_sedumi,
            cvx_solver sedumi
        end

        % device width variables
        variable w(N)

        % device specs
        device(1:2) = PMOS; device(3:4) = NMOS;

        for num = 1:N
            device(num).R   = device(num).R/w(num);
            device(num).Cdb = device(num).Cdb*w(num);
            device(num).Csb = device(num).Csb*w(num);
            device(num).Cgb = device(num).Cgb*w(num);
            device(num).Cgs = device(num).Cgs*w(num);
        end

        % capacitances
        C1 = sum([device(1:3).Cdb]) + Cload;
        C2 = device(3).Csb + device(4).Cdb;

        % input capacitances
        Cin_A = sum([ device([2 3]).Cgb ]) + sum([ device([2 3]).Cgs ]);
        Cin_B = sum([ device([1 4]).Cgb ]) + sum([ device([1 4]).Cgs ]);

        % resistances
        R = [device.R]';

        % area definition
        area = sum(w);

        % delays and dissipated energies for all six possible transitions
        % transition 1 is A: 1->1, B: 1->0, Z: 0->1
        D1 = R(1)*(C1 + C2);
        E1 = (C1 + C2)*Vdd^2/2;
        % transition 2 is A: 1->0, B: 1->1, Z: 0->1
        D2 = R(2)*C1;
        E2 = C1*Vdd^2/2;
        % transition 3 is A: 1->0, B: 1->0, Z: 0->1
        % D3 = C1*R(1)*R(2)/(R(1) + R(2)); % not a posynomial
        E3 = C1*Vdd^2/2;
        % transition 4 is A: 1->1, B: 0->1, Z: 1->0
        D4 = C1*R(3) + R(4)*(C1 + C2);
        E4 = (C1 + C2)*Vdd^2/2;
        % transition 5 is A: 0->1, B: 1->1, Z: 1->0
        D5 = C1*(R(3) + R(4));
        E5 = (C1 + C2)*Vdd^2/2;
        % transition 6 is A: 0->1, B: 0->1, Z: 1->0
        D6 = C1*R(3) + R(4)*(C1 + C2);
        E6 = (C1 + C2)*Vdd^2/2;

        % objective is the worst-case delay
        minimize( max( [D1 D2 D4] ) )
        subject to
            area <= Amax(k);
            w >= wmin;
    cvx_end
    % display and store computed values
    fprintf(1,' delay = %3.2f\n',cvx_optval);
    Dopt = [Dopt cvx_optval];
end

% plot the tradeoff curve
plot(Dopt,Amax);
xlabel('Dmin'); ylabel('Amax');
disp('Optimal tradeoff curve plotted.')


%demoL2iPotts_Deconv
% Reconstruction of a blurred jump-sparse signal from incomplete measurements under
% Gaussian noise using the inverse L2-Potts functional

% load signal
groundTruth = loadPcwConst('sampleDec');
n = numel(groundTruth);

% create Gaussian kernel
K = convkernel('gaussian', 51, 6);
Afull = spconvmatrix(K, numel(groundTruth));

% select random measurements
idx = sort(randidx(n, 0.5)) ;
A = Afull(idx, :);

% create blurred and noisy signal (Gaussian noise)
fBlurry = A * groundTruth(:);
fNoisy = fBlurry + 0.05 * randn(size(fBlurry));

% reconstruction using the inverse L2-Potts problem
gamma = 0.03;
[u, dataError, nJumps, energy] = minL2iPotts(fNoisy, gamma, A);

% show result
showPotts(fNoisy, u, groundTruth, 'L^2-iPotts')


function KLDemo
% Illustration of information gains with Bayesian fusion
% FORMAT KLDemo)
%
%--------------------------------------------------------------------------
% This routine  illustrates the benefit of multimodal or Bayesian fusion in
% terms of conditional dependencies among parameters. In other words, it
% shows that even if one data modality contains no information about a
% particular set of parameters, it can help resolve uncertainty about
% another set and thereby disclose information contained in the other
% modality. This is illustrated here using a simple linear model with
% neuronal and haemodynamic parameters to show that EEG can provide some
% information gain, in relation to haemodynamic parameters.
%
% comment the orthogonalisation of the fMRI design matrix below to see the
% effect of conditional dependencies on the haemodynamic information gain
% afforded by EEG data
%__________________________________________________________________________
% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging

% Setup and preliminaries
%--------------------------------------------------------------------------
m    = 64;                         % number of observations
n    = 8;                          % number of parameters
j{1} = 1:n;                        % indices of both parameters
j{2} = 1:(n/2);                    % indices of neuronal parameters
j{3} = (1 + n/2):n;                % indices of haemodynamic parameters

% design matrices
%--------------------------------------------------------------------------
XEEG      = randn(m,n);
XMRI      = randn(m,n);

% make EEG design uninformative about haemodynamic parameters
%--------------------------------------------------------------------------
XEEG(:,j{3}) = 0;

% and orthogonalised fMRI design with respect to the EEG design
%--------------------------------------------------------------------------
% XMRI      = spm_orth(XMRI);

B         = randn(n,1);            % parameters
YEEG      = XEEG*B + randn(m,1)/8; % EEG data
YMRI      = XMRI*B + randn(m,1)/4; % MRI data

% model inversion using parametric empirical Bayes
%==========================================================================
PEEG{1}.X = XEEG;
PEEG{1}.C = {eye(m,m)};
PEEG{2}.X = zeros(n,1);
PEEG{2}.C = eye(n,n);

CEEG = spm_PEB(YEEG,PEEG,1);       % inversion using EEG data

PMRI{1}.X = XMRI;
PMRI{1}.C = {eye(m,m)};
PMRI{2}.X = zeros(n,1);
PMRI{2}.C = eye(n,n);

CMRI = spm_PEB(YMRI,PMRI,1);       % inversion using MRI data

PMRI{1}.X = XMRI;
PMRI{1}.C = {eye(m,m)};
PMRI{2}.X = CEEG{2}.E;             % Bayesian belief updating
PMRI{2}.C = CEEG{2}.C;             % using posteriors from EEG inversion

CMRE = spm_PEB(YMRI,PMRI,1);       % inversion using EEG and MRI data

% evaluate fMRI posteriors using Bayesian model reduction
%==========================================================================
[F,sE,sC] = spm_log_evidence(CMRE{2}.E,CMRE{2}.C,CEEG{2}.E,CEEG{2}.C,PEEG{2}.X,PEEG{2}.C);
CMRR.E    = sE;
CMRR.C    = sC;

%  evaluate information gain is entailed divergence
%==========================================================================
%  crucially, we will use the Bayesian model reduction estimate which means
%  we never have to actually invert the fMRI data
%--------------------------------------------------------------------------
for i = 1:length(j)          %  loop over different subsets of parameters

    % subsets
    %----------------------------------------------------------------------
    k      = j{i};

    % information gains
    %----------------------------------------------------------------------
    D(1,i) = spm_kl_normal(CEEG{2}.E(k),CEEG{2}.C(k,k),PEEG{2}.X(k),PEEG{2}.C(k,k));
    D(2,i) = spm_kl_normal(   CMRR.E(k),   CMRR.C(k,k),PEEG{2}.X(k),PEEG{2}.C(k,k));
    D(3,i) = spm_kl_normal(CMRE{2}.E(k),CMRE{2}.C(k,k),CEEG{2}.E(k),CEEG{2}.C(k,k));
    D(4,i) = spm_kl_normal(CMRE{2}.E(k),CMRE{2}.C(k,k),CMRI{2}.E(k),CMRI{2}.C(k,k));

    %  cow divergence between reduced and direct MRI posterior
    %----------------------------------------------------------------------
    D(5,i) = spm_kl_normal(CMRR.E(k),CMRR.C(k,k),CMRI{2}.E(k),CMRI{2}.C(k,k));

end

% illustrate results
%--------------------------------------------------------------------------
spm_figure('GetWin','Figure 1'); clf;
str{1} =  '0 -> EEG';
str{2} =  '0 -> MRI';
str{3} =  'EEG -> MRI & EEG';
str{4} =  'MRI -> MRI & EEG';

%  show for information gains
%--------------------------------------------------------------------------
for i = 1:4
    subplot(3,2,i), bar(D(i,:))
    title(str{i},'fontsize',16)
    set(gca,'XTickLabel',{'both','neuronal','haemodynamic'})
    axis square
end
a = axis;

%  show  divergence between direct and reduced posterior
%--------------------------------------------------------------------------
subplot(3,1,3),bar(D(5,:))
title('KL between estimated and direct fMRI','fontsize',12)
set(gca,'XTickLabel',{'both','neuronal','haemodynamic'})
axis (a), axis square


%% cunique
% Below is a demonstration of the features of the |cunique| function

%%
clear; close all; clc;

%% Syntax
% |[A_uni,ind1,ind2,Ac]=cunique(A);|

%% Description
% The |imx| function provides a figure window based GUI for 3D image
% segmentation

%% Examples

%%
% Plot settings
fontSize=20;

%% Example 1: Getting unique entries and occurance counts for 1xN arrays

n=15;
A=round(25*rand(1,n)); %Rounded random set in range 0-25
A(1)=A(end); %Force at least one double occurance for this example
A

%Get unique set and counts
[A_uni,ind1,ind2,Ac]=cunique(A)

%% Example 2: Getting unique entries and occurance counts for NxM arrays

n=5;
m=6;
A=round(25*rand(n,m)); %Rounded random set in range 0-25
A(1)=A(end); %Force at least one double occurance for this example
A

%Get unique set and counts
[A_uni,ind1,ind2,Ac]=cunique(A)

%%
% Visualizing input array and occurange counts

cFigure;
subplot(1,2,1);
title('The input array')
hold on;
imagesc(A);
image_numeric(A,[],0,fontSize);
axis tight; axis equal;
colormap(gca,gjet(max(A(:))));
icolorbar;

subplot(1,2,2);
title('The occurance counts')
hold on;
imagesc(Ac);
image_numeric(Ac,[],0,fontSize);
axis tight; axis equal;
colormap(gca,gjet(max(Ac(:))));
icolorbar;
drawnow;

%% Example 3: Getting unique entries and occurance counts for NxMx... arrays

n=3;
m=4;
l=2;

A=round(25*rand(n,m,l)); %Rounded random set in range 0-25
A(1)=A(end); %Force at least one double occurance for this example
A

%Get unique set and counts
[A_uni,ind1,ind2,Ac]=cunique(A)

%% Example 4: Using 'rows' option

n=5;
m=3;

A=round(25*rand(n,m)); %Rounded random set in range 0-25
A(1,:)=A(end,:); %Force at least one double row for this example
A

%Get unique set and counts
[A_uni,ind1,ind2,Ac]=cunique(A,'rows')

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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/>.


function blend_test05 ( )

%*****************************************************************************80
%
%% BLEND_TEST05 checks out BLEND_IJK_0D1
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 October 2008
%
%  Author:
%
%    John Burkardt
%
  m1 = 4;
  m2 = 3;
  m3 = 3;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'BLEND_TEST05\n' );
  fprintf ( 1, '  BLEND_IJK_0D1 interpolates data in a table,\n' );
  fprintf ( 1, '  from corner data.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The table is %d rows by %d columns by %d layers.\n', ...
    m1, m2, m3 );
%
%  Load data on the faces.
%
  for i = 1 : m1
    r = ( i - 1 ) / ( m1 - 1 );
    for j = 1 : m2
      s = ( j - 1 ) / ( m2 - 1 );
      for k = 1 : m3
        t = ( k - 1 ) / ( m3 - 1 );

        num_extreme = 0;
        if ( i == 1 | i == m1 )
          num_extreme = num_extreme + 1;
        end
        if ( j == 1 | j == m2 )
          num_extreme = num_extreme + 1;
        end
        if ( k == 1 | k == m3 )
          num_extreme = num_extreme + 1;
        end

        if ( num_extreme == 3 )
          x(i,j,k) = quad_rst ( r, s, t, 1 );
        else
          x(i,j,k) = 0.0;
        end

      end
    end
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Data given to BLEND_IJK_0D1:\n' );
  fprintf ( 1, '\n' );

  for k = 1 : m3
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Layer K = %d\n', k );
    fprintf ( 1, '\n' );
    for i = 1 : m1
      fprintf ( 1, '  %10f  %10f  %10f\n', x(i,1:m2,k) );
    end
  end

  x = blend_ijk_0d1 ( x, m1, m2, m3 );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Values interpolated by BLEND_IJK_0D1:\n' );
  fprintf ( 1, '\n' );

  for k = 1 : m3
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Layer K = %d\n', k );
    fprintf ( 1, '\n' );
    for i = 1 : m1
      fprintf ( 1, '  %10f  %10f  %10f\n', x(i,1:m2,k) );
    end
  end
%
%  Load all data.
%
  for i = 1 : m1
    r = ( i - 1 ) / ( m1 - 1 );
    for j = 1 : m2
      s = ( j - 1 ) / ( m2 - 1 );
      for k = 1 : m3
        t = ( k - 1 ) / ( m3 - 1 );
        x(i,j,k) = quad_rst ( r, s, t, 1 );
      end
    end
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Exact data:\n' );
  fprintf ( 1, '\n' );

  for k = 1 : m3
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Layer K = %d\n', k );
    fprintf ( 1, '\n' );
    for i = 1 : m1
      fprintf ( 1, '  %10f  %10f  %10f\n', x(i,1:m2,k) );
    end
  end

  return
end


function res = imProjectedArea(img, shifts, varargin)
% Total projected area of a 3D region in a given direction.
%
%   AREA = imProjectedArea(IMG, SHIFT)
%   IMG is a 3D binary image, SHIFT is a 1-by-3 row vector indicating the
%   shift between two voxels to test.
%
%   Example
%     % generate binary image of a 3D ellipsoid
%     elli = [50.12 50.23 50.34 50 35 20 30 40 50];
%     img = discreteEllipsoid(1:100, 1:100, 1:100, elli);
%     % compute projected area in main directions
%     D1 = imProjectedArea(img, [1 0 0]);
%     D2 = imProjectedArea(img, [0 1 0]);
%     D3 = imProjectedArea(img, [0 0 1]);
%     % compute projected area in a less common direction
%     D4 = imProjectedArea(img, [2 1 1]);
%
%   See also
%     imSurface, imProjectedDiameter

% ------
% Author: David Legland
% e-mail: david.legland@inrae.fr
% Created: 2015-05-27,    using Matlab 8.4.0.150421 (R2014b)
% Copyright 2015 INRAE - Cepia Software Platform.

dim = size(img);

dx = shifts(1);
dy = shifts(2);
dz = shifts(3);

dl = hypot(hypot(dx, dy), dz);
% vol = dx * dy * dz;

% iterate over pixels in image to count number of transitions
% count = 0;
% for z = 3:dim(3)-2
%     for y = 3:dim(1)-2
%         for x = 3:dim(2)-2
%             if img(y, x, z) ~= img(y+dy, x+dx, z+dz)
%                 count = count + 1;
%             end
%         end
%     end
% end

ix = 3:dim(2)-2;
iy = 3:dim(1)-2;
iz = 3:dim(3)-2;
count = sum(sum(sum( img(iy, ix, iz) ~= img(iy+dy, ix+dx, iz+dz) )));

% number of connected components
count = count / 2;

% normalize with line density
res = count * 1 / dl;


function out = innerProduct(f, g)
%INNERPRODUCT Compute the inner product of two DELTAFUN objects.
%   INNERPRODUCT(F, G) is the inner-product of two DELTAFUN object F and G.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

%% Trivial cases:
if ( isempty(f) || isempty(g) )
    out = [];
    return
end

% Make sure both arguments are DELTAFUNS: (At least one must already be)
if ( ~isa(g, 'deltafun') )
    g = deltafun(g, [], []);
elseif ( ~isa(f, 'deltafun') )
    f = deltafun(f, [], []);
end

%%
% The innerProduct has four contributions:
% < (f + df) , (g + dg ) > = <f, g> + <df, g> + <dg, f> + <df, dg>

% <df, dg>: If two delta functions are at the same location, compute the
% appropriate infinity and return:
[fcomIdx, gcomIdx] = sameDeltaLocs(f, g);
if ( any(fcomIdx) )
    % If there is an overlap of locations, extract the columns corresponding to
    % the first overlap:
    fIdx = find(fcomIdx, 1);
    gIdx = find(gcomIdx, 1);
    df = f.deltaMag(:,fIdx);
    dg = g.deltaMag(:,gIdx);

    % Extract, the first non-zero product term:
    pref = chebfunpref();
    tol = pref.deltaPrefs.deltaTol;
    df = df(find(abs(df) > tol, 1));
    dg = dg(find(abs(dg) > tol, 1));
    % Assign a signed infinity:
    out = inf * sign(df*dg);
    return
end

% Delta functions don't overlap: compute the components of the inner product:
funIP = innerProduct(f.funPart, g.funPart);                   % <f, g>
dfIP = deltaInnerProduct(g.funPart, f.deltaMag, f.deltaLoc);  % <g, df>
dgIP = deltaInnerProduct(f.funPart, g.deltaMag, g.deltaLoc);  % <f, dg>
out = funIP + dfIP + dgIP;

end

function deltaIP = deltaInnerProduct(g, deltaMag, deltaLoc)
%DELTAINNERPRODUCT   Inner product of a DELTAFUN G with delta functions.

% Handle the empty case:
if ( isempty(deltaLoc) )
    deltaIP = 0;
    return
end

% Compute the derivatives needed:
m = size(deltaMag, 1);
maxDiffOrder = m - 1;
G = zeros(m, length(deltaLoc));
G(1,:) = feval(g, deltaLoc);
for k = 1:maxDiffOrder
    g = diff(g);
    G(k+1,:) = feval(g, deltaLoc);
end

% The output is always a scalar double:
deltaIP = 0;
v = ones(maxDiffOrder+1, 1);
v(2:2:end) = -1;
for k = 1:length(deltaLoc)
    % Apply the definition of inner product with delta functions:
    % <sum(ai dirac^(i)(x-xk)), f(x)> = sum ai*(-1)^i f^(i)(xk)
    ipk = (v.*deltaMag(:,k)).' * G(:,k) ;
    deltaIP = deltaIP + ipk;
end

end


% DEMUSPSIVM1 Try the IVM on the USPS digits data with RBF kernel.

% IVM

dataSetName = 'usps';
experimentNo = 1;

randn('seed', 1e5)
rand('seed', 1e5)

[X, y, XTest, yTest] = mapLoadData(dataSetName);

capitalName = dataSetName;
capitalName(1) = upper(capitalName(1));

options = ivmOptions;
options.kern = {'rbf', 'lin', 'bias', 'white'};
options.numActive = 500;

mu = zeros(size(yTest));
varSigma = zeros(size(yTest));

tic
% Learn an IVM for each digit
for trainData = 0:9
  index = trainData+1;

  % Train the IVM.
  model = ivmRun(X, y(:, index), options);

  % Make prediction for this digit.
  [mu(:, index), varSigma(:, index)] = ivmPosteriorMeanVar(model, XTest);
  mu(:, index) = mu(:, index) + model.noise.bias;
  yPred = sign(mu(:, index));
  testError(index) = 1-sum(yPred==yTest(:, index))/size(yTest, 1);
  fprintf('Digit %d, test error %2.4f\n', trainData, testError(index));

  % Deconstruct IVM for saving.
  [kernStore{index}, noiseStore{index}, ...
   ivmInfoStore{index}] = ivmDeconstruct(model);
  save(['dem' capitalName num2str(experimentNo)], 'testError', ...
       'ivmInfoStore', 'kernStore', 'noiseStore')
end
overallTime = toc;

% Make prediction for all digits.
[void, yPred] = max(mu, [], 2);
[void, yTest] = max(yTest, [], 2);
yPred = yPred - 1;
yTest = yTest - 1;
overallError = 1 - sum(yPred == yTest)/size(yTest, 1);

confusMat = zeros(10);
for i = 1:length(yPred)
  confusMat(yPred(i)+1, yTest(i)+1) = confusMat(yPred(i)+1, yTest(i)+1) + 1;
end
save(['dem' capitalName num2str(experimentNo)], 'testError', ...
     'ivmInfoStore', 'kernStore', ...
     'noiseStore', 'overallError', ...
     'confusMat', 'overallTime');


% Distortionless data hiding based on integer wavelet transform (Watermark Extraction)
% Guorong Xuan   Jiang Zhu   Jidong Chen   Shi, Y.Q.   Zhicheng Ni   Wei Su
% Department of Computer Science, Tongji University, Shanghai
%
% This paper appears in: Electronics Letters
% Publication Date: 5 Dec 2002
% Volume: 38,  Issue: 25
% On page(s): 1646- 1648
% ISSN: 0013-5194

% August 19, 2007, 3:38pm
% updated 13 December, 2008
% By: Asad (asad_82@yahoo.com)

clear all;
close all;

load WatermarkInfo.mat;
disp('------------------------ Extraction -------------------------------');

% read image and convert to gray scale if necessary
% a = imread('Watermarked Image.bmp');
% get the single channel
% a = a(:,:,1);
a = watermarkedImage;

% STEP 1: perfom integer wavelet decomposition
LS = liftwave('cdf2.2','Int2Int');
[CA,CH,CV,CD] = lwt2(double(a),LS);

% STEP 2: extract the embeded signal from 5th bit of CH, CV and CD
index = 1;
% preallocate memory to fasten things
embededSignal = zeros(size(CH,1)*size(CH,2)+size(CV,1)*size(CV,2)+size(CD,1)*size(CD,2),1);
for i=1:size(CH,1)
    for j=1:size(CH,2)
        % for constructing binary image using CH
        if CH(i,j) ~= -ERROR_NUM
            binSeq = dec2bin(abs(CH(i,j)),8);
            if binSeq(BITPLANE_NUMBER) == '1'
                embededSignal(index,1) = 1;
            else
                embededSignal(index,1) = 0;
            end
            index = index + 1;
        end
    end
end

% extract the embeded signal from 5th bit of CV
for i=1:size(CV,1)
    for j=1:size(CV,2)
        % for constructing binary image using CV
        if CV(i,j) ~= -ERROR_NUM
            binSeq = dec2bin(abs(CV(i,j)),8);
            if binSeq(BITPLANE_NUMBER) == '1'
                embededSignal(index,1) = 1;
            else
                embededSignal(index,1) = 0;
            end
            index = index + 1;
        end
    end
end

% extract the embeded signal from 5th bit of CD
for i=1:size(CD,1)
    for j=1:size(CD,2)
        % for constructing binary image using CD
        if CD(i,j) ~= -ERROR_NUM
            binSeq = dec2bin(abs(CD(i,j)),8);
            if binSeq(BITPLANE_NUMBER) == '1'
                embededSignal(index,1) = 1;
            else
                embededSignal(index,1) = 0;
            end
            index = index + 1;
        end
    end
end

% STEP 3: extract header information
% obtain count1 of CH for use in aritmatic decoding
binNum = '';
for i=1:8
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
count1(1,1) = num;

binNum = '';
for i=9:16
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
count1(1,2) = num;

% obtain count2 of CV for use in aritmatic decoding
binNum = '';
for i=17:24
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
count2(1,1) = num;

binNum = '';
for i=25:32
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
count2(1,2) = num;

% obtain count3 of CD for use in aritmatic decoding
binNum = '';
for i=33:40
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
count3(1,1) = num;

binNum = '';
for i=41:48
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
count3(1,2) = num;

% obtain length of compressed CH
binNum = '';
for i=49:64
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
lenCH5 = num;

% obtain length of compressed CV
binNum = '';
for i=65:80
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
lenCV5 = num;

% obtain length of compressed CD
binNum = '';
for i=81:96
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
lenCD5 = num;

% obtain length of watermark
binNum = '';
for i=97:128
    if embededSignal(i,1) == 1
        binNum = strcat(binNum,'1');
    else
        binNum = strcat(binNum,'0');
    end
end
num = bin2dec(binNum);
lenWatermark = num;

% STEP 4: Extract the respective signals CH, CV, CD and decode(uncompress) to get the original bit sequence
HL = 128;
% construct sequence 1(CH) and decode
seq11 = embededSignal(HL+1:(HL+lenCH5));
CH5 = arithdeco(seq11,count1,size(CH,1)*size(CH,2));

% construct sequence 2(CV) and decode
seq22 = embededSignal((HL+lenCH5)+1:(HL+lenCH5+lenCV5));
CV5 = arithdeco(seq22,count2,size(CV,1)*size(CV,2));

% construct sequence 3(CD) and decode
seq33 = embededSignal((HL+lenCH5+lenCV5)+1:(HL+lenCH5+lenCV5+lenCD5));
CD5 = arithdeco(seq33,count3,size(CD,1)*size(CD,2));

% additional step is to verify the embeded watermark so extract it (not compared to the original but can be)
watermarkE = embededSignal((HL+lenCH5+lenCV5+lenCD5)+1:(HL+lenCH5+lenCV5+lenCD5+lenWatermark));
if isequal(watermark,watermarkE')
    disp('Watermark correct');
else
    disp('Watermark Error')
end
watermarkE = reshape(watermarkE,WM_SIZE,WM_SIZE);
figure,imshow(watermarkE,[]),title('Retrieved Watermark')

% STEP 5: Restore the Image i.e. remove the watermark and insert the
% uncompressed 5th bit data back into the image
CH5 = reshape(CH5,size(CH,1),size(CH,1));
CV5 = reshape(CV5,size(CV,1),size(CV,1));
CD5 = reshape(CD5,size(CD,1),size(CD,1));

neg = 0;

for x=1:size(CH,1)
    for y=1:size(CH,2)
        if CH(x,y) ~= -ERROR_NUM
            % restore 5th bit of CH
            neg = 0;
            if CH(x,y) < 0
                neg = 1;
            end
            binSeq = dec2bin(abs(CH(x,y)),8);
            if CH5(x,y) == 2
                binSeq(BITPLANE_NUMBER) = '1';
            else
                binSeq(BITPLANE_NUMBER) = '0';
            end
            num = bin2dec(binSeq);
            if neg == 1
                CH(x,y) = num * -1;
            else
                CH(x,y) = num;
            end
        end
        % restore 5th bit of CV
        if CV(x,y) ~= -ERROR_NUM
            neg = 0;
            if CV(x,y) < 0
                neg = 1;
            end
            binSeq = dec2bin(abs(CV(x,y)),8);
            if CV5(x,y) == 2
                binSeq(BITPLANE_NUMBER) = '1';
            else
                binSeq(BITPLANE_NUMBER) = '0';
            end
            num = bin2dec(binSeq);
            if neg == 1
                CV(x,y) = num * -1;
            else
                CV(x,y) = num;
            end
        end

        % restore 5th bit of CD
        if CD(x,y) ~= -ERROR_NUM
            neg = 0;
            if CD(x,y) < 0
                neg = 1;
            end
            binSeq = dec2bin(abs(CD(x,y)),8);
            if CD5(x,y) == 2
                binSeq(BITPLANE_NUMBER) = '1';
            else
                binSeq(BITPLANE_NUMBER) = '0';
            end
            num = bin2dec(binSeq);
            if neg == 1
                CD(x,y) = num * -1;
            else
                CD(x,y) = num;
            end
        end
    end
end

%STEP 6: Take inverse integer wavelet transform to get the original
%distortionless image back
restoredImage = ilwt2(CA,CH,CV,CD,LS);
figure,imshow(restoredImage,[]),title('Restored Image (Distortionless)');

difference = abs(double(originalImage) - double(restoredImage));
figure,imshow(difference,[]),title('Difference Image');


%==============================================================================
% (c) Lars Ruthotto 2010/12/27, see FAIR.2 and FAIRcopyright.m.
% http://www.mic.uni-luebeck.de/people/lars-ruthotto.html
%
% function [t,Yt,LSiter,LS] = ArmijoBacktrackFEM(objFctn,Yc,dY,Jc,dJ,varargin)
%
% Armijo linesearch with additional volume control to guarantee a
% diffeomorphic update of the current iterate.
%
% That is, the Armijo condition  of sufficient descent
%                        objFctn( Yc + t*dY ) <= Jc + t*LSreduction*(dJ*dY)
% is accompanied by the condition
%                        min(vol( Yc + t*dY )) > 0
% which garantees that the nodal grid Yc + t*dY is diffeomorphic.
%
% if min(vol( Yc + t*dY ))>0 && objFctn( Yc + t*dY ) <= Jc + t*LSreduction*(dJ*dY),
%   success!
% endIf
% t=2^-[0:10], else: t=0, no success
%
% Input:
%   objFctn    function handle to the objective function
%   Yc         current vlue of Y
%   dY         search direction
%   Jc         current function value
%   dJ         current gradient
%  varargin    optional parameters, see below
%
% Output:
%  t      steplength
%  Yt      new iterate
%  LSiter    number of steps performed
%  LS      flag for success
%
% see, e.g.,
%  @Book{NocWri1999,
%      author = {J. Nocedal and S. J. Wright},
%       title = {Numerical optimization},
%        year = {1999},
%   publisher = {Springer},
%     address = {New York},
%  }
% and
%  @article{2011-BMR,
%	Author = {Burger M., Modersitzki J., Ruthotto L. },
%	Publisher = {University of Muenster},
%	Title = {A hyperelastic regularization energy for image registration},
%	Year = {2011}
%  }
%
% see also ArmijoBacktrack.m (version for nodal grids)
%==============================================================================

function [t,Yt,LSiter,LS] = ArmijoDiffeomorphicFEM(objFctn,Yc,dY,Jc,dJ,varargin)

if nargin == 0,
  help(mfilename)
  return;
end;

LSMaxIter   = 10;           % max number of trials
LSreduction = 1e-4;         % slope of line
para        = [];

for k=1:2:length(varargin), % overwrites default parameter
  eval([varargin{k},'=varargin{',int2str(k+1),'};']);
end;

t = 1; descent =   dJ * dY;
LS = 0; DIFFEOMORPHIC = 1;
for LSiter =1:LSMaxIter,
  Yt = Yc + t*dY; 			       % compute test value Yt
  V =  volTetraGrid(para.Mesh,Yt,'matrixFree',1);
  DIFFEOMORPHIC = (min(V(:))>0);    % check if update is diffeomorphic
  if DIFFEOMORPHIC,
    Jt = objFctn(Yt);              % evalute objective function
    LS = (Jt<Jc + t*LSreduction*descent); % compare
    if LS, break; end;             % success, return
  end
  t = t/2;                         % reduce t
end;
if LS, return; end;                % we are fine
if not(DIFFEOMORPHIC),
    fprintf(['Line Search failed (No diffeomorphic update could be found)'...
        '- norm(dY)=%1.3e - break \n'],norm(dY));
elseif not(LS)
    fprintf(['Line Search failed (No sufficient descent found) '...
        '- norm(dY)=%1.3e - break\n'],norm(dY));
end
t = 0; Yt = Yc;        % take no action


function [model] = BCPF_IC(Y, varargin)
% Bayesian CP Factorization for Image Completion
% Author : Qibin Zhao  2014
%
% -----------------------------------------------------------------------
%  [model] = BCPF_IC(Y, 'PARAM1', val1, 'PARAM2', val2, ...)
%
%  INPUTS
%     Y              - Input tensor
%     'obs'          - Binary (0-1) tensor indicating missing entries
%                      (0: missing; 1: observed)
%     'init'         - Initialization method
%                     - 'ml'  : SVD initilization (default)
%                     - 'rand': Random matrices
%     'maxRank'      - The initialization of rank (larger than true rank)
%     'dimRed'       - 1: Remove unnecessary components automaticly (default)
%                    - 0: Not remove
%     'maxiters'     - max number of iterations (default: 100)
%     'tol'          - lower band change tolerance for convergence dection
%                      (default: 1e-5)
%     'noise'        - whether noise is updated
%                        - 'on': update noise parameter (default)
%                        - 'off': fixed noise parameter (1e-5)
%     'predVar'      - Predictive distribution
%                         - 1:  compute and output
%                         - 0:  doesnot compute  (default)
%     'verbose'      - visualization of results
%                       - 0: no
%                       - 1: text (default)
%                       - 2: online display image
%                       - 3: show factors by image
%                       - 4: show factors by hinton plot (very slow)
%   OUTPUTS
%      model         - Model parameters and hyperparameters
% -----------------------------------------------------------------------
%
%   Example:
%
%     [model] = BCPF_IC(Y, 'obs', O, 'init', 'rand', 'maxRank', 10, 'dimRed', 1, 'maxiters', 100, ...
%                                'tol', 1e-6, 'verbose', 3);
%
% < Bayesian CP Factorization of Incomplete Image >
% Copyright (C) 2014  Qibin Zhao
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%
warning off; %#ok<WNOFF>
randn('state',1); rand('state',1); %#ok<RAND>
dimY = size(Y);
N = ndims(Y);

%% Set parameters from input or by using defaults
ip = inputParser;
ip.addParamValue('obs', ones(dimY), @(x) (isnumeric(x) || islogical(x)) );
ip.addParamValue('init', 'rand', @(x) (ismember(x,{'ml','rand'})));
ip.addParamValue('maxRank', max(dimY), @isscalar);
ip.addParamValue('maxiters', 100, @isscalar);
ip.addParamValue('tol', 1e-5, @isscalar);
ip.addParamValue('verbose', 1, @isscalar);
ip.addParamValue('noise', 'on', @(x)ismember(x,{'on','off'}));
ip.addParamValue('dimRed', 1, @isscalar);
ip.addParamValue('predVar', 0, @isscalar);
ip.parse(varargin{:});

O     = ip.Results.obs;
init  = ip.Results.init;
R   = ip.Results.maxRank;
maxiters  = ip.Results.maxiters;
tol   = ip.Results.tol;
verbose  = ip.Results.verbose;
DIMRED   = ip.Results.dimRed;
noise = ip.Results.noise;
predVar = ip.Results.predVar;

%% Initialization
Y = tensor(Y.*O);
O = tensor(O);
nObs = sum(O(:));

a_gamma0     = 1e-6;
b_gamma0     = 1e-6;
if  strcmp(noise,'on')
    a_beta0      = 1e-6;
    b_beta0      = 1e-6;
else
    a_beta0      = 1e-1;
    b_beta0      = 1e-6;
end
gammas = ones(R,1);
beta = 1e4;
dscale = 1;

switch init,
    case 'ml'    % Maximum likelihood
        Z = cell(N,1);
        ZSigma = cell(N,1);
        if ~isempty(find(O==0))
            Y(find(O==0)) = sum(Y(:))/nObs;
        end
        for n = 1:N
            ZSigma{n} = (repmat(eye(R), [1 1 dimY(n)]));
            [U, S, V] = svd(double(tenmat(Y,n)), 'econ');
            if R <= size(U,2)
                Z{n} = U(:,1:R)*(S(1:R,1:R)).^(0.5);
            else
                Z{n} = [U*(S.^(0.5)) randn(dimY(n), R-size(U,2))];
            end
        end
        Y = Y.*O;
    case 'rand'   % Random initialization
        Z = cell(N,1);
        ZSigma = cell(N,1);
        for n = 1:N
            Z{n} = randn(dimY(n),R);
            ZSigma{n} = repmat(eye(R), [1 1 dimY(n)]);
        end
end
% --------- E(aa') = cov(a,a) + E(a)E(a')----------------
EZZT = cell(N,1);
for n=1:N
    EZZT{n} = (reshape(ZSigma{n}, [R*R, dimY(n)]))';
end

Fit =0;
LB = 0;
X = double(ktensor(Z));

%% Create figures
if verbose >2,
    scrsz = get(0,'ScreenSize');
    h1 = figure('Position',[scrsz(3)*0.2 scrsz(4)*0.3 scrsz(3)*0.6 scrsz(4)*0.4]);
    figure(h1);
    switch verbose,
        case 4,
            subplot(2,3,1); hintonDiagram(Z{1}); title('Mode-1'); ylabel('Length of #-mode');
            subplot(2,3,2); hintonDiagram(Z{2}); title('Mode-2'); xlabel('Latent dimensions');
            if N>=3, subplot(2,3,3); hintonDiagram(Z{3}); title('Mode-3'); end
        case 3,
            subplot(2,3,1); imagesc(Z{1}); title('Mode-1'); ylabel('Length of #-mode');
            subplot(2,3,2); imagesc(Z{2}); title('Mode-2'); xlabel('Latent dimensions');
            if N>=3, subplot(2,3,3); imagesc(Z{3}); title('Mode-3');end
    end
    subplot(2,3,4); bar(gammas); title('Posterior mean of \lambda'); xlabel('Latent components'); ylabel(''); axis tight;
    subplot(2,3,5); plot(LB, '-r.','LineWidth',1.5,'MarkerSize',10 ); title('Lower bound'); xlabel('Iteration');  grid on;
    subplot(2,3,6); plotGamma(a_beta0, a_beta0); title('Posterior pdf'); xlabel('Noise precision \tau');grid on;
    set(findall(h1,'type','text'),'fontSize',12);
    drawnow;
end
if verbose ==2;
    h3 = figure;
    temp = 255.*(X-min(X(:)))/(max(X(:))-min(X(:)));
    imshow(uint8(temp));
    title(['Iter.= '  num2str(0),',  Rank = ' num2str(R)],'FontSize', 13, 'color','b');
    tic;
    xlabel(['(BCPF)  Time: ' num2str(round(toc)), ' seconds'],'FontSize', 13, 'color','b');
    drawnow;
end

%% Model learning
for it=1:maxiters,
    %% Update factor matrices
    Aw = diag(gammas);
    for n=1:N
        ENZZT = reshape(khatrirao_fast(EZZT{[1:n-1, n+1:N]},'r')' * double(tenmat(O,n)'), [R,R,dimY(n)]);
        FslashY = khatrirao_fast(Z{[1:n-1, n+1:N]},'r')' * tenmat(Y.*O, n)';
        for i=1:dimY(n)
            ZSigma{n}(:,:,i) = (beta * ENZZT(:,:,i) + Aw )^(-1);
            Z{n}(i,:) = (beta * ZSigma{n}(:,:,i) * FslashY(:,i))';
        end
        EZZT{n} = (reshape(ZSigma{n}, [R*R, dimY(n)]) + khatrirao_fast(Z{n}',Z{n}'))';
    end

    %% Update latent tensor X
    X = double(ktensor(Z));

    %% Update hyperparameters gamma
    a_gammaN = (0.5*sum(dimY) + a_gamma0)*ones(R,1);
    b_gammaN = 0;
    for n=1:N
        b_gammaN = b_gammaN + diag(Z{n}'*Z{n}) + diag(sum(ZSigma{n},3));
    end
    b_gammaN = b_gamma0 + 0.5.* b_gammaN;
    gammas = a_gammaN./b_gammaN;

    %% update noise beta
    %  The most time and space consuming part
    if 0 % save time but large space needed
        EX2 =  O(:)' * khatrirao_fast(EZZT,'r') * ones(R*R,1);
    else  % save space but slow
        temp1 = cell(N,1);
        EX2 =0;
        for i =1:R
            for n=1:N
                temp1{n} = EZZT{n}(:,(i-1)*R+1: i*R);
            end
            EX2 = EX2 + O(:)' * khatrirao_fast(temp1,'r')* ones(R,1);
        end
    end
    err = Y(:)'*Y(:) - 2*Y(:)'*X(:) + EX2;
    if  strcmp(noise,'on')
        a_betaN = a_beta0 + 0.5*nObs;
        b_betaN = b_beta0 + 0.5*err;
    else
        a_betaN = a_beta0;
        b_betaN = b_beta0;
    end
    beta = a_betaN/b_betaN;
    Fit = 1 - sqrt(sum(err(:)))/norm(Y(:));

    %% Lower bound
    temp1 = -0.5*nObs*safelog(2*pi) + 0.5*nObs*(psi(a_betaN)-safelog(b_betaN)) - 0.5*(a_betaN/b_betaN)*err;
    temp22 =0;
    for n=1:N
        temp22= temp22 + Z{n}'*Z{n} + sum(ZSigma{n},3);
    end
    temp2 = -0.5*R*sum(dimY)*safelog(2*pi) + 0.5*sum(dimY)*sum(psi(a_gammaN)-safelog(b_gammaN)) -0.5*trace(diag(gammas)* temp22);
    temp3 = sum(-safelog(gamma(a_gamma0)) + a_gamma0*safelog(b_gamma0) -  b_gamma0.*(a_gammaN./b_gammaN) + (a_gamma0-1).*(psi(a_gammaN)-safelog(b_gammaN)));
    temp4 = -safelog(gamma(a_beta0)) + a_beta0*safelog(b_beta0) + (a_beta0-1)*(psi(a_betaN)-safelog(b_betaN)) - b_beta0*(a_betaN/b_betaN);
    temp5=0;
    for n=1:N
        for i=1:size(ZSigma{n},3)
            temp5 = temp5 + 0.5*safelog(det(ZSigma{n}(:,:,i))) + 0.5*R*(1+safelog(2*pi));
        end
    end
    temp6 = sum(safelog(gamma(a_gammaN)) - (a_gammaN-1).*psi(a_gammaN) -safelog(b_gammaN) + a_gammaN);
    temp7 = safelog(gamma(a_betaN)) - (a_betaN-1)*psi(a_betaN) -safelog(b_betaN) + a_betaN;
    LB(it) = temp1 + temp2 + temp3 + temp4 + temp5 + temp6 + temp7;

    %% Prune irrelevant dimensions?
    Zall = cell2mat(Z);
    comPower = diag(Zall' * Zall);
    comTol = sum(dimY)*eps(norm(Zall,'fro'));
    rankest = sum(comPower> comTol );
    if max(rankest)==0
        disp('Rank becomes 0 !!!');
        break;
    end
    if DIMRED==1  && it >=2,
        if R~= max(rankest)
            indices = comPower > comTol;
            gammas = gammas(indices);
            temp = ones(R,R);
            temp(indices,indices) = 0;
            temp = temp(:);
            for n=1:N
                Z{n} = Z{n}(:,indices);
                ZSigma{n} = ZSigma{n}(indices,indices,:);
                EZZT{n} = EZZT{n}(:, temp == 0);
            end
            R = max(rankest);
        end
    end

    %% Display progress
    if it>2
        LBRelChan = abs(LB(it) - 2*LB(it-1) + LB(it-2))/-LB(2);
    else
        LBRelChan = NaN;
    end
    if verbose,
        fprintf('Iter. %d: RelChan = %g, Fit = %g, R = %d \n', it, LBRelChan, Fit, rankest);
    end

    %% visualize online results
    if verbose >2 ,
        switch verbose,
            case 4,
                set(0,'CurrentFigure',h1);
                subplot(2,3,1); hintonDiagram(Z{1}); title('Mode-1'); ylabel('Length of #-mode');
                subplot(2,3,2); hintonDiagram(Z{2}); title('Mode-2'); xlabel('Latent dimensions');
                if N>=3, subplot(2,3,3); hintonDiagram(Z{3}); title('Mode-3'); end
            case 3,
                set(0,'CurrentFigure',h1);
                subplot(2,3,1); imagesc(Z{1}); title('Mode-1'); ylabel('Length of #-mode');
                subplot(2,3,2); imagesc(Z{2}); title('Mode-2'); xlabel('Latent dimensions');
                if N>=3, subplot(2,3,3); imagesc(Z{3}); title('Mode-3'); end
        end
        subplot(2,3,4); bar(gammas); title('Posterior mean of \lambda'); xlabel('Latent components'); ylabel(''); axis tight;
        subplot(2,3,5); plot(LB, '-r.','LineWidth',1.5,'MarkerSize',10 ); title('Lower bound'); xlabel('Iteration');  grid on;
        subplot(2,3,6); plotGamma(a_betaN, b_betaN); title('Posterior pdf'); xlabel('Noise precision \tau');grid on;
        set(findall(h1,'type','text'),'fontSize',12);
        drawnow;
    end
    if verbose==2
        set(0,'CurrentFigure',h3);
        figure(h3);
        %        temp = (X-min(X(:)))/(max(X(:))-min(X(:)));
        %        image(temp);
        %        axis off;
        imshow(uint8(X));
        title(['Iter.= '  num2str(it),',  Rank = ' num2str(max(rankest))],'FontSize', 13, 'color','b');
        xlabel(['(BCPF)  Time: ' num2str(round(toc)), ' seconds'],'FontSize', 13, 'color','b');
        drawnow;
    end

    %% Convergence check
    if it>5 && abs(LBRelChan) < tol
        disp('\\\======= Converged===========\\\');
        break;
    end
end

%% Predictive distribution
if predVar==1
    Xvar =  tenzeros(size(Y));
    for n=1:N
        Xvar = tenmat(Xvar,n);
        Fslash = khatrirao_fast(Z{[1:n-1, n+1:N]},'r');
        if 1
            temp1 = double(tenmat(tensor(ZSigma{n}),3));
            temp2 = khatrirao_fast(Fslash', Fslash');
            Xvar(:,:) = Xvar(:,:) + temp1*temp2;
        else
            % ---  slow computation ------
            for i=1:size(Xvar,1)     %#ok
                Xvar(i,:) = Xvar(i,:) + diag(Fslash * ZSigma{n}(:,:,i) *Fslash')';
            end
            % ---  slow computation ------
        end
        Xvar = tensor(Xvar);
    end
    Xvar = Xvar + beta^(-1);
    Xvar = Xvar.*(2*a_betaN)/(2*a_betaN-2);
    Xvar = Xvar.*(dscale^2);
else
    Xvar =[];
end

%% Prepare the results
SNR = 10*log10(var(X(:))*beta);
X = ktensor(Z)*dscale;
X = arrange(X);

%% Output
model.X = X;
model.ZSigma = ZSigma;
model.gammas = gammas;
model.Fit = Fit;
model.SNR = SNR;
model.Xvar = double(Xvar);
model.TrueRank = rankest;
model.LowBound = max(LB);

function y = safelog(x)
x(x<1e-300)=1e-200;
x(x>1e300)=1e300;
y=log(x);


function m = shiftleft(m,r)
%SHIFTLEFT    Shift array m left by r bits
%
%   m = shiftleft(m,r)
%
%first r bits of m(:,1) are zero, otherwise lost
%

% written  12/30/98     S.M. Rump
% modified 08/26/12     S.M. Rump  global variables removed
%

  INTLAB_LONG_LOGBETA = getappdata(0,'INTLAB_LONG_LOGBETA');

  Ones = ones(1,size(m,2));

  % first r bits of m
  factor = 2.^(r-INTLAB_LONG_LOGBETA)*Ones ;
  ms = floor( m .* factor );

  % array m shifted left by r bits, last r bits zero
  m =  ( m - ms ./ factor ) .* ( 2.^r*Ones );

  % add last r bits
  m(:,1:end-1) = m(:,1:end-1) + ms(:,2:end);


function n = navier_q1(xy,ev,flowsol)
%navier_q1  Q1 convection matrix
%   N = navier_q1(xy,ev,flowsol);
%   input
%          xy         Q2 nodal coordinate vector
%          ev         element mapping matrix
%          flowsol    Q1-Q1 or Q1_P0 flow solution
%   output
%          N          Q1 scalar convection matrix
%
%   Natural boundary conditions apply.
%   IFISS function: DJS; 11 March 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage
nngpt=4;
x=xy(:,1); y=xy(:,2);
nvtx=length(x);   nel=length(ev(:,1));
usol=flowsol(1:nvtx); vsol=flowsol(nvtx+1:2*nvtx);
fprintf('setting up Q1 convection matrix...  ')
%
% initialise global matrices
      n = sparse(nvtx,nvtx);
%
% Gauss point integration rules
      if (nngpt==4)        % 2x2 Gauss points
      gpt=1.0e0/sqrt(3.0e0);
      s(1) = -gpt; t(1) = -gpt; wt(1)=1;
      s(2) =  gpt; t(2) = -gpt; wt(2)=1;
      s(3) =  gpt; t(3) =  gpt; wt(3)=1;
      s(4) = -gpt; t(4) =  gpt; wt(4)=1;
      elseif (nngpt==1)   % 1x1 Gauss point
      s(1) =    0; t(1) =    0; wt(1)=4;
      else
	  error('Check Gauss point integration specification')
      end
%
% inner loop over elements
      for ivtx = 1:4
      xl_v(:,ivtx) = x(ev(:,ivtx));
      yl_v(:,ivtx) = y(ev(:,ivtx));
      xsl(:,ivtx) = usol(ev(:,ivtx));
	  ysl(:,ivtx) = vsol(ev(:,ivtx));
	  end
      ne = zeros(nel,4,4);
%
% loop over Gauss points
         for igpt = 1:nngpt
         sigpt=s(igpt);
         tigpt=t(igpt);
         wght=wt(igpt);
%  evaluate derivatives etc
         [jac,invjac,phi,dphidx,dphidy] = deriv(sigpt,tigpt,xl_v,yl_v);
         u_x = zeros(nel,1); u_y=zeros(nel,1);
            for k=1:4
		    u_x(:) = u_x(:) + xsl(:,k) .* phi(:,k);
		    u_y(:) = u_y(:) + ysl(:,k) .* phi(:,k);
		    end
		 for j = 1:4
            for i = 1:4
				ne(:,i,j)  = ne(:,i,j)  + wght*u_x(:).*phi(:,i).*dphidx(:,j);
                ne(:,i,j)  = ne(:,i,j)  + wght*u_y(:).*phi(:,i).*dphidy(:,j);
             end
	    end
%
% end of Gauss point loop
         end
%
%%  element assembly into global matrix
      for krow=1:4
	  nrow=ev(:,krow);
          for kcol=1:4
		  ncol=ev(:,kcol);
          n = n + sparse(nrow,ncol,ne(:,krow,kcol),nvtx,nvtx);
	      end
       end
%
fprintf('done.\n')
return


function out = MF_StateSpace_n4sid(y,ord,ptrain,steps)
% MF_StateSpace_n4sid   State space time-series model fitting.
%
% First fits the model to the whole time series, then trains it on the first
% portion and tries to predict the rest.
%
% In the second portion of this code, the state space model is fitted to the
% first p*N samples of the time series, where p is a given proportion and N is
% the length of the time series.
%
% This model is then used to predict the latter portion of the time
% series (i.e., the subsequent (1-p)*N samples).
%
% Model of the form:
% dx/dt = A x(t) + B u(t) + K e(t)
% y(t) = C x(t) + D u(t) + e(t)
% (for state space matrices A, B, C, D), disturbance matrix K (coefficients of
% noise input), input u, output y, vector of states x, and disturbance (noise) e.
%
%---INPUTS:
% y, the input time series
% ord, the order of state-space model to implement (can also be the string 'best')
% ptrain, the proportion of the time series to use for training
% steps, the number of steps ahead to predict
%
%---OUTPUTS: parameters from the model fitted to the entire time series, and
% goodness of fit and residual analysis from n4sid prediction.
%
% Uses the functions iddata, n4sid, aic, and predict from Matlab's System
% Identification Toolbox

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This function 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/>.
% ------------------------------------------------------------------------------

% ------------------------------------------------------------------------------
%% Check that a System Identification Toolbox license is available:
% ------------------------------------------------------------------------------
BF_CheckToolbox('identification_toolbox')

% ------------------------------------------------------------------------------
%% Check Inputs:
% ------------------------------------------------------------------------------
% (1) y: the time series as a column vector
% Convert y to time series object
N = length(y); % length of time series, N

y = iddata(y,[],1);

% (2) Order, the order of the state space model to fit. Can specify a positive
% integer or the string 'best'.
if nargin < 2 || isempty(ord)
    ord = 2;
end

% (3) train model on this proportion.
if nargin < 3 || isempty(ptrain)
    ptrain = 0.5;
end

% (4) steps, step-ahead prediction
if nargin < 4 || isempty(steps)
    steps = 1; % one-step ahead prediction
end

% ------------------------------------------------------------------------------
%% Build the state-space model
% ------------------------------------------------------------------------------
% Use the whole time series -- prediction comes later...
m = n4sid(y,ord); % fits a state-space model of given order

if strcmp(ord,'best')
    % also return the best order as an output statistic
    out.bestorder = length(m.k);
end

% ------------------------------------------------------------------------------
%% Model parameters
% ------------------------------------------------------------------------------
% Analysis of model

% Parameters
m_as = m.A; % 'transition' matrix in underlying ss model, x
m_ks = m.K; % coefficients for noise input in ss model
m_cs = m.C; % coefficients for measurement function, y
m_x0 = m.X0; % initial condition
m_np = length(m.ParameterVector); % number of parameters fitted

% Output model parameters
allm_as = m_as(:);
for i = 1:length(allm_as)
    out.(sprintf('A_%u',i)) = allm_as(i);
end
for i = 1:length(m_ks)
    out.(sprintf('k_%u',i)) = m_ks(i);
end
for i = 1:length(m_cs)
    out.(sprintf('c_%u',i)) = m_cs(i);
end
out.x0mod = sqrt(sum(m_x0.^2));
out.np = m_np; % the number of parameters, only a useful output if not specified

% Transition interval (this should always be 1 in this case, from how we've
% defined our time series, so not a useful output to record):
out.m_Ts = m.Ts;

% Goodness of fit outputs
% Since noisevar, lossfunction, and fpe so highly correlated, the default
% hctsa library only measures fpe.
out.m_noisevar = m.NoiseVariance; % a scalar number, basically the fpe
out.m_lossfn = m.EstimationInfo.LossFcn; % basically the fpe
out.m_fpe = m.EstimationInfo.FPE;
out.m_aic = aic(m);

% ------------------------------------------------------------------------------
%% Prediction
% ------------------------------------------------------------------------------

% Select first portion of data for estimation
% This could be any portion, actually... Maybe could look at robustness of
% model to different training sets...
ytrain = y(1:floor(ptrain*N));
% ytest = y;
ytest = y(floor(ptrain*N):end); % overlap

% Train the model on just this portion
% mp = armax(ytrain, orders);
try
    mp = n4sid(ytrain, ord);
catch emsg
    error('Couldn''t fit the model to this time series: %s',emsg.message)
    % out = NaN; return
end

%-------------------------------------------------------------------------------
% Step-ahead predictions
%-------------------------------------------------------------------------------
% steps = 2; % predicts this many steps ahead
% Maybe look at trends across different prediction horizons...
yp = predict(mp, ytest, steps, 'init', 'e'); % across whole ytest dataset

% plot the two:
% plot(y,yp);

mresiduals = ytest.y - yp.y;

%-------------------------------------------------------------------------------
% Statistics on residuals
%-------------------------------------------------------------------------------
residout = MF_ResidualAnalysis(mresiduals);

% Convert these to local outputs in quick loop
fields = fieldnames(residout);
for k = 1:length(fields);
    out.(fields{k}) = residout.(fields{k});
end

out.ac1diff = abs(CO_AutoCorr(y.y,1,'Fourier')) - abs(CO_AutoCorr(mresiduals,1,'Fourier'));

end


function psi = psifunc(centers,x,dis)
%This function is the psi second order spline function
% If other orders are desired, this function can be replaced
% centers are the knot locations
%x is a nxd matrix where d is the dimension and n are the number of points
%dis is an optional distance matrix. If it is not supplied, simple
% Euclidean distance will be calculated. This can also be used to save
% computational time if the matrix is calculated elsewhere

if nargin<3
    dis = pdist2(centers,x);
end
r=dis.*dis;
r(r==0)=1;
psi=r.*log(r);
end


% Fig. 5.23  Feedback Control of Dynamic Systems, 5e
%             Franklin, Powell, Emami
% script to generate Fig. 5.23
n=1;
d=[1 1 0];
n1=[1 2 ];
d1=conv(d,[1 20]);
d2=conv(d,[1 10]);
 sys1=tf(n1,d);
rlocus(sys1)
hold on
sys2=tf(n1,d1);
rlocus(sys2,':')
sys3=tf(n1,d2);
rlocus(sys3,'--')
axis([-6 2 -3 3])
title('Fig. 5.23 Root locus with PD or lead compensation')
z=0:.1:.9;
 wn=1:1:6;
 sgrid(z, wn)
 hold off


function DEM_HB_and_LE
%--------------------------------------------------------------------------
% This routine is a numerical examination of the relationship between
% entropy, mutual information and the exponential divergence of
% trajectories as the Rayleigh parameter of a Lorenz attractoris increased
% - through a pitchfork bifurcation and subsequent (subcritical) Hopf
% bifurcation. The (stochastic) Lorentz system is integrated for different
% values of the Rayleigh parameter. The nonequilibrium steady-state density
% is then estimated by embedding into a discrete state space; while the
% bifurcations are characterised in terms of the maximal Lyapunov exponent.
% The key thing to observe is the decrease in entropy of blanket states
% prior to the Hopf bifurcation and implicit exponential divergence of
% trajectories. This is scored by the maximal Lyapunov exponent crossing
% zero. Here, the form of the Lorenz attractor defines the three states as
% active, sensory and hidden. Note that there are no internal states in
% this example and blanket states become the particular states (i.e., the
% states of a particle).
%__________________________________________________________________________
% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: DEM_HB_and_LE.m 7502 2018-12-02 12:28:03Z karl $

% generative model
%==========================================================================                       % switch for demo
spm_figure('GetWin','DEM'); clf

% flow and Jacobian functions
%--------------------------------------------------------------------------
f  = @(x,v,P,G) v(:) + [-P(1) P(1) 0; P(3) -1 -x(1); x(2) 0 P(2)]*x/64;
Df = @(x,v,P,G) [-P(1) P(1) 0; P(3) -1 -x(1); x(2) 0 P(2)]/64 + ...
                [0 0 0; -x(3) 0 0; 0 x(1) 0]/64;

% model with initial states
%--------------------------------------------------------------------------
G.x  = [1; 1; 24];
G.f  = f;

% set up
%--------------------------------------------------------------------------
b     = 32;                         % number of bins for density estimation
T     = 2^20;                       % length of trajectory
W     = 32;                         % precision of intrinsic fluctuations
P     = exp((-16:32)*log(32)/32);   % Rayleigh parameter range
for k = 1:length(P)

    % integrated timeseries
    %----------------------------------------------------------------------
    U.u   = randn(T + 256,3)/W;
    Pk    = [10; -8/3; P(k)];
    t     = spm_int_L(Pk,G,U);

    % remove intial transients
    %----------------------------------------------------------------------
    t     = t(256:end,:);
    t     = t(1:T,:);
    tt{k} = t;

    % sample density
    %----------------------------------------------------------------------
    for i = 1:3
        t(:,i) = t(:,i) - min(t(:,i));
        t(:,i) = (b - 2)*t(:,i)/max(t(:,i));
    end
    t     = t + 1;
    p     = zeros(b,b,b) + 1;
    S     = 0;
    for i = 1:T

        % accumulate in bins
        %------------------------------------------------------------------
        j = round(t(i,:));
        p(j(3),j(2),j(1)) = p(j(3),j(2),j(1)) + 1;

        % Lyapunov exponents
        %------------------------------------------------------------------
        dfdx = Df(tt{k}(i,:)',zeros(1,3)',Pk);
        S    = S + sort(real(eig(dfdx,'nobalance')),'descend');

    end
    p     = p/sum(p(:));
    pp{k} = p;

    % mutual informations of sample density
    %----------------------------------------------------------------------
    [I,Ii,Ie] = spm_self_entropy(p);
    MI(1,k)   = I;
    MI(2,k)   = Ii;
    MI(3,k)   = Ie;
    LE(:,k)   = S/T;

    % plot mutual informations
    %----------------------------------------------------------------------
    subplot(3,2,3)
    semilogx(P(1:k),MI(1,:),'b',P(1:k),MI(2,:),'b-.',P(1:k),MI(3,:),'b:')
    axis square xy
    title('Expected surpise','Fontsize',16)
    xlabel('Control parameter'),ylabel('Entropies (nats)'),drawnow

    % plot maximal Lyapunov exponent
    %----------------------------------------------------------------------
    subplot(3,2,4)
    semilogx(P(1:k),LE(1,:),'b')
    axis square xy
    title('Lyapunov exponent','Fontsize',16)
    xlabel('Control parameter'),ylabel('Principal exponent'),drawnow

end

% lines and thresholds
%--------------------------------------------------------------------------
j     = find(LE(1,:) > 0,1);
j     = P(j);
subplot(3,2,3)
hold on, plot([j j],[ 0 6],':'), hold off
hold on, plot([1 1],[ 0 6],':'), hold off
legend({'H(B)','H(B|E)','I(B,E)'})
subplot(3,2,4)
hold on, plot([j j],[-1 1]*0.03,':'), hold off
hold on, plot([1 1],[-1 1]*0.03,':'), hold off
hold on, plot(P,zeros(size(P)),'--'), hold off

% illustrate trajectories and ergodic density
%--------------------------------------------------------------------------
j     = [8 38 length(P)];
for i = 1:length(j)

    % exemplar trajectory (plot)
    %----------------------------------------------------------------------
    subplot(3,3,i)
    t    = tt{j(i)};
    plot(t(1:1024,2),t(1:1024,3),'k')
    axis square xy
    title('Trajectory','Fontsize',16)
    axis([-30 30 -5 60])

    % image format
    %----------------------------------------------------------------------
    subplot(3,3,6 + i)
    p = pp{j(i)};
    imagesc(1-squeeze(sum(p,2))'),axis xy square
    title('Marginal density','Fontsize',16)
    ylabel('State'), xlabel('State')

%     subplot(3,3,6 + i)
%     [W,S,X,beta] = spm_power_law(t');
%     plot(W,S,'b.',W,X*beta,'b','LineWidth',1)
%     title(sprintf('alpha = %-2.2f',beta(2)),'FontSize',16)
%     ylabel('Log power'), xlabel('Log frequency')
%     axis square, axis xy, spm_axis tight

end

return

function [HB,HBH,IBH] = spm_self_entropy(pHxB)
% FORMAT [HB,HBH,IBH] = spm_self_entropy(pHxB)
% Entropies
% HS  = H(B)              % self entropy
% HBH = H(B|H)            % conditional entropy
% IBH = I(B,H)            % mutual information
%
% This subroutine assumes that the first dimension of the joint density
% corresponds to a hidden or external state and the rest are particular
% or blanket states

% evaluate joint density and posterior
%--------------------------------------------------------------------------
pB    = sum(pHxB,1);
pH    = sum(sum(sum(pHxB,2),3),4);

% inline functions
%--------------------------------------------------------------------------
ln    = @(p)log(spm_vec(p) + 1e-16);
H     = @(p)-spm_vec(p)'*ln(p);

% relative entropies
%--------------------------------------------------------------------------
HB    = H(pB);
IBH   = H(pH) + H(pB) - H(pHxB);
HBH   = HB - IBH;

return

function D = spm_Kaplan_Yorke(LE)
% FORMAT Kaplan Yorke estimate of dimensional complexity
%--------------------------------------------------------------------------
L     = real(LE);
for i = 1:size(L,2)
    l = sort(L(:,i),'descend');
    j = find(cumsum(l) > 0,1);
    if isempty(j), j = 0; end
    D(i) = j + sum(l(1:j))/abs(l(j + 1));
end

function [W,S,X,beta] = spm_power_law(x)
% FORMAT spm_power_law(x)

% illustrate power law scaling
%--------------------------------------------------------------------------
N     = floor(log2(size(x,2)));
s     = abs(fft(x(1,:)')).^2;
w     = (1:2^12)';
W     = w;
S     = s(w + 1);

S     = decimate(log(S),N - 4);
W     = log(decimate(W,N - 4));
X     = [ones(size(W)),W];

% plot part of trajectory
%--------------------------------------------------------------------------
[~,i] = max(abs(diff(spm_conv(x(1,:),2^(N - 8)))));
nn    = 2^10;
i     = (-nn:nn) + i;
i     = i(i > 0 & i < size(x,2));

% estimate exponent (alpha)
%--------------------------------------------------------------------------
[~,~,beta] = spm_ancova(X,[],S,[0;1]);


function  [fx,dfdx,dfdP] = f_Qlearn2(x,P,u,in)
% evolution function of q-values of a RL agent (2-armed bandit problem)
% [fx,dfdx,dfdP] = f_Qlearn2(x,P,u,in)
% Here, there are only two q-values to evolve, i.e. there are only two
% actions to reinforce (2-armed bandit problem).
% IN:
%   - x_t : q-values (2x1)
%   - P : (inverse-sigmoid) learning-rate
%   - u : u(1)=previous action (1 or 0), u(2)=feedback
%   - in : [useless]
% OUT:
%   - fx: evolved q-values (2x1)
%   - dfdx/dfdP: gradient of the q-values evolution function, wrt q-avlues
%   and evolution parameter, respectively.

alpha = 1./(1+exp(-P)); % learning rate is bounded between 0 and 1.
fx = zeros(2,1);
pe = u(2)-x; % prediction error
fx(1) = x(1) + alpha*pe(1)*u(1);
fx(2) = x(2) + alpha*pe(2)*(1-u(1));
% gradients' derivation
if u(1)==1
    dfdx = [1-alpha, 0;
            0, 1];
    dfdP = [alpha*(1-alpha)*pe(1),0];
else
    dfdx = [1, 0;
            0, 1-alpha];
    dfdP = [0,alpha*(1-alpha)*pe(2)];
end


function snr = get_snr(data)
% Data is a matrix whos columns index voxels, and rows index subjects (or trials, etc.)
%
% :Usage:
% ::
%
%     snr = get_snr(data)
%
% ..
%    Tor Wager
% ..

mystd = nanstd(data);
mystd(mystd == 0) = NaN;
snr = nanmean(data) ./ mystd;

return


function [bestError bestMap] = compare_labels(correctLabels, computedLabels)

% compare_labels
%
%   Given two labelings of a set of data, find a map between the
%   labelings that minimizes the number of samples that they assign
%   different labels. This version assumes the correct labeling has a small
%   number of groups (<= 5), and does an exhaustive search to find
%   the best map. If the correct number of groups is larger, the result
%   from relabel_samples (which will likely be incorrect) is run.
%
% Inputs:
%   correctLabels - the true labels of some data.
%   computedLabels - the labels computed by some algorithm for that data.
%
% Outputs:
%   bestError - the misclassification rate obtained by this relabelling.
%   bestMap - the map that converts correct labels to computed labels
%
% Sep. '07  Shankar Rao -- srrao@uiuc.edu

% Copyright 2007, University of Illinois. All rights reserved.

correctLabels = correctLabels(:)';
computedLabels = computedLabels(:)';

groupCount = max(correctLabels);
computedGroupCount = max(computedLabels);
sampleCount = length(correctLabels);

maxGroupCount = max(groupCount, computedGroupCount);

if groupCount <= 5
    bestError = 1;
    bestMap = [1:groupCount];
    candidateLabels = nchoosek(1:maxGroupCount, groupCount);
    permCount = factorial(groupCount);
    for candidateIndex = 1:size(candidateLabels,1)
        maps = perms(candidateLabels(candidateIndex,:));
        for permIndex = 1:permCount
            map = maps(permIndex,:);
            currentError = mean(map(correctLabels) ~= computedLabels);
            if currentError < bestError
                bestError = currentError;
                bestMap = map;
            end
        end
    end
else
    [bestMap, bestError] = relabel_samples(correctLabels, computedLabels, ones(1,groupCount));
end


function pass = test_times(pref)
% Test chebfun3/times

if ( nargin == 0)
    pref = chebfunpref;
end
tol = 1e4*pref.cheb3Prefs.chebfun3eps;

f = chebfun3(@(x,y,z) cos(x.*y.*z));
h = chebfun3(@(x,y,z) 2*cos(x.*y.*z));
k = chebfun3(@(x,y,z) cos(x.*y.*z).^2);

pass(1) = norm(f.*2 - h) < tol;
pass(2) = norm(f*2 - h) < tol;
pass(3) = norm(2*f - h) < tol;
pass(4) = norm(2.*f - h) < tol;
pass(5) = norm(f.^2 - k) < tol;
pass(6) = norm(f.*f - k) < tol;

ff = @(x,y,z) cos(x.*y.*z);
gg = @(x,y,z) x + y + z + x.*y.*z;
dom = [-1 1 -1 1 -1 1];
f = chebfun3(ff, dom);
g = chebfun3(gg, dom);
FtimesG = chebfun3(@(x,y,z) ff(x,y,z).*gg(x, y, z), dom);
tolj = norm(dom, inf) * tol;
pass(7) = norm(f.*g - FtimesG) < tolj;

dom = [-2 2 -2 2 -2 2];
f = chebfun3(ff, dom);
g = chebfun3(gg, dom);
FtimesG = chebfun3(@(x,y,z) ff(x,y,z).*gg(x, y, z), dom);
tolj = norm(dom, inf) * tol;
pass(8) = norm(f.*g - FtimesG) < tolj;

dom = [0 pi 0 pi -pi/2 pi/2];
f = chebfun3(ff, dom);
g = chebfun3(gg, dom);
FtimesG = chebfun3(@(x,y,z) ff(x,y,z).*gg(x, y, z), dom);
tolj = norm(dom, inf) * tol;
pass(9) = norm(f.*g - FtimesG) < tolj;

end


function H = discriminant(f, x, y, varargin)
%DISCRIMINANT the determinant of Hessian of a CHEBFUN2 at (x,y)
%   H = DISCRIMINANT(F,x,y) returns the determinant of the Hessian of F at
%   (x,y). The gradient of F should be zero at (x,y).
%
%   H = DISCRIMINANT(F,G,x,y) returnes the determinant of the 'border' Hessian
%   of F at (x,y).
%
%   Note that we cannot represent the Hessian matrix because we do not allow
%   horizontal concatenation of CHEBFUN2 objects.
%
% See also JACOBIAN.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Empty check:
if ( isempty( f ) )
    H = [];
    return
end

% Mixed second partial derivatives:
fxx = diff(f, 2, 2);
fyy = diff(f, 2, 1);
fxy = diff(f, [1 1]);

if ( nargin == 3 )      % Standard Hessian
    % Evaluate at (x,y):
    fxx = feval(fxx, x, y);
    fxy = feval(fxy, x, y);
    fyy = feval(fyy, x, y);
    H = fxx.*fyy - fxy.^2;

elseif ( nargin == 4 )  % Bordered Hessian
    % Parse user inputs:
    g = x;
    x = y;
    y = varargin{1};

    % Evaluate at (x,y):
    fxx = feval(fxx, x, y);
    fyy = feval(fxy, x, y);
    fxy = feval(fyy, x, y);

    % Partial diff and evaluate:
    gx = diff(g, 1, 2);
    gy = diff(g, 1, 1);
    gx = feval(gx, x, y);
    gy = feval(gy, x, y);

    % Determinant of bordered Hessian.
    H = -gx.*(gx.*fyy - gy.*fxy) + gy.*(gx.*fxy - gy.*fxx);

else
    error('CHEBFUN:CHEBFUN2:discriminant:badInput', 'Invalid input arguments.');
end

end


function nmfmse( V, rdim, fname, showflag )
%

% Check that we have non-negative data
if min(V(:))<0, error('Negative values in data!'); end

% Globally rescale data to avoid potential overflow/underflow
V = V/max(V(:));

% Dimensions
vdim = size(V,1);
samples = size(V,2);

% Create initial matrices
W = abs(randn(vdim,rdim));
H = abs(randn(rdim,samples));

% Initialize displays
if showflag,
   figure(1); clf; % this will show the energies and sparsenesses
   figure(2); clf; % this will show the objective function
   drawnow;
end

% Calculate initial objective
objhistory = 0.5*sum(sum((V-W*H).^2));

timestarted = clock;

% Start iteration
iter = 0;
while 1,

    % Show progress
    fprintf('[%d]: %.5f \n',iter,objhistory(end));

    % Save every once in a while
    if rem(iter,5)==0,
	elapsed = etime(clock,timestarted);
	fprintf('Saving...');
	save(fname,'W','H','iter','objhistory','elapsed');
	fprintf('Done!\n');
    end

    % Show stats
    if showflag & (rem(iter,5)==0),
	figure(1);
	cursW = (sqrt(vdim)-(sum(W)./sqrt(sum(W.^2))))/(sqrt(vdim)-1);
	cursH = (sqrt(samples)-(sum(H')./sqrt(sum(H'.^2))))/(sqrt(samples)-1);
	subplot(3,1,1); bar(sqrt(sum(W.^2)));
	subplot(3,1,2); bar(cursW);
	subplot(3,1,3); bar(cursH);
	if iter>1,
	    figure(2);
	    plot(objhistory(2:end));
	end
	drawnow;
    end

    % Update iteration count
    iter = iter+1;

    % Save old values
    Wold = W;
    Hold = H;

    % Compute new W and H (Lee and Seung; NIPS*2000)
    H = H.*(W'*V)./(W'*W*H + 1e-9);
    W = W.*(V*H')./(W*H*H' + 1e-9);

    % Renormalize so rows of H have constant energy
    norms = sqrt(sum(H'.^2));
    H = H./(norms'*ones(1,samples));
    W = W.*(ones(vdim,1)*norms);

    % Calculate objective
    newobj = 0.5*sum(sum((V-W*H).^2));
    objhistory = [objhistory newobj];

end


%  quantization -- discretizes a set of random variates
%
%  ::
%
%    [x,w] = quantization(n,xw_discrete)
%
%  Args:
%
%     n (vector): vector containing the number of discrete quantities in
%        each dimension of the gaussian shocks
%
%     xw_discrete (1 x 2 cell array): The first cell is the vector of all
%        possible values of the discrete distribution. The second cell is
%        the vector of weights of each of those possible values
%
%  Returns:
%     :
%
%     - **x** [matrix]: grid combinations of the different variates, with
%        the number of shocks in rows and the number of combinations in
%        columns
%
%     - **w** [vector]: probability distribution over the different
%        combinations
%
%  Note:
%
%     - Only works with gaussian shocks at the moment.
%
%


function [R] = spm_resels(FWHM,L,SPACE)
% Returns the RESEL counts of a search volume
% FORMAT [R] = spm_resels(FWHM,L,SPACE)
% FWHM       - smoothness of the component fields {FWHM - voxels}
% L          - space definition            {in voxels}
%                L = radius                {Sphere}
%                L = [height width length] {Box}
%                L = XYZ pointlist         {Discrete voxels}
%                L = Mapped image volume   {Image}
% SPACE      - Search space
%               'S' - Sphere
%               'B' - Box
%               'V' - Discrete voxels
%               'I' - Image VOI
%
% R          - RESEL counts {adimensional}
%
%__________________________________________________________________________
% For one or two dimensional spaces the appropriate manifold is
% used (e.g. sphere -> disc -> line).
%
% Reference : Worsley KJ et al 1996, Hum Brain Mapp. 4:58-73
%
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Karl Friston & Matthew Brett
% $Id: spm_resels.m 3899 2010-05-25 15:36:40Z guillaume $

% Dimensionality
%--------------------------------------------------------------------------
switch SPACE

case 'S'                                                           % Sphere
    %----------------------------------------------------------------------
    s     = L(:)./FWHM(:);
    s     = s(s > 0);
    if length(s) == 2,  SPACE = 'D';  end
    if length(s) == 1,  SPACE = 'L';  end

case 'B'                                                              % Box
    %----------------------------------------------------------------------
    s     = L(:)./FWHM(:);
    s     = s(s > 0);
    if length(s) == 2,  SPACE = 'R';  end
    if length(s) == 1,  SPACE = 'L';  end
end

% Default {sphere - assuming L = volume i.e. number of voxels)
%--------------------------------------------------------------------------
if nargin < 3
    SPACE = 'S';
    L     = (L*(3/4)/pi)^(1/3);
end

% RESEL Counts (R)
%==========================================================================

switch SPACE

case 'S'                                                           % Sphere
    %----------------------------------------------------------------------
    s     = prod(s).^(1/3);
    R     = [1 4*s 2*pi*s^2 (4/3)*pi*s^3];

case 'D'                                                             % Disc
    %----------------------------------------------------------------------
    s     = prod(s).^(1/2);
    R     = [1 pi*s pi*s^2 0];

case 'B'                                                              % Box
    %----------------------------------------------------------------------
    R     = [1 sum(s) (s(1)*s(2) + s(2)*s(3) + s(1)*s(3)) prod(s)];

case 'R'                                                        % Rectangle
    %----------------------------------------------------------------------
    R     = [1 sum(s) prod(s) 0];

case 'L'                                                             % Line
    %----------------------------------------------------------------------
    R     = [1 s 0 0];

case 'V'                                                           % Voxels
    %----------------------------------------------------------------------
    %R     = spm_Pec_resels(L,FWHM);
    V     = zeros(max(L,[],2)');
    LL    = mat2cell(L,ones(1,size(L,1)),size(L,2));
    V(sub2ind(size(V),LL{:})) = 1;
    R     = spm_resels_vol(V,FWHM)';

case 'I'                                                            % Image
    %----------------------------------------------------------------------
    R     = spm_resels_vol(L,FWHM)';

end