%
% Usage: [W [optim]]=mexFistaGraph(Y,X,W0,graph,param);
%
% Name: mexFistaGraph
%
% Description: mexFistaGraph solves sparse regularized problems.
%         X is a design matrix of size m x p
%         X=[x^1,...,x^n]', where the x_i's are the rows of X
%         Y=[y^1,...,y^n] is a matrix of size m x n
%         It implements the algorithms FISTA, ISTA and subgradient descent.
%
%         It implements the algorithms FISTA, ISTA and subgradient descent for solving
%
%           min_W  loss(W) + lambda psi(W)
%
%         The function psi are those used by mexProximalGraph (see documentation)
%         for the loss functions, see the documentation of mexFistaFlat
%
%         This function can also handle intercepts (last row of W is not regularized),
%         and/or non-negativity constraints on W.
%
% Inputs: Y:  double dense m x n matrix
%         X:  double dense or sparse m x p matrix
%         W0:  double dense p x n matrix or p x Nn matrix (for multi-logistic loss)
%              initial guess
%         graph: struct (see documentation of mexProximalGraph)
%         param: struct
%            param.loss (choice of loss, see above)
%            param.regul (choice of regularization, see function mexProximalFlat)
%            param.lambda (regularization parameter)
%            param.lambda2 (optional, regularization parameter, 0 by default)
%            param.lambda3 (optional, regularization parameter, 0 by default)
%            param.verbose (optional, verbosity level, false by default)
%            param.pos (optional, adds positivity constraints on the
%                coefficients, false by default)
%            param.numThreads (optional, number of threads for exploiting
%                multi-core / multi-cpus. By default, it takes the value -1,
%                which automatically selects all the available CPUs/cores).
%            param.max_it (optional, maximum number of iterations, 100 by default)
%            param.it0 (optional, frequency for computing duality gap, every 10 iterations by default)
%            param.tol (optional, tolerance for stopping criteration, which is a relative duality gap
%                if it is available, or a relative change of parameters).
%            param.gamma (optional, multiplier for increasing the parameter L in fista, 1.5 by default)
%            param.L0 (optional, initial parameter L in fista, 0.1 by default, should be small enough)
%            param.fixed_step (deactive the line search for L in fista and use param.L0 instead)
%            param.compute_gram (optional, pre-compute X^TX, false by default).
%            param.intercept (optional, do not regularize last row of W, false by default).
%            param.ista (optional, use ista instead of fista, false by default).
%            param.subgrad (optional, if not param.ista, use subradient descent instead of fista, false by default).
%            param.a, param.b (optional, if param.subgrad, the gradient step is a/(t+b)
%            also similar options as mexProximalTree
%
%            the function also implements the ADMM algorithm via an option param.admm=true. It is not documented
%            and you need to look at the source code to use it.
%
%
% Output:  W:  double dense p x n matrix or p x Nn matrix (for multi-logistic loss)
%          optim: optional, double dense 4 x n matrix.
%              first row: values of the objective functions.
%              third row: values of the relative duality gap (if available)
%              fourth row: number of iterations
%
% Author: Julien Mairal, 2010


function dat = alignment(algo,dat)

  [x y]=get_xy(dat);

  if size(x,1)~=size(x,2)
      x=x*x';
  end;
  if size(y,1)~=size(y,2)
      y=y*y';
  end;

  lss=sum(sum( x .* y)) / sqrt(sum(sum(x.^2)) * sum(sum(y.^2)) );

  dat=data([get_name(dat) ' -> alignment='  num2str(lss,4) ],[],lss);


function f = logsigmoid_fh(w)
% This is a factory for a function handle to an MV2DF, which represents
% the vectorization of the logsigmoid function. The mapping is, in
% MATLAB-style code:
%
%   y = log(sigmoid(w)) = log(1./1+exp(-w)) = -log(1+exp(-w))
%
% Inputs:
%   m: the number of inputs to each individual logsumexp calculation.
%   direction: 1 sums down columns, or 2 sums accross rows.
%   w: optional, if ssupplied
%
% Outputs:
%   f: a function handle to the MV2DF described above.
%
% see: MV2DF_API_DEFINITION.readme

if nargin==0
    test_this();
    return;
end

f = vectorized_function([],@(x)F0(x));

if exist('w','var') && ~isempty(w)
    f = f(w);
end

end

function [y,f1] = F0(x)
logp1 = -neglogsigmoid(x);
logp2 = -neglogsigmoid(-x);
y = logp1;
f1 = @() F1(logp1,logp2);
end

function [J,f2,linear] = F1(logp1,logp2)
linear = false;
J = exp(logp2);
f2 = @(dx) F2(dx,logp1,logp2);
end

function h = F2(dx,logp1,logp2)
h = -dx.*exp(logp1+logp2);
end

function test_this()
n = 10;
f = logsigmoid_fh([]);
x = randn(n,1);
test_MV2DF(f,x);
end


function [T1 Mls]=cp_Tparam(M, R)
[u,s,v]=svd(M');
T1=v(:,size(M,2)+1:size(M,1))';

%ls matrix
Mls=lsmat_v000(M,R);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% QPSK demonstration packet-based transceiver for Chilipepper
% Toyon Research Corp.
% http://www.toyon.com/chilipepper.php
% Created 10/17/2012
% embedded@toyon.com
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Demonstration of a Costas Loop. Refer to:
% Telecommunications Breakdown: Concepts of Communication Transmitted via
% Software-Defined Radio C. Richard Johnson
% We employ a hard-decision feedback in order to get rid of the loop
% filters.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%#codegen
function [z_i_out, z_q_out, fe] = qpsk_rx_foc(y_i, y_q, mu_in)

    persistent phi

    lSin = SIN;
    lCos = COS;

    if isempty(phi)
        phi = 0;
    end

    mu = mu_in/2^12;

    % create the VCO signal
    if phi >= 1
        phi = phi - 1;
    end
    if phi < 0
        phi = phi + 1;
    end

    phi12 = round(phi*2^12)+1;
    if phi12 >= 2^12
        phi12 = 1;
    end
    if phi12 < 0
        phi12 = 0;
    end
    f_i = lCos(phi12+1);
    f_q = lSin(phi12+1);
    ti1 = y_i*f_i;
    ti2 = y_q*f_q;
    tq1 = y_q*f_i;
    tq2 = -y_i*f_q;
    z_i = ti1 + ti2;
    z_q = tq1 + tq2;

    % generate the error term to drive VCO generateion
    if z_q < 0
        tf = -z_i;
    else
        tf = z_i;
    end
    if z_i < 0
        bf = -z_q;
    else
        bf = z_q;
    end
    % using sign of error in order to make it gain invariant
    time_diff = tf-bf;
    if time_diff < 0
        e = -1;
    else
        e = 1;
    end

    c = mu*e;
    phiNew = phi - c;
    phi = phiNew;

    fe = phiNew;

    z_i_out = z_i;
    z_q_out = z_q;
end


function phiFaceAverage = tvdMean3D(phi, u, FL)
% This function gets the value of the field variable phi defined
% over the MeshStructure and calculates the upwind average on
% the cell faces, based on the direction of the velocity vector for a uniform mesh.
%
% SYNOPSIS:
%   phiFaceAverage = tvdMean3D(u, phi, FL)
%
% PARAMETERS:
%
%
% RETURNS:
%
%
% EXAMPLE:
%
% SEE ALSO:
%

% Written by Ali A. Eftekhari
% See the license file

% extract the velocity data
% note: size(ux) = [1:m+1, 1:n] and size(uy) = [1:m, 1:n+1]
ux = u.xvalue;
uy = u.yvalue;
uz = u.zvalue;

% check the size of the variable and the mesh dimension
Nx = u.domain.dims(1);
Ny = u.domain.dims(2);
Nz = u.domain.dims(3);
dx=repmat(0.5*(u.domain.cellsize.x(1:end-1)+u.domain.cellsize.x(2:end)), 1, Ny, Nz);
dy=repmat(0.5*(u.domain.cellsize.y(1:end-1)+u.domain.cellsize.y(2:end))', Nx, 1, Nz);
dz=zeros(1, 1, Nz+1);
dz(1,1,:)=0.5*(u.domain.cellsize.z(1:end-1)+u.domain.cellsize.z(2:end));
dz=repmat(dz, Nx, Ny, 1);

% define the tvd face vectors
phiX_p = zeros(Nx+1,Ny,Nz);
phiX_m = zeros(Nx+1,Ny,Nz);
phiY_p = zeros(Nx,Ny+1,Nz);
phiY_m = zeros(Nx,Ny+1,Nz);
phiZ_p = zeros(Nx,Ny,Nz+1);
phiZ_m = zeros(Nx,Ny,Nz+1);

% calculate the upstream to downstream gradient ratios for u>0 (+ ratio)
% x direction
dphiX_p = (phi.value(2:Nx+2, 2:Ny+1, 2:Nz+1)-phi.value(1:Nx+1, 2:Ny+1, 2:Nz+1))./dx;
rX_p = dphiX_p(1:end-1,:,:)./fsign(dphiX_p(2:end,:,:));
phiX_p(2:Nx+1,:,:) = phi.value(2:Nx+1, 2:Ny+1, 2:Nz+1)+0.5*FL(rX_p).* ...
    (phi.value(3:Nx+2,2:Ny+1,2:Nz+1)-phi.value(2:Nx+1,2:Ny+1,2:Nz+1));
phiX_p(1,:,:) = (phi.value(1,2:Ny+1,2:Nz+1)+phi.value(2,2:Ny+1,2:Nz+1))/2; % left boundary
% y direction
dphiY_p = (phi.value(2:Nx+1, 2:Ny+2, 2:Nz+1)-phi.value(2:Nx+1, 1:Ny+1, 2:Nz+1))./dy;
rY_p = dphiY_p(:,1:end-1,:)./fsign(dphiY_p(:,2:end,:));
phiY_p(:,2:Ny+1,:) = phi.value(2:Nx+1, 2:Ny+1, 2:Nz+1)+0.5*FL(rY_p).* ...
    (phi.value(2:Nx+1,3:Ny+2,2:Nz+1)-phi.value(2:Nx+1, 2:Ny+1,2:Nz+1));
phiY_p(:,1,:) = (phi.value(2:Nx+1,1,2:Nz+1)+phi.value(2:Nx+1,2,2:Nz+1))/2; % Bottom boundary
% z direction
dphiZ_p = (phi.value(2:Nx+1, 2:Ny+1, 2:Nz+2)-phi.value(2:Nx+1, 2:Ny+1, 1:Nz+1))./dz;
rZ_p = dphiZ_p(:,:,1:end-1)./fsign(dphiZ_p(:,:,2:end));
phiZ_p(:,:,2:Nz+1) = phi.value(2:Nx+1, 2:Ny+1, 2:Nz+1)+0.5*FL(rZ_p).* ...
    (phi.value(2:Nx+1,2:Ny+1,3:Nz+2)-phi.value(2:Nx+1,2:Ny+1,2:Nz+1));
phiZ_p(:,:,1) = (phi.value(2:Nx+1,2:Ny+1,1)+phi.value(2:Nx+1,2:Ny+1,2))/2; % Back boundary

% calculate the upstream to downstream gradient ratios for u<0 (- ratio)
% x direction
rX_m = dphiX_p(2:end,:,:)./fsign(dphiX_p(1:end-1,:,:));
phiX_m(1:Nx,:,:) = phi.value(2:Nx+1, 2:Ny+1, 2:Nz+1)+0.5*FL(rX_m).* ...
    (phi.value(1:Nx, 2:Ny+1, 2:Nz+1)-phi.value(2:Nx+1, 2:Ny+1, 2:Nz+1));
phiX_m(Nx+1,:,:) = (phi.value(end,2:Ny+1,2:Nz+1)+phi.value(end-1,2:Ny+1,2:Nz+1))/2; % right boundary
% y direction
rY_m = dphiY_p(:,2:end,:)./fsign(dphiY_p(:,1:end-1,:));
phiY_m(:,1:Ny,:) = phi.value(2:Nx+1,2:Ny+1,2:Nz+1)+0.5*FL(rY_m).* ...
    (phi.value(2:Nx+1,1:Ny,2:Nz+1)-phi.value(2:Nx+1,2:Ny+1,2:Nz+1));
phiY_m(:,Ny+1,:) = (phi.value(2:Nx+1, end,2:Nz+1)+phi.value(2:Nx+1, end-1,2:Nz+1))/2; % top boundary
% z direction
rZ_m = dphiZ_p(:,:,2:end)./fsign(dphiZ_p(:,:,1:end-1));
phiZ_m(:,:,1:Nz) = phi.value(2:Nx+1,2:Ny+1,2:Nz+1)+0.5*FL(rZ_m).* ...
    (phi.value(2:Nx+1,2:Ny+1,1:Nz)-phi.value(2:Nx+1,2:Ny+1,2:Nz+1));
phiZ_m(:,:,Nz+1) = (phi.value(2:Nx+1,2:Ny+1,end)+phi.value(2:Nx+1,2:Ny+1,end-1))/2; % front boundary

% calculate the average value
xvalue = (ux>0).*phiX_p+ ...
                        (ux<0).*phiX_m+ ...
                        0.5*(ux==0).*(phi.value(1:Nx+1,2:Ny+1,2:Nz+1)+phi.value(2:Nx+2,2:Ny+1,2:Nz+1));
yvalue = (uy>0).*phiY_p+ ...
                        (uy<0).*phiY_m+ ...
                        0.5*(uy==0).*(phi.value(2:Nx+1,1:Ny+1,2:Nz+1)+phi.value(2:Nx+1,2:Ny+2,2:Nz+1));
zvalue = (uz>0).*phiZ_p+ ...
                        (uz<0).*phiZ_m+ ...
                        0.5*(uz==0).*(phi.value(2:Nx+1,2:Ny+1,1:Nz+1)+phi.value(2:Nx+1,2:Ny+1,2:Nz+2));
phiFaceAverage=FaceVariable(phi.domain, xvalue, yvalue, zvalue);
end

function phi_out = fsign(phi_in)
% This function checks the value of phi_in and assigns an eps value to the
% elements that are less than or equal to zero, while keeping the signs of
% the nonzero elements
    phi_out = (abs(phi_in)>=eps).*phi_in+eps*(phi_in==0)+eps*(abs(phi_in)<eps).*sign(phi_in);
end


function [y, P] = mlpClassPred(model, X)
% Multilayer perceptron classification prediction
% logistic activation function is used.
% Input:
%   model: model structure
%   X: d x n data matrix
% Ouput:
%   y: 1 x n label vector
%   P: k x n probability matrix
% Written by Mo Chen (sth4nth@gmail.com).
W = model.W;
b = model.b;
T = length(W);
Z = X;
for t = 1:T-1
    Z = sigmoid(W{t}'*Z+b{t});
end
P = softmax(W{T}'*Z+b{T});
[~,y] = max(P,[],1);


function rez = datashift2(rez, do_correction)

NrankPC = 6;
[wTEMP, wPCA]    = extractTemplatesfromSnippets(rez, NrankPC);
rez.wTEMP = gather(wTEMP);
rez.wPCA  = gather(wPCA);

ops = rez.ops;

% The min and max of the y and x ranges of the channels
ymin = min(rez.yc);
ymax = max(rez.yc);
xmin = min(rez.xc);
xmax = max(rez.xc);

dmin = median(diff(unique(rez.yc)));
fprintf('vertical pitch size is %d \n', dmin)
rez.ops.dmin = dmin;
rez.ops.yup = ymin:dmin/2:ymax; % centers of the upsampled y positions

% dminx = median(diff(unique(rez.xc)));
yunq = unique(rez.yc);
mxc = zeros(numel(yunq), 1);
for j = 1:numel(yunq)
    xc = rez.xc(rez.yc==yunq(j));
    if numel(xc)>1
       mxc(j) = median(diff(sort(xc)));
    end
end
dminx = max(5, median(mxc));
fprintf('horizontal pitch size is %d \n', dminx)

rez.ops.dminx = dminx;
nx = round((xmax-xmin) / (dminx/2)) + 1;
rez.ops.xup = linspace(xmin, xmax, nx); % centers of the upsampled x positions
disp(rez.ops.xup)

if  getOr(rez.ops, 'nblocks', 1)==0
    rez.iorig = 1:rez.temp.Nbatch;
    return;
end

% binning width across Y (um)
dd = 5;
% min and max for the range of depths
dmin = ymin - 1;
dmax  = 1 + ceil((ymax-dmin)/dd);
disp(dmax)

spkTh = 10; % same as the usual "template amplitude", but for the generic templates

% Extract all the spikes across the recording that are captured by the
% generic templates. Very few real spikes are missed in this way.
[st3, rez] = standalone_detector(rez, spkTh);
%%

% detected depths
% dep = st3(:,2);
% dep = dep - dmin;

Nbatches      = rez.temp.Nbatch;
% which batch each spike is coming from
batch_id = st3(:,5); %ceil(st3(:,1)/dt);

% preallocate matrix of counts with 20 bins, spaced logarithmically
F = zeros(dmax, 20, Nbatches);
for t = 1:Nbatches
    % find spikes in this batch
    ix = find(batch_id==t);

    % subtract offset
    dep = st3(ix,2) - dmin;

    % amplitude bin relative to the minimum possible value
    amp = log10(min(99, st3(ix,3))) - log10(spkTh);

    % normalization by maximum possible value
    amp = amp / (log10(100) - log10(spkTh));

    % multiply by 20 to distribute a [0,1] variable into 20 bins
    % sparse is very useful here to do this binning quickly
    M = sparse(ceil(dep/dd), ceil(1e-5 + amp * 20), ones(numel(ix), 1), dmax, 20);

    % the counts themselves are taken on a logarithmic scale (some neurons
    % fire too much!)
    F(:, :, t) = log2(1+M);
end

%%
% determine registration offsets
ysamp = dmin + dd * [1:dmax] - dd/2;
[imin,yblk, F0, F0m] = align_block2(F, ysamp, ops.nblocks);

if isfield(rez, 'F0')
    d0 = align_pairs(rez.F0, F0);
    % concatenate the shifts
    imin = imin - d0;
end

%%
if getOr(ops, 'fig', 1)
    figure;
    set(gcf, 'Color', 'w')

    % plot the shift trace in um
    plot(imin * dd)
    box off
    xlabel('batch number')
    ylabel('drift (um)')
    title('Estimated drift traces')
    drawnow

    figure;
    set(gcf, 'Color', 'w')
    % raster plot of all spikes at their original depths
    st_shift = st3(:,2); %+ imin(batch_id)' * dd;
    for j = spkTh:100
        % for each amplitude bin, plot all the spikes of that size in the
        % same shade of gray
        ix = st3(:, 3)==j; % the amplitudes are rounded to integers
        plot(st3(ix, 1)/ops.fs, st_shift(ix), '.', 'color', [1 1 1] * max(0, 1-j/40)) % the marker color here has been carefully tuned
        hold on
    end
    axis tight
    box off

    xlabel('time (sec)')
    ylabel('spike position (um)')
    title('Drift map')

end
%%
% convert to um
dshift = imin * dd;

% this is not really used any more, should get taken out eventually
[~, rez.iorig] = sort(mean(dshift, 2));

if do_correction
    % sigma for the Gaussian process smoothing
    sig = rez.ops.sig;
    % register the data batch by batch
    dprev = gpuArray.zeros(ops.ntbuff,ops.Nchan, 'single');
    for ibatch = 1:Nbatches
        dprev = shift_batch_on_disk2(rez, ibatch, dshift(ibatch, :), yblk, sig, dprev);
    end
    fprintf('time %2.2f, Shifted up/down %d batches. \n', toc, Nbatches)
else
    fprintf('time %2.2f, Skipped shifting %d batches. \n', toc, Nbatches)
end
% keep track of dshift
rez.dshift = dshift;
% keep track of original spikes
rez.st0 = st3;

rez.F = F;
rez.F0 = F0;
rez.F0m = F0m;

% next, we can just run a normal spike sorter, like Kilosort1, and forget about the transformation that has happened in here

%%


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

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @deftypemethod  @@sym {@var{e} =} factor (@var{n})
%% @deftypemethodx @@sym {[@var{p}, @var{m}] =} factor (@var{n})
%% @deftypemethodx @@sym {@var{g} =} factor (@var{f})
%% @deftypemethodx @@sym {@var{g} =} factor (@var{f}, @var{x})
%% @deftypemethodx @@sym {@var{g} =} factor (@var{f}, @var{x}, @var{y}, @dots{})
%% Factor a symbolic polynomial or integer.
%%
%% A symbolic integer @var{n} can be factored:
%% @example
%% @group
%% e = factor(sym(28152))
%%   @result{} e = (sym)
%%         1  3   1  2
%%       17 ⋅2 ⋅23 ⋅3
%% @end group
%% @end example
%%
%% However, if you want to do anything other than just look at the result,
%% you probably want:
%% @example
%% @group
%% [p, m] = factor(sym(28152))
%%   @result{} p = (sym) [2  3  17  23]  (1×4 matrix)
%%   @result{} m = (sym) [3  2  1  1]  (1×4 matrix)
%% prod(p.^m)
%%   @result{} (sym) 28152
%% @end group
%% @end example
%%
%% An example of factoring a polynomial:
%% @example
%% @group
%% syms x
%% factor(x^2 + 7*x + 12)
%%   @result{} (sym) (x + 3)⋅(x + 4)
%% @end group
%% @end example
%%
%% When the expression @var{f} depends on multiple variables,
%% the second argument @var{x} effects what is factored:
%% @example
%% @group
%% syms x y
%% f = expand((x+3)*(x+4)*(y+5)*(y+6));
%% factor(f)
%%   @result{} (sym) (x + 3)⋅(x + 4)⋅(y + 5)⋅(y + 6)
%% factor(f, x, y)
%%   @result{} (sym) (x + 3)⋅(x + 4)⋅(y + 5)⋅(y + 6)
%% factor(f, x)
%%   @result{} (sym)
%%                       ⎛ 2            ⎞
%%       (x + 3)⋅(x + 4)⋅⎝y  + 11⋅y + 30⎠
%% factor(f, y)
%%   @result{} (sym)
%%                       ⎛ 2           ⎞
%%       (y + 5)⋅(y + 6)⋅⎝x  + 7⋅x + 12⎠
%% @end group
%% @end example
%%
%% Passing input @var{x} can be useful if your expression @var{f} might
%% be a constant and you wish to avoid factoring it as an integer:
%% @example
%% @group
%% f = sym(42);    % i.e., a degree-zero polynomial
%% factor(f)       % no, don't want this
%%   @result{} (sym)
%%        1  1  1
%%       2 ⋅3 ⋅7
%% factor(f, x)
%%   @result{} (sym) 42
%% @end group
%% @end example
%%
%% @seealso{@@sym/expand}
%% @end deftypemethod

function [p, m] = factor(f, varargin)

  f = sym(f);
  for i = 1:length(varargin)
    varargin{i} = sym(varargin{i});
  end

  if ((nargin > 1) || (~isempty (findsymbols (f))))
    %% have symbols, do polynomial factorization

    if (nargout > 1)
      print_usage ();
    end

    p = pycall_sympy__ ('return factor(*_ins, deep=True)', f, varargin{:});

  else
    %% no symbols: we are doing integer factorization

    if (~isscalar(f))
      error ('factor: integer prime factoring is only supported for scalar input')
    end

    if (nargout <= 1)
      % this is rather fragile, as noted in docs
      p = pycall_sympy__ ('return factorint(_ins[0], visual=True),', f);
    else
      cmd = { 'd = factorint(_ins[0], visual=False)'
              'num = len(d.keys())'
              'sk = sorted(d.keys())'
              'p = sp.Matrix(1, num, sk)'
              'm = sp.Matrix(1, num, lambda i,j: d[sk[j]])'
              'return (p, m)' };
      [p, m] = pycall_sympy__ (cmd, f);
    end

  end
end

%!test
%! % n = 152862;
%! % [p,m] = factor(n);  % only works on Octave, no Matlab as of 2014a
%! n = 330;  % so we use an output without repeated factors
%! p = factor(n); m = ones(size(p));
%! [ps,ms] = factor(sym(n));
%! assert (isequal (p, ps))
%! assert (isequal (m, ms))

%!test
%! n = sym(2)^4*13;
%! [p,m] = factor(n);
%! assert (isequal (p, [2 13]))
%! assert (isequal (m, [4 1]))

%!test syms x
%! assert( logical (factor(x^2 + 6*x + 5) == (x+5)*(x+1)))

%!test
%! syms x
%! f = [ x^4/2 + 5*x^3/12 - x^2/3     x^2 - 1      10];
%! g = [ x^2*(2*x - 1)*(3*x + 4)/12   (x+1)*(x-1)  10];
%! assert (isequal (factor(f), g))

%!test
%! % "fragile form" works
%! A = factor(sym(124));
%! B = strtrim(disp(A, 'flat'));
%! assert (strcmp (B, '2**2*31**1'))

%!error [p, m] = factor(sym('x'));
%!error [p, m] = factor(sym(42), sym('x'));

%!test
%! % if polynomial happens to be a constant, don't attempt integer
%! % factorization if a variable is specified
%! f = sym(42);
%! q = factor(f, sym('x'));
%! assert (isequal (f, q));


 Example due to Wang Hee Lin" <engp1622@nus.edu.sg

intra = zeros(2);
intra(1,2) = 1;
inter = zeros(2);
inter(1,1) = 1;

Q = 2; % num hidden states
O = 2; % num observable symbols
ns = [Q O];%number of states
dnodes = 1:2;
%onodes = [1:2]; % only possible with jtree, not hmm
onodes = [2];
bnet = mk_dbn(intra, inter, ns, 'discrete', dnodes, 'observed', onodes);
for i=1:4
  bnet.CPD{i} = tabular_CPD(bnet, i);
end

prior0 = normalise(rand(Q,1));
transmat0 = mk_stochastic(rand(Q,Q));
obsmat0 = mk_stochastic(rand(Q,O));

%engine = smoother_engine(hmm_2TBN_inf_engine(bnet));
engine = smoother_engine(jtree_2TBN_inf_engine(bnet));

ss = 2;%slice size(ss)
ncases = 10;%number of examples
T=10;
max_iter=2;%iterations for EM
cases = cell(1, ncases);
for i=1:ncases
  ev = sample_dbn(bnet, T);
  cases{i} = cell(ss,T);
  cases{i}(onodes,:) = ev(onodes, :);
end
[bnet2, LLtrace] = learn_params_dbn_em(engine, cases, 'max_iter', 4);


% (non-blind) image deblurring

% @inproceedings{zhang2017learning,
%   title={Learning Deep CNN Denoiser Prior for Image Restoration},
%   author={Zhang, Kai and Zuo, Wangmeng and Gu, Shuhang and Zhang, Lei},
%   booktitle={IEEE Conference on Computer Vision and Pattern Recognition},
%   year={2017}
% }

% If you have any question, please feel free to contact with me.
% Kai Zhang (e-mail: cskaizhang@gmail.com)

clear; clc;

addpath('utilities');
imageSets    = {'Set3G','Set3C'}; %%% testing dataset
setTest      = imageSets([1]); %%% select the dataset

showResult   = 1;
pauseTime    = 1;
useGPU       = 1;

folderTest   = 'testsets';
folderResult = 'results';
folderModel  = 'models';
taskTestCur  = 'Deblur';
if ~exist(folderResult,'file')
    mkdir(folderResult);
end

load(fullfile('kernels','Levin09.mat'));
kernelType = 1; % 1~8
if kernelType > 8
    k = fspecial('gaussian', 25, 1.6);
else
    k = kernels{kernelType};
end
sigmas      = [2, 2.55, 7.65]/255;
sigma       = sigmas(3);
totalIter   = 30; % default
lamda       = (sigma^2)/3; % default 3, ****** from {1 2 3 4} ******
modelSigma1 = 49; % default
modelSigma2 = 13; % ****** from {1 3 5 7 9 11 13 15} ******
modelSigmaS = logspace(log10(modelSigma1),log10(modelSigma2),totalIter);
rho         = sigma^2/((modelSigma1/255)^2);

ns          = min(25,max(ceil(modelSigmaS/2),1));
ns          = [ns(1)-1,ns];

for n_set = 1 : numel(setTest)
    %%% read images
    setTestCur = cell2mat(setTest(n_set));
    disp('--------------------------------------------');
    disp(['----',setTestCur,'-----Image Debluring-----']);
    disp('--------------------------------------------');
    folderTestCur = fullfile(folderTest,setTestCur);
    ext                 =  {'*.jpg','*.png','*.bmp'};
    filepaths           =  [];
    for i = 1 : length(ext)
        filepaths = cat(1,filepaths,dir(fullfile(folderTestCur, ext{i})));
    end
    eval(['PSNR_',taskTestCur,'_',setTestCur,' = zeros(length(filepaths),1);']);

    %%% folder to store results
    folderResultCur = fullfile(folderResult, ['Deblur_',setTestCur,'_kernel_',num2str(kernelType)]);
    if ~exist(folderResultCur,'file')
        mkdir(folderResultCur);
    end

    for i = 1 : length(filepaths)

        x  = imread(fullfile(folderTestCur,filepaths(i).name));
        [~,imageName,ext] = fileparts(filepaths(i).name);
        randn('seed',0);
        y = imfilter(im2double(x), k, 'circular', 'conv') + sigma*randn(size(x));
        [w,h,c]  = size(y);
        V = psf2otf(k,[w,h]);
        denominator = abs(V).^2;

        if c>1
            denominator = repmat(denominator,[1,1,c]);
            V = repmat(V,[1,1,c]);
        end
        upperleft   = conj(V).*fft2(y);

        if c==1
            load(fullfile(folderModel,'modelgray.mat'));
        elseif c==3
            load(fullfile(folderModel,'modelcolor.mat'));
        end
        z = single(y);
        if useGPU
            z           = gpuArray(z);
            upperleft   = gpuArray(upperleft);
            denominator = gpuArray(denominator);
        end
        tic;
        for itern = 1:totalIter
            %%% step 1
            rho = lamda*255^2/(modelSigmaS(itern)^2);
            z = real(ifft2((upperleft + rho*fft2(z))./(denominator + rho)));
            if ns(itern+1)~=ns(itern)
                [net] = loadmodel(modelSigmaS(itern),CNNdenoiser);
                net = vl_simplenn_tidy(net);
                if useGPU
                    net = vl_simplenn_move(net, 'gpu');
                end
            end
            %%% step 2
            res = vl_simplenn(net, z,[],[],'conserveMemory',true,'mode','test');
            residual = res(end).x;
            z = z - residual;
        end

        if useGPU
            output = im2uint8(gather(z));
        end
        toc;

        [PSNR_Cur,SSIM_Cur] = Cal_PSNRSSIM(x,output,0,0); %%% single
        disp(['Image Deblurring     ',num2str(PSNR_Cur,'%2.2f'),'dB','    ',filepaths(i).name]);
        eval(['PSNR_',taskTestCur,'_',setTestCur,'(',num2str(i),') = PSNR_Cur;']);

        if showResult
            imshow(cat(2,im2uint8(y),output,x));
            drawnow;
            title(['Image Deblurring     ',filepaths(i).name,'    ',num2str(PSNR_Cur,'%2.2f'),'dB'],'FontSize',12)
            pause(pauseTime)
            %pause()
            imwrite(output,fullfile(folderResultCur,[imageName,'.png']));
        end
    end
    disp(['Average PSNR is ',num2str(mean(eval(['PSNR_',taskTestCur,'_',setTestCur])),'%2.2f'),'dB']);

    %%% save PSNR
    save(fullfile(folderResultCur,['PSNR_',taskTestCur,'_',setTestCur,'.mat']),['PSNR_',taskTestCur,'_',setTestCur])

end


% Rotate position samples
%
% This function rotates provided position samples to specified angle.
%
%  USAGE
%   rpos = rotatePositions(pos, degAngle)
%   pos         Matrix with position samples.
%   degAngle    Rotation angle in degrees.
%   rpos        Rotated position samples. Same dimension as pos.
%
function rpos = rotatePositions(pos, degAngle)
    rpos(:, 2) = pos(:, 2)*cosd(degAngle) - pos(:, 3)*sind(degAngle);
    rpos(:, 3) = pos(:, 2)*sind(degAngle) + pos(:, 3)*cosd(degAngle);
    if size(pos, 2) > 3
        rpos(:, 4) = pos(:, 4)*cosd(degAngle) - pos(:, 5)*sind(degAngle);
        rpos(:, 5) = pos(:, 4)*sind(degAngle) + pos(:, 5)*cosd(degAngle);
    end
end


%MDL_FANUC10L  Create kinematic model of Fanuc AM120iB/10L robot
%
% MDL_FANUC10L is a script that creates the workspace variable R which
% describes the kinematic characteristics of a Fanuc AM120iB/10L robot
% using standard DH conventions.
%
% Also defines the workspace vector:
%   q0   mastering position.
%
% Notes::
% - SI units of metres are used.
%
% Author::
%  Wynand Swart,
%  Mega Robots CC, P/O Box 8412, Pretoria, 0001, South Africa
%  wynand.swart@gmail.com
%
% See also SerialLink, mdl_irb140, mdl_m16, mdl_motomanHP6, mdl_puma560.

% MODEL: Fanuc, AM120iB/10L, 6DOF, standard_DH

% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for Matlab (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.

%Cell: 073-1555-430
%30 Sep 2007
%Fanuc AM120iB/10L robot

%            theta    d      a    alpha
clear L
L(1) = Link([0        0     0.15  -pi/2   0  ]);
L(2) = Link([0        0     0.77   pi     0  ]);
L(3) = Link([0        0     0.1   -pi/2   0  ]);
L(4) = Link([0       -0.96  0      pi/2   0  ]);
L(5) = Link([0        0     0     -pi/2   0  ]);
L(6) = Link([0       -0.1   0      0      0  ]);
%##########################################################
%Pose 0; At MASTERING position;
%##########################################################
q0 =[0   -pi/2   0   0   0   0];
R=SerialLink(L, 'name', 'Fanuc AM120iB/10L');
%##########################################################


function [ a, seed ] = r83s_random ( n, seed )

%*****************************************************************************80
%
%% R83S_RANDOM randomizes an R83S matrix.
%
%  Discussion:
%
%    The R83S storage format is used for a tridiagonal scalar matrix.
%    The vector A(3) contains the subdiagonal, diagonal, and superdiagonal
%    values that occur on every row.
%
%  Example:
%
%    Here is how an R83S matrix of order 5, stored as (A1,A2,A3), would
%    be interpreted:
%
%      A2  A3   0   0   0
%      A1  A2  A3   0   0
%       0  A1  A2  A3   0
%       0   0  A1  A2  A3
%       0   0   0  A1  A2
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 July 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of the linear system.
%
%    Input, integer SEED, a seed for the random number generator.
%
%    Output, real A(3), the R83 matrix.
%
%    Output, integer SEED, an updated seed for the random number generator.
%
  [ a(1:3), seed ] = r8vec_uniform_01 ( 3, seed );

  return
end


function [ptheta] = tapas_sem_prosa_gaussian_priors()
%% Generates standard priors for a gaussian distribution.
%
%   Input
%   ptheta      -- Structure with the priors.
%

% aponteeduardo@gmail.com
% copyright (C) 2016
%

DIM_THETA = tapas_sem_prosa_ndims();

ptheta = struct();

[mmu, mvu, vmu, vvu, me, ve, ml, vl, p0m, p0v] = ...
    tapas_sem_unified_gaussian_priors();

mu = repmat([mmu, vmu], 1, 3);
ptheta.mu = [mu, me, ml, p0m]';

pm = repmat([mvu, vvu], 1, 3);
ptheta.pm = [1./[pm, ve, vl] p0v]';

ptheta.p0 = ptheta.mu;
ptheta.p0(9) = tan(pi * (-0.4));
% Eta is beta distributed
ptheta.bdist = [9];

end


function [ozf] = kip2ozf(kip)
% Convert force from kip to ounces-force.
% Chad A. Greene 2012
ozf = kip*16000;


function G = gsp_graph_default_parameters(G)
%GSP_GRAPH_DEFAULT_PARAMETERS load default parameters for graphs
%   Usage: G = gsp_graph_default_parameters(G);
%          G = gsp_graph_default_parameters();
%
%   Input parameters
%       G   : Graph (Optional)
%   Output parameters
%       G   : Graph
%
%   This function will fill a graph with all missing parameters such that
%   it is compabatible with all functions of the GSPBox. If you create a
%   graph manually, you need to set only the weight matrix *W*. If you have
%   some coordonate, you can also set *G.coords*. *G.coords* is a $N$ x $2$
%   or a $N$ x $3$ matrix with each columns beeing the coordonates in each
%   dimention. Finally, we recommend to set the fiel *G.type* with a name
%   that suits your graph.
%
%   Example::
%
%          W = rand(30);
%          W = (W + W')/2;
%          G.W = W - diag(diag(W));
%          G = gsp_graph_default_parameters(G)
%
%   This function can be used to update the weights of your graph. It will
%   recompute the Laplacian operator. Warning this function does not
%   perform any change to the Fourier basis::
%
%          G.W = Wnew;
%          G = gsp_graph_default_parameters(G);
%
%
%   List of parameters of the graph structure
%   -----------------------------------------
%
%   By default, a graph structure in the GSPbox contains the following
%   parameters:
%
%   * *G.W*: Weight matrix (empty by default)
%   * *G.A*: Adacency matrix (constructed with *W*)
%   * *G.N*: Number of nodes (`size(W,1)`)
%   * *G.type*: Type of graph ('unknown' by default)
%   * *G.directed*: 1 if the graph is directed, 0 if not
%   * *G.lap_type*: Laplacian type (default 'combinatorial') See the
%     function |gsp_create_laplacian| for a exhaustive list of the
%     available laplacians.
%   * *G.d*: Degree vector (Computed with *G.W*)
%   * *G.Ne*: Number of edges
%   * *G.coords*: Coordinates of the vertices (default (0,0) )
%   * *G.plotting*: Plotting parameters
%     * *G.plotting.edge_width*: Width of edges (default 1)
%     * *G.plotting.edge_color*: Color of edges (default [255,88,41]/255 )
%     * *G.plotting.edge_style*: Style of edges (default '-')
%     * *G.plotting.vertex_size*: Size of vertex (default 50)
%     * *G.plotting.vertex_color*: Color of vertex (default 'b')
%
%   Remark: There is redudancy between $A$, $W$, $L$. However, the GSPBox
%   is done in matlab and is not suppose yet to scale to graph sufficiently
%   large that your matlab have memory problem. However, this will be most
%   likely change for milestone 1.0.0. If you do have a urgent need to
%   overcome this problem, please contact the devolper team.
%

% Author: Nathanael Perraudin
% Date  : 09.12.2013

if nargin<1
    G=struct;
end

if ~isfield(G,'W') % Weight matrix
    G.W = sparse(0);

end

G.A=sparse(G.W>0);
G.N = size(G.W,1);

% Type of graph
if ~isfield(G,'type')
    G.type='unknown';
end;

% if ~isfield(G,'directed')
    G.directed = gsp_isdirected(G);
% end;

if ~isfield(G,'hypergraph')
    G.hypergraph = 0;
end;

% Create the graph Laplacian
if ~isfield(G,'lap_type')
    G.lap_type='combinatorial';
end

% if ~isfield(G,'L')
    G = gsp_create_laplacian(G);
% end

G.d = full(sum(G.W,2));

% Number of edges
if G.directed
    G.Ne = nnz(G.W);
else
    G.Ne = nnz(G.W)/2;
end

if ~isfield(G,'coords') % Coordonates
    G.coords = [];
end

G = gsp_graph_default_plotting_parameters(G);

end


function displayProbGraph(pathRF,nameOutcomes,nameSets,thesholds)
% nameOutcomes and nameSets are associated: one set per outcome

startpath = pwd;
nOutcomes = numel(nameOutcomes);
symbols = {'ob','xr'}; % First entry for positive instances, second entry for negative instances

figure
cd(pathRF), load('testing')
nameThick = cell(1,nOutcomes*2+3); nameThick{1} = '';
for o = 1:nOutcomes
    nameOutcome = nameOutcomes{o}; fSet = nameSets{o};
    %load(['testResultsRF_',fSet,'_',nameOutcome]) % results gets out of there
    load(['testResults_',fSet,'_',nameOutcome]) % results gets out of there
    probData = results.probResponse;
    outcome = testing.outcomes.(nameOutcome);
    probPos = probData(outcome == 1); xPos = ones(numel(probPos),1)*o;
    probNeg = probData(outcome == 0); xNeg = ones(numel(probNeg),1)*o;
    plot(xPos,probPos,symbols{1},'LineWidth',6,'MarkerSize',18,'MarkerFaceColor',symbols{1}(end),'MarkerEdgeColor',symbols{1}(end))
    hold on
    plot(xNeg,probNeg,symbols{2},'LineWidth',6,'MarkerSize',20,'MarkerFaceColor',symbols{2}(end),'MarkerEdgeColor',symbols{2}(end))
    hold on
    nameThick{o*2} = ''; nameThick{o*2+1} = [nameOutcome,'_{',nameSets{o},'+clinic}'];
end
xThres = (0+0.05):0.05:(nOutcomes+1-0.05);
plot(xThres,ones(1,numel(xThres))*thesholds(1)/100,'--m','LineWidth',4), hold on
plot(xThres,ones(1,numel(xThres))*thesholds(2)/100,'--m','LineWidth',4)
nameThick{end} = '';
title('Probability of occurence of events: testing cohorts','FontSize',36)
ylabel(['Random forest output probability'],'FontSize',24)
axis([0,nOutcomes+1,0,1])
legend('Status: Event occured','Status: Event did not occur')
set(gca,'xticklabel',nameThick)
set(gca,'FontSize',24)

cd(startpath)
end


function tfrqview(tfr,sig,t,method,p1,p2,p3,p4,p5);
%TFRQVIEW Quick visualization of time-frequency representations.
%       TFRQVIEW(TFR,SIG,T,METHOD,P1,P2,P3,P4,P5) allows a quick
%       visualization of a time-frequency representation.
%
%       TFR     : time-frequency representation (MxN).
%       SIG     : signal in time. If unavailable, put sig=[] as input
%                 parameter.                    (default : []).
%       T       : time instants                 (default : 1:N).
%       METHOD  : name of chosen representation (default : 'TYPE1').
%                 See the TFR* files for authorized names.
%                 TYPE1 : the representation TFR goes in normalized
%                       frequency from -0.5 to 0.5 ;
%                 TYPE2 : the representation TFR goes in normalized
%                       frequency from 0 to 0.5.
%       P1...P5 : optional parameters of the representation : run the
%                 file TFRPARAM(METHOD) to know the meaning of P1..P5
%                 for your method.
%
%	When you use the 'save' option in the main menu, you save all your
%	variables as well as two strings, TfrQView and TfrView, in a mat
%	file. If you load this file and do eval(TfrQView), you will restart
%	the display session under tfrqview ; if you do eval(TfrView), you
%	will obtain the exact layout of the screen you had when clicking on
%	the 'save' button.
%
%       Example :
%        sig=fmsin(128); tfr=tfrwv(sig);
%        tfrqview(tfr,sig,1:128,'tfrwv');
%
%       See also TFRVIEW, TFRSAVE, TFRPARAM.

%       F. Auger, September 1994, July 1995
%       O. Lemoine, Oct 1995, May-July 1996.
%       F. Auger, May 1998.
%       Copyright (c) 1996 by CNRS (France).
%
%  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 2 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, write to the Free Software
%  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

comp=computer;  %  so as to know the running computer
MatlabVersion=version; MatlabVersion=str2num(MatlabVersion(1));

% Tests on the input arguments
if nargin<1,
 error('At least one parameter required'); % at least the tfr
end
[tfrrow,tfrcol]=size(tfr);
if nargin==1,
 sig=[]; t=1:tfrcol; method='type1'; % empty signal
elseif nargin==2,
 t=1:tfrcol; method='type1';
elseif nargin==3,
 method='type1';
end
[trow,tcol] = size(t);
if (trow~=1),
 error('T must only have one row'); % t must be a row vector
end;
if (tfrcol~=tcol),
 error('T must have as much elements as tfr has columns');
end;

[Nsig,Ncol]=size(sig);
if Ncol>2,
 error('SIG must have one or two columns');
end

% Computation of Nf2, the number of interresting points in frequency
method=upper(method);
if istfr2(method),
 Nf2=tfrrow;
elseif istfr1(method),
 Nf2=tfrrow/2;
else
 error('Unknown representation. Use type1 or type2');
end;

% Computation of freq (vector of frequency samples)
if istfraff(method),
 freq=eval(['p',num2str(nargin-4)]);   	% last input argument is freqs.
else
 freq=(0.5*(0:Nf2-1)/Nf2);
end

% Initialization of the variables
if exist('options.mat'),
 load options
 colormap(SavedColorMap);
else
 threshold=5.0;  % visualization threshold
 linlogtfr=0;    % tfr visualization scale : 0 for linear 1 for logarithmic
 linlogspec=1;   % spectrum visualization scale
 sigenveloppe=0; % signal enveloppe visualization

 levelnumb=64;   % number of levels in the contour plot
 colmap=1;       % colormap index

 display=2;      % display index

 isgridsig=0;    % grid on signal
 isgridspec=0;   % grid on spectrum
 isgridtfr=0;    % grid on tfr

 issig=0;        % display signal
 isspec=0;       % display spectrum
 iscolorbar=0;   % display colorbar

 fs=1.0;         % sampling frequency (Hz)
 fmin=0.0;       % smallest displayed frequency
 fmax=0.5*fs;    % highest displayed frequency
end;

% Test of analycity
if ~isempty(sig),
 for k=1:Ncol,
  % spec(:,k)=abs(fft(sig(min(t):max(t),k))).^2; Nsp=length(spec);
  % modifications :  F. Auger (fog), 30/11/97
  Lt_fog=max(t)-min(t)+1;
  Nb_tranches_fog = floor(Lt_fog/tfrrow);
  % fprintf('%f \n',Nb_tranches_fog);
  spec(:,k)=zeros(tfrrow,1);
  for Num_tranche_fog=0:Nb_tranches_fog-1,
   % fprintf('%f \n',Num_tranche_fog);
   spec(:,k)=spec(:,k)+abs(fft(sig(min(t)+tfrrow*Num_tranche_fog+(0:tfrrow-1),k))).^2;
  end;

  if (Lt_fog>Nb_tranches_fog*tfrrow),
   spectre_fog=fft(sig(min(t)+tfrrow*Nb_tranches_fog:max(t),k),tfrrow);
   spectre_fog=spectre_fog(:);
   spec(:,k)=spec(:,k)+abs(spectre_fog).^2;
  end;

  % spec1=sum(spec(1:tfrrow/2,k));
  % spec2=sum(spec(tfrrow/2+1:Nsp,k));
  spec1=sum(spec(1:tfrrow/2,k));
  spec2=sum(spec(tfrrow/2+1:tfrrow,k));

  if spec2>spec1/10,
   disp('Be careful : the signal is not analytic!');
  end
 end
end

% Test of reality
if (Ncol==2 & ~isreal(tfr)),
 disp('Cross distribution. As the result is complex, we display the real part.');
 tfr=real(tfr);
end

ChoiceDisplay     =  1; % All the possible values of the choice variable
ChoiceLayout      =  2;
ChoiceSampling    =  3;
ChoiceFreqBounds  =  4;
ChoiceThreshold   =  5;
ChoiceLinlog      =  6;
ChoiceRedraw      =  7;
ChoiceNewFigure   =  8;
ChoiceSaveResults =  9;
ChoiceSaveOptions = 10;
ChoicePrint       = 11;
ChoiceClose       = 12;

CallTfrView = 1; % 1 to call tfrview, 0 not to do it
RefreshFigure=1; % 1 to refresh figure every time, 0 to freeze

choice=ChoiceSampling;
while choice~=ChoiceClose,                       % while not close
 if RefreshFigure & CallTfrView,                 % Call to tfrview
  linlog=linlogtfr+2*linlogspec+4*sigenveloppe;
  isgrid=isgridsig+2*isgridspec+4*isgridtfr;
  layout=issig+isspec*2+iscolorbar*4+1;
  param = [display, linlog, threshold, levelnumb, Nf2, layout,...
           fs, isgrid, fmin, fmax];
  if (nargin<=4),
   tfrview(tfr,sig,t,method,param);
  elseif (nargin==5),
   tfrview(tfr,sig,t,method,param,p1);
  elseif (nargin==6),
   tfrview(tfr,sig,t,method,param,p1,p2);
  elseif (nargin==7),
   tfrview(tfr,sig,t,method,param,p1,p2,p3);
  elseif (nargin==8),
   tfrview(tfr,sig,t,method,param,p1,p2,p3,p4);
  elseif (nargin==9),
   tfrview(tfr,sig,t,method,param,p1,p2,p3,p4,p5);
  end;
 end;

 if (linlogtfr==0),                              % Lin/log scale of the tfr
  linlogstr='Change to a logarithmic scale';
 else
  linlogstr='Change to a linear scale';
 end;

 if (RefreshFigure==1),
  redrawstr='Don''t redraw yet';
 else
  redrawstr='Redraw now';
 end;

 % Main menu
 choice=menu ('TFRQVIEW MENU :',...
              'Change the display mode',...       % ChoiceDisplay
              'Change the display layout',...     % ChoiceLayout
              'Change the sampling frequency',... % ChoiceSampling
              'Change the frequency bounds',...   % ChoiceFreqBounds
              'Change the threshold',...          % ChoiceThreshold
              linlogstr,...                       % ChoiceLinlog
              redrawstr,...                       % ChoiceRedraw
              'New figure',...                    % ChoiceNewFigure
              'Save results',...                  % ChoiceSaveResults
              'Save options',...                  % ChoiceSaveOptions
              'Print',...                         % ChoicePrint
              'Close');                           % ChoiceClose

 if (choice==ChoiceDisplay),                      % Change the display mode

  OldDisplay=display;
  display=menu('DISPLAY MODE :',...
               'contour',...                      % 1
               'imagesc',...                      % 2
               'pcolor',...                       % 3
               'surf',...                         % 4
               'mesh',...                         % 5
               'change the color map',...         % 6
               'change the number of colors or levels',...  % 7
               'cancel');                         % 8

  if (display>=1)&(display<=5),
   CallTfrView=1;
  elseif (display==6),
   if MatlabVersion>=5,
    colmap=menu('COLOR MAP :',...
                'hsv','jet','cool','bone','gray','hot','prism',...
                'pink','colorcube','autumn','winter','spring','summer',...
                'brighten','darken','permute','spin','cancel');
    if     colmap== 1,  colormap(hsv(levelnumb));
    elseif colmap== 2,  colormap(jet(levelnumb));
    elseif colmap== 3,  colormap(cool(levelnumb));
    elseif colmap== 4,  colormap(bone(levelnumb));
    elseif colmap== 5,  colormap(gray(levelnumb));
    elseif colmap== 6,  colormap(hot(levelnumb));
    elseif colmap== 7,  colormap(prism(levelnumb));
    elseif colmap== 8,  colormap(pink(levelnumb));
    elseif colmap== 9,  colormap(colorcube(levelnumb));
    elseif colmap==10,  colormap(autumn(levelnumb));
    elseif colmap==11,  colormap(winter(levelnumb));
    elseif colmap==12,  colormap(spring(levelnumb));
    elseif colmap==13,  colormap(summer(levelnumb));
    elseif colmap==14,  brighten(+0.20);
    elseif colmap==15,  brighten(-0.10);
    elseif colmap==16,  MyMap = colormap; colormap(flipud(MyMap));
    elseif colmap==17,  spinmap;
    end
   else
    colmap=menu('COLOR MAP :',...
                'hsv','jet','cool','bone','gray','hot','prism',...
                'brighten','darken','permute','spin','cancel');
    if     colmap== 1,  colormap(hsv(levelnumb));
    elseif colmap== 2,  colormap(jet(levelnumb));
    elseif colmap== 3,  colormap(cool(levelnumb));
    elseif colmap== 4,  colormap(bone(levelnumb));
    elseif colmap== 5,  colormap(gray(levelnumb));
    elseif colmap== 6,  colormap(hot(levelnumb));
    elseif colmap== 7,  colormap(prism(levelnumb));
    elseif colmap== 8,  brighten(+0.25);
    elseif colmap== 9,  brighten(-0.25);
    elseif colmap==10,  MyMap = colormap; colormap(flipud(MyMap));
    elseif colmap==11,  spinmap;
    end
   end
   display=OldDisplay; CallTfrView=0;

  elseif (display==7),
   fprintf(' Old number of levels: %f\n',levelnumb); levelold=levelnumb;
   levelnumb=input(' New number of levels: ');
   if isempty(levelnumb),
    levelnumb=levelold; CallTfrView=0;
   else
    if levelnumb<levelold,
     CallTfrView=1;
     MyMap = colormap; MyMap=MyMap(1:levelnumb,:); colormap(MyMap);
    elseif levelnumb>levelold,
     CallTfrView=1;
     MyMap = ones(levelnumb, 3); MyMap(1:levelold,:)=colormap;
     fprintf('warning : the colormap size has been increased by identical vectors\n');
     fprintf('You should redefine the colormap\n');
    else
     CallTfrView=0;
    end
   end
   display=OldDisplay;

  elseif (display==8),
   display=OldDisplay; CallTfrView=0;
  end;

 elseif (choice==ChoiceLayout),                 % Change the display layout

  layout=1;
  if issig==0,
   SignalStr= 'display signal';
  else
   SignalStr='remove signal';
  end;

  if isspec==0,
   SpectrumStr= 'display spectrum';
  else
   SpectrumStr='remove spectrum';
  end;

  if ~issig & ~isspec,
   if isgridtfr,
    GridStr='Remove the grid';
   else
    GridStr='Add a grid';
   end;
  else
   GridStr='Grids';
  end;

  if iscolorbar==0,
   ColorbarStr='display colorbar';
  else
   ColorbarStr='remove colorbar';
  end;

  layout=menu('DISPLAY LAYOUT',...
               SignalStr,...
               SpectrumStr,...
               GridStr,...
               ColorbarStr,...
              'cancel');

  if layout==1,
   issig=~issig;
   if issig==1,
    if isempty(sig),
     disp('Impossible action : the signal is unavailable'); issig=0; CallTfrView=0;
    else
     sigenveloppe=menu('SIGNAL REPRESENTATION','signal only','signal with enveloppe')-1;
     CallTfrView=1;
    end;
   else
    isgridsig=0;
   end;
  elseif layout==2,
   isspec=~isspec;
   if isspec==1,
    if isempty(sig),
     disp('Impossible action : the signal is unavailable'); isspec=0; CallTfrView=0;
    else
     linlogspec=menu('FREQUENCY REPRESENTATION','linear scale','log scale')-1;
     CallTfrView=1;
    end;
   else
    isgridspec=0;
   end;

  elseif layout==3,

   if ~issig & ~isspec,	                 % No signal and no spectrum
    isgridtfr=1-isgridtfr;
    CallTfrView=1;

   elseif issig & ~isspec,               % A signal, no spectrum
    Grid=1;
    if ~isgridsig,
     gridsigstr='add a grid on the signal';
    else
     gridsigstr='remove the grid on the signal';
    end

    if ~isgridtfr,
     gridtfrstr='add a grid on the TFR';
    else
     gridtfrstr='remove the grid on the TFR';
    end

    Grid=menu('GRID MENU :',gridsigstr,gridtfrstr,'cancel');
    if Grid==1,
     isgridsig=1-isgridsig; CallTfrView=1;
    elseif Grid==2,
     isgridtfr=1-isgridtfr; CallTfrView=1;
    else
     CallTfrView=0;
    end

   elseif ~issig & isspec,               % No signal, a spectrum
    Grid=1;
    if ~isgridspec,
     gridspestr='add a grid on the spectrum';
    else
     gridspestr='remove the grid on the spectrum';
    end
    if ~isgridtfr,
     gridtfrstr='add a grid on the TFR';
    else
     gridtfrstr='remove the grid on the TFR';
    end
    Grid=menu('GRID MENU :',gridspestr,gridtfrstr,'Close');
    if Grid==1,
     isgridspec=1-isgridspec; CallTfrView=1;
    elseif Grid==2,
     isgridtfr=1-isgridtfr; CallTfrView=1;
    else CallTfrView=0;
    end

  else                                  % A signal and a spectrum
   Grid=1;
   if ~isgridsig,
    gridsigstr='add a grid on the signal';
   else
    gridsigstr='remove the grid on the signal';
   end
   if ~isgridspec,
    gridspestr='add a grid on the spectrum';
   else
    gridspestr='remove the grid on the spectrum';
   end
   if ~isgridtfr,
    gridtfrstr='add a grid on the TFR';
   else
    gridtfrstr='remove the grid on the TFR';
   end
   Grid=menu('GRID MENU :',gridsigstr,gridspestr,gridtfrstr,'cancel');
   if Grid==1,
    isgridsig=1-isgridsig; CallTfrView=1;
   elseif Grid==2,
    isgridspec=1-isgridspec; CallTfrView=1;
   elseif Grid==3,
    isgridtfr=1-isgridtfr; CallTfrView=1;
   else CallTfrView=0;
   end
  end

  elseif layout==4,
   iscolorbar=~iscolorbar; CallTfrView=1;
  elseif layout==5,
   CallTfrView=0;
  end;

 elseif (choice==ChoiceSampling),                   % Change the sampling frequency

  fprintf(' Old sampling frequency: %f\n',fs);
  fsold=fs; fs=input(' New sampling frequency: ');
  if isempty(fs),
   fs=fsold; CallTfrView=0;
  else
   CallTfrView=1;
  end;
 elseif (choice==ChoiceFreqBounds),                 % Change the frequency bounds
  CallTfrView=0;

     fprintf(' Old smallest normalized frequency : %f\n',fmin); fminold=fmin;
  fmin=input(' New smallest normalized frequency : ');
  if isempty(fmin),
   fmin=fminold;
  elseif fmin>0.5,
   fprintf('normalized frequency desired ! value unmodified\n');
   fmin=fminold;
  else
   CallTfrView=1;
  end;

     fprintf(' Old highest normalized frequency  : %f\n',fmax); fmaxold=fmax;
  fmax=input(' New highest normalized frequency  : ');
  if isempty(fmax),
   fmax=fmaxold;
  elseif fmax>0.5,
   fprintf('normalized frequency desired ! value unmodified\n');
   fmax=fmaxold;
  else
   CallTfrView=1;
  end;

 elseif (choice==ChoiceThreshold),                  % Change the threshold

  fprintf(' Old threshold: %f\n', threshold); throld=threshold;
  threshold=input(' New threshold: ');
  if isempty(threshold),
   threshold=throld; CallTfrView=0;
  else
   CallTfrView=1;
  end

 elseif (choice==ChoiceLinlog),                     % Change the lin/log scale of tfr

  linlogtfr=1-linlogtfr;

 elseif (choice==ChoiceRedraw),                           % redraw ?
  RefreshFigure=1-RefreshFigure;
  if RefreshFigure==1, CallTfrView=1; end;

 elseif (choice==ChoiceNewFigure),                        % new figure
  figure; CallTfrView=1;

 elseif (choice==ChoiceSaveResults),                      % Save the results

  f=freq*fs;
  Nmethod=length(method);
  if comp(1:2)=='PC',
   DefaultName=[method(4:Nmethod),num2str(Nsig),'.mat'];
   [name,PathWorkDir] = uiputfile(DefaultName, 'Save As');
  else
   DefaultName=[method(4:Nmethod),num2str(Nsig)];
   nameStr=[' Name of the MAT file [',DefaultName,'] : '];
   name=input(nameStr,'s');
   while (length(name)>8),
    disp(' The name must have less than 8 characters');
    name=input(nameStr,'s');
   end
   if isempty(name),
    name=DefaultName;
   end
   PathWorkDir='';
  end
  linlog=linlogtfr+2*linlogspec+4*sigenveloppe;
  isgrid=isgridsig+2*isgridspec+4*isgridtfr;
  param = [display,linlog,threshold,levelnumb,Nf2,layout,fs,isgrid,fmin,fmax];
  SavedColorMap=colormap;
  if (nargin<=4),
   TfrQView=['colormap(SavedColorMap); tfrqview(tfr,sig,t,method)'];
   TfrView =['clf;colormap(SavedColorMap); tfrview(tfr,sig,t,method,param)'];
   eval(['save ',PathWorkDir,name,...
         ' tfr sig t f fs method param SavedColorMap TfrView TfrQView']);
  elseif (nargin==5),
   TfrQView=['colormap(SavedColorMap); tfrqview(tfr,sig,t,method,p1)'];
   TfrView =['clf; colormap(SavedColorMap); tfrview(tfr,sig,t,method,param,p1)'];
   eval(['save ',PathWorkDir,name, ...
         ' tfr sig t f fs method param p1 SavedColorMap TfrView TfrQView']);
  elseif (nargin==6),
   TfrQView=['colormap(SavedColorMap); tfrqview(tfr,sig,t,method,p1,p2)'];
   TfrView =['clf; colormap(SavedColorMap); tfrview(tfr,sig,t,method,param,p1,p2)'];
   eval(['save ',PathWorkDir,name,...
         ' tfr sig t f fs method param p1 p2 SavedColorMap TfrView TfrQView']);
  elseif (nargin==7),
   TfrQView=['colormap(SavedColorMap); tfrqview(tfr,sig,t,method,p1,p2,p3)'];
   TfrView =['clf; colormap(SavedColorMap); tfrview(tfr,sig,t,method,param,p1,p2,p3)'];
   eval(['save ',PathWorkDir,name,...
         ' tfr sig t f fs method param p1 p2 p3 SavedColorMap TfrView TfrQView']);
  elseif (nargin==8),
   TfrQView=['colormap(SavedColorMap); tfrqview(tfr,sig,t,method,p1,p2,p3,p4)'];
   TfrView =['clf; colormap(SavedColorMap); tfrview(tfr,sig,t,method,param,p1,p2,p3,p4)'];
   eval(['save ',PathWorkDir,name,...
         ' tfr sig t f fs method param p1 p2 p3 p4 SavedColorMap TfrView TfrQView']);
  elseif (nargin==9),
   TfrQView=['colormap(SavedColorMap); tfrqview(tfr,sig,t,method,p1,p2,p3,p4,p5)'];
   TfrView =['clf; colormap(SavedColorMap); tfrview(tfr,sig,t,method,param,p1,p2,p3,p4,p5)'];
   eval(['save ',PathWorkDir,name,...
         ' tfr sig t f fs method param p1 p2 p3 p4 p5 SavedColorMap TfrView TfrQView']);
  end;
  disp(' ');
  fprintf('The file is saved in the directory %s\n',PathWorkDir);
  fprintf('under the name %s\n',name);

  fprintf('If you want to find again the exact layout of this screen, do\n');
  fprintf('load %s%s; eval(TfrView);\n\n', PathWorkDir,name);
  fprintf('If you want to restart the display session under tfrqview, do\n');
  fprintf('load %s%s; eval(TfrQView);\n',PathWorkDir,name);
  CallTfrView=0;

 elseif (choice==ChoiceSaveOptions),                 % Save options
  SavedColorMap=colormap;
  save options fs fmin fmax threshold linlogtfr linlogspec levelnumb  ...
       display layout colmap SavedColorMap iscolorbar  ...
       isgridsig isgridspec isgridtfr issig sigenveloppe isspec;
  fprintf('\n Options saved\n');
  CallTfrView=0;

 elseif (choice==ChoicePrint),	                     % Print the current figure

  Nmethod=length(method);
  TFTBDevice = MENU('Choose a device',...
                    '-deps','-depsc','-deps2','-depsc2','-djpeg','-dtiff','other','cancel');
  if TFTBDevice==1,
   TFTBDeviceName='-deps '  ; TFTBExtension='.eps';
  elseif TFTBDevice==2,
   TFTBDeviceName='-depsc ' ; TFTBExtension='.eps';
  elseif TFTBDevice==3,
   TFTBDeviceName='-deps2 ' ; TFTBExtension='.eps';
  elseif TFTBDevice==4,
   TFTBDeviceName='-depsc2 '; TFTBExtension='.eps';
  elseif TFTBDevice==5,
   TFTBDeviceName='-djpeg ' ; TFTBExtension='.jpg';
  elseif TFTBDevice==6,
   TFTBDeviceName='-dtiff ' ; TFTBExtension='.tif';
  elseif TFTBDevice==7,
   TFTBDeviceName=input('device option : ','s'); ; TFTBDeviceName=[TFTBDeviceName,' '];
   TFTBExtension =input('file extension : ','s'); ;
  end;
  if TFTBDevice~=8,
   if comp(1:2)=='PC',
    DefaultName=[method(4:Nmethod),num2str(Nsig),TFTBExtension];
    [name,PathWorkDir] = uiputfile(DefaultName, 'Save As');
   else
    DefaultName=[method(4:Nmethod),num2str(Nsig),TFTBExtension];
    nameStr=[' file name [',DefaultName,'] : '];
    name=input(nameStr,'s');
    while (length(name)>8),
     disp('The name must have less than 8 characters');
     name=input(nameStr,'s');
    end
    if isempty(name),
     name=DefaultName;
    end
   end
   % ['print ', TFTBDeviceName, PathWorkDir, name]
   eval(['print ', TFTBDeviceName, PathWorkDir, name]);
   fprintf(' The file is saved in the directory %s\n',PathWorkDir);
   fprintf('under the name %s\n',name);
  end;
  CallTfrView=0;

 end;

end;

% good bye. I hope that everything happened fine.


function [z,output] = minf_lbfgsdl(f,g,z0,options)
%MINF_LBFGSDL Minimize a function by L-BFGS with dogleg trust region.
%   [z,output] = minf_lbfgsdl(f,g,z0) starts at z0 and attempts to find a
%   local minimizer of the real-valued function f(z). The input variables z
%   may be a scalar, vector, matrix, tensor or even a (nested) cell array
%   of tensors and its contents may be real or complex.
%
%   If f(x) is a function of real variables x, the function g(x) should
%   compute the partial derivatives of f with respect to the real variables
%   x, i.e. g(xk) := df(xk)/dx. If f(z) is a function of complex variables
%   z, the function g(z) should compute two times the partial derivative
%   of f with respect to conj(z) (treating z as constant), i.e. g(zk) :=
%   2*df(zk)/d(conj(z)) = 2*conj(df(zk)/dz). If g is the empty matrix [],
%   the real gradient or scaled conjugate cogradient is approximated with
%   finite differences. The output of the function g(z) may have the same
%   structure as z (although this is not necessary). The structure output
%   returns additional information:
%
%      output.alpha      - The plane search step lengths in every
%                          iteration, if a plane search is selected.
%      output.delta      - The trust region radius at every step attempt.
%      output.fevals     - The total number of function calls.
%      output.fval       - The value of the objective function f in every
%                          iteration.
%      output.gevals     - The total number of gradient calls.
%      output.info       - The circumstances under which the procedure
%                          terminated:
%                             1: Objective function tolerance reached.
%                             2: Step size tolerance reached.
%                             3: Maximum number of iterations reached.
%      output.infops     - The circumstances under which the plane search
%                          terminated in every iteration.
%      output.iterations - The number of iterations.
%      output.relfval    - The difference in objective function value
%                          between every two successive iterates, relative
%                          to its initial value.
%      output.relstep    - The step size relative to the norm of the
%                          current iterate in every iteration.
%      output.rho        - The trustworthiness at every step attempt.
%
%   minf_lbfgsdl(f,g,z0,options) may be used to set the following options:
%
%      options.Delta =            - The initial trust region radius.
%      0.3*max(1,norm(z0))
%      options.Display = 10       - Displays the objective function value,
%                                   its difference with the previous
%                                   iterate relative to the first iterate
%                                   and the relative step size each
%                                   options.Display iterations. Set to 0 to
%                                   disable.
%      options.M =                - The number of updates to store.
%      min(30,length(z0))
%      options.MaxIter = 500      - The maximum number of iterations.
%      options.PlaneSearch        - The plane search used to minimize the
%      = false                      objective function in the plane spanned
%                                   by the steepest descent direction and
%                                   the Gauss-Newton step. Disables dogleg
%                                   trust region strategy. The method
%                                   should have the function signature
%                                   options.PlaneSearch(F,dF,z,p1,p2, ...
%                                   state,options.PlaneSearchOptions).
%      options.PlaneSearchOptions - The options structure passed to the
%                                   plane search search routine.
%      options.TolFun = 1e-6      - The tolerance for output.relfval.
%      options.TolX = 1e-8        - The tolerance for output.relstep.

%   Authors: Laurent Sorber (Laurent.Sorber@cs.kuleuven.be)
%            Marc Van Barel (Marc.VanBarel@cs.kuleuven.be)
%            Lieven De Lathauwer (Lieven.DeLathauwer@kuleuven-kulak.be)
%
%   References:
%   [1] L. Sorber, M. Van Barel, L. De Lathauwer, "Unconstrained
%       optimization of real functions in complex variables", SIAM J. Opt.,
%       Vol. 22, No. 3, 2012, pp. 879-898.

% Store the structure of the input space and evaluate the gradient.
dim = structure(z0);
fval = f(z0);
if ~isa(g,'function_handle') && isempty(g)
    grad = serialize(deriv(f,z0,fval));
else
    grad = serialize(g(z0));
end
z0 = serialize(z0);

% Check the options structure.
if nargin < 4, options = struct; end
if ~isfield(options,'Delta'), options.Delta = 0.3*max(1,norm(z0)); end
if ~isfield(options,'Display'), options.Display = 10; end
if ~isfield(options,'M'), options.M = min(30,length(z0)); end
if ~isfield(options,'MaxIter'), options.MaxIter = 500; end
if ~isfield(options,'PlaneSearch'), options.PlaneSearch = false; end
if ~isfield(options,'PlaneSearchOptions')
    options.PlaneSearchOptions = struct;
end
if ~isfield(options,'TolFun'), options.TolFun = 1e-6; end
if ~isfield(options,'TolX'), options.TolX = 1e-8; end

% Initialize the algorithm.
S = zeros(numel(z0),options.M);
Y = zeros(numel(z0),options.M);
a = zeros(1,options.M);
r = zeros(1,options.M);
m = 0;
midx = 0;

% L-BFGS with dogleg trust region.
output.alpha = [];
output.delta = options.Delta;
output.fevals = 1;
output.fval = fval;
output.gevals = 1;
output.info = false;
output.infops = [];
output.iterations = 0;
output.relfval = [];
output.relstep = [];
output.rho = [];
while ~output.info

    % Compute the quasi-Newton step pqn = -H*grad.
    pqn = -grad;
    for i = 1:m
        a(i) = r(midx(i))*real(S(:,midx(i))'*pqn);
        pqn = pqn-a(i)*Y(:,midx(i));
    end
    if m > 0
        y1 = Y(:,midx(1));
        y1y1 = y1'*y1;
        gamma = y1y1*r(midx(1));
        pqn = 1/gamma*pqn;
    end
    for i = m:-1:1
        b = r(midx(i))*real(Y(:,midx(i))'*pqn);
        pqn = pqn+(a(i)-b)*S(:,midx(i));
    end

    % Approximate the Cauchy point pcp = -alpha*grad, where alpha is equal
    % to arg min m(-alpha*grad) and m(p) is a second order model of f at z.
    gg = grad'*grad;
    if m == 0
        alpha = 1;
    else
        s1 = S(:,midx(1));
        gBg = gg-real(grad'*s1)^2/(s1'*s1)+real(grad'*y1)^2/y1y1;
        gBg = gamma*gBg;
        alpha = gg/gBg;
    end

    % Plane search in the plane spanned by {pqn,pcp}.
    if isa(options.PlaneSearch,'function_handle')
        if output.iterations == 0, pcp = zeros(size(grad));
        else pcp = -alpha*grad; end
        state = output; state.grad = grad;
        [alpha,outputps] = options.PlaneSearch( ...
            f,g,deserialize(z0,dim),deserialize(pqn,dim), ...
            deserialize(pcp,dim),state,options.PlaneSearchOptions);
        output.alpha(:,end+1) = alpha;
        if length(alpha) < 3, alpha(3) = 1; end
        p = alpha(1)*pqn+alpha(2)*pcp;
        z = deserialize(alpha(3)*(z0+p),dim);
        relstep = norm(p)/norm(z0); if isnan(relstep), relstep = 0; end
        if isfield(outputps,'fval'), fval = outputps.fval;
        else fval = f(z); end
        if isfield(outputps,'info')
            output.infops(end+1) = outputps.info;
        end
        rho = 1;
    else
        rho = -inf;
    end

    % Dogleg trust region.
    normpqn = norm(pqn);
    while rho <= 0

        % Compute the dogleg step p.
        delta = output.delta(end);
        if normpqn <= delta
            p = pqn;
            dfval = -0.5*real(grad'*pqn);
        elseif abs(alpha)*sqrt(gg) >= delta
            p = (-delta/sqrt(gg))*grad;
            dfval = delta*(sqrt(gg)-0.5*delta/alpha);
        else
            bma = pqn+alpha*grad; bmabma = bma'*bma;
            a = -alpha*grad; aa = alpha^2*gg;
            c = real(a'*bma);
            if c <= 0
                beta = (-c+sqrt(c^2+bmabma*(delta^2-aa)))/bmabma;
            else
                beta = (delta^2-aa)/(c+sqrt(c^2+bmabma*(delta^2-aa)));
            end
            p = a+beta*bma;
            dfval = 0.5*alpha*(1-beta)^2*gg- ...
                    0.5*beta *(2-beta)*real(grad'*pqn);
        end

        % Compute the trustworthiness rho.
        if dfval > 0
            z = deserialize(z0+p,dim);
            fval = f(z);
            rho = (output.fval(end)-fval)/dfval;
            if isnan(rho), rho = -inf; end
            output.rho(end+1) = rho;
            output.fevals = output.fevals+1;
        end

        % Update trust region radius delta.
        if rho > 0.5
            output.delta(end+1) = max(delta,2*norm(p));
        else
            sigma = (1-0.25)/(1+exp(-14*(rho-0.25)))+0.25;
            if normpqn < sigma*delta && rho < 0
                e = ceil(log2(normpqn/delta)/log2(sigma));
                output.delta(end+1) = sigma^e*delta;
            else
                output.delta(end+1) = sigma*delta;
            end
        end

        % Check for convergence.
        relstep = norm(p)/norm(z0); if isnan(relstep), relstep = 0; end
        if rho <= 0 && relstep <= options.TolX
            output.rho(end+1) = rho;
            fval = output.fval(end);
            z = deserialize(z0,dim);
            break;
        end

    end

    % Save current state.
    if rho > 0
        z0 = serialize(z);
        grad1 = grad;
    end

    % Evaluate the gradient and update step information.
    if rho > 0
        if isa(options.PlaneSearch,'function_handle') && ...
           output.iterations >= 1 && isfield(outputps,'grad')
            grad = outputps.grad;
        elseif ~isa(g,'function_handle') && isempty(g)
            grad = serialize(deriv(f,z,fval));
        else
            grad = serialize(g(z));
        end
        s = p;
        y = grad-grad1;
        sy = real(y'*s);
        if sy > 0
            m = min(m+1,options.M);
            midx = [midx(1)+1:-1:1,m:-1:midx(1)];
            S(:,midx(1)) = s;
            Y(:,midx(1)) = y;
            r(:,midx(1)) = 1/sy;
        end
    end

    % Update the output structure.
    output.fval(end+1) = fval;
    output.gevals = output.gevals+1;
    output.iterations = output.iterations+1;
    output.relfval(end+1) = ...
        abs(diff(output.fval(end:-1:end-1)))/abs(output.fval(1));
    output.relstep(end+1) = relstep;
    if output.relfval(end) <= options.TolFun, output.info = 1; end
    if output.relstep(end) <= options.TolX, output.info = 2; end
    if output.iterations >= options.MaxIter, output.info = 3; end

    % Display progress.
    if options.Display > 0 && (output.iterations == 1 || output.info || ...
       mod(output.iterations,options.Display) == 0)
        if output.iterations == 1
            bold = '%s';
            [~,~,~,~,v] = regexp(version('-release'),'([0-9]+)([ab])');
            if usejava('Desktop') && str2double(v{1}{1}) > 2011 || ...
               (str2double(v{1}{1}) == 2011 && strcmpi(v{1}{2},'b'))
                bold = '%s';
            end
        end
        if output.iterations == 1 || ...
           mod(output.iterations,15*options.Display) == 0
            fprintf('\n%7s%s','',sprintf(bold,'fval'));
            fprintf('%13s%s','',sprintf(bold,'relfval'));
            fprintf('%10s%s','',sprintf(bold,'relstep'));
            if isa(options.PlaneSearch,'function_handle')
                fprintf('%10s%s','',sprintf(bold,'alpha'));
            else
                fprintf('%10s%s','',sprintf(bold,'delta'));
                fprintf('%8s%s','',sprintf(bold,'rho'));
            end
            fprintf('\n%21s%9s = %4.e %6s = %4.e\n\n','=1/2*norm(F)^2', ...
                    'TolFun',options.TolFun,'TolX',options.TolX);
        end
        if output.iterations == 1
            fprintf('%4i: % 14.8e |\n',0,output.fval(1));
        end
        if isa(options.PlaneSearch,'function_handle')
            stralpha = [repmat('%10.4e ',1,size(output.alpha,1)) '\n'];
            fprintf(['%4i: % 14.8e | %14.8e | %14.8e | ' stralpha], ...
                    output.iterations,output.fval(end), ...
                    output.relfval(end),output.relstep(end), ...
                    abs(output.alpha(:,end)));
        else
            fprintf(['%4i: % 14.8e | %14.8e | %14.8e | ' ...
                     '%10.4e | %10.4e\n'],...
                    output.iterations,output.fval(end), ...
                    output.relfval(end),output.relstep(end), ...
                    output.delta(end),output.rho(end));
        end
    end

end

% Display termination message.
if options.Display > 0
    ahref = '\n%s\n\n';
    x = round(linspace(0,output.iterations,min(500,output.iterations)));
    if length(bold) > 2
        ahref = sprintf(['\n%%s\n\n'],mat2str(x'), ...
            mat2str([output.fval(x+1)' [nan output.relfval(x(2:end))]' ...
                    [nan output.relstep(x(2:end))]'],3));
    end
    switch output.info
        case 1, fprintf(ahref,'Objective function tolerance reached.');
        case 2, fprintf(ahref,'Step size tolerance reached.');
        case 3, fprintf(ahref,'Maximum number of iterations reached.');
    end
end

end

function [z,offset] = deserialize(z,dim,offset)
    if iscell(dim)
        v = z;
        z = cell(size(dim));
        if nargin < 3, offset = 0; end
        for i = 1:numel(z)
            if iscell(dim{i})
                [z{i},offset] = deserialize(v,dim{i},offset);
            else
                n = prod(dim{i}(:));
                z{i} = reshape(v(offset+(1:n)),dim{i});
                offset = offset+n;
            end
        end
    elseif ~isempty(dim)
        z = reshape(z,dim);
    end
end

function z = serialize(z)
    if iscell(z)
        for i = find(cellfun(@iscell,z(:).'))
            z{i} = serialize(z{i});
        end
        s = cellfun(@numel,z(:)); o = [0; cumsum(s)];
        c = z; z = zeros(o(end),1);
        for i = 1:length(s), z(o(i)+(1:s(i))) = c{i}(:); end
    else
        z = z(:);
    end
end

function dim = structure(z)
    if iscell(z)
        dim = cellfun(@size,z,'UniformOutput',false);
        for i = find(cellfun(@iscell,z(:).'))
            dim{i} = structure(z{i});
        end
    else
        dim = size(z);
        if numel(z) == dim(1), dim = []; end
    end
end


function dn = jed_to_datenum ( jed )

%*****************************************************************************80
%
%% JED_TO_DATENUM converts a JED to a MATLAB date number.
%
%  Discussion:
%
%    The MATLAB "datenum" function accepts a string defining
%    a date and returns a datenumber:
%
%      dn = datenum ( 'Aug 17 1939' )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 June 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real JED, the Julian Ephemeris Date.
%
%    Output, real DN, a MATLAB date number.
%
  dn = jed - 1721058.5;

  return
end


function A = warmUpExercise()
% function [y1,...,yN] = myfun(x1,...,xN)
% above function 'myfun' takes argument (x1,...,xN) and returns y1,...,yN
% Return the 5x5 identity matrix in octave

A = eye(5);
end


% MatrixUser, a multi-dimensional matrix analysis software package
% https://sourceforge.net/projects/matrixuser/
%
% The MatrixUser is a matrix analysis software package developed under Matlab
% Graphical User Interface Developing Environment (GUIDE). It features
% functions that are designed and optimized for working with multi-dimensional
% matrix under Matlab. These functions typically includes functions for
% multi-dimensional matrix display, matrix (image stack) analysis and matrix
% processing.
%
% Author:
%   Fang Liu <leoliuf@gmail.com>
%   University of Wisconsin-Madison
%   Aug-30-2014

%update preview in panels
function MU_update_preview(axes_handle,TMatrix,V)

    axes(axes_handle);
    cla(axes_handle);
    imagesc(TMatrix(:, :, V.Slice),[V.C_lower V.C_upper]);
    colormap(V.Color_map);
    if V.Color_bar==1
        colorbar;
    end
    axis image;
    axis off;
end


function varargout = drawRect2(varargin)
%DRAWRECT2 Draw centered rectangle on the current axis
%
%   r = drawRect2(x, y, w, h) draw rectangle with width W and height H,
%   whose center is located at (x, y);
%
%   The four corners of rectangle are then :
%   (X-W/2, Y-H/2), (X+W/2, Y-H/2), (X+W/2, Y+H/2), (X-W/2, Y+H/2).
%
%   r = drawRect2(x, y, w, h, theta) also specifies orientation for
%   rectangle. Theta is given in radians.
%
%   r = drawRect2(coord) is the same as DRAWRECT2(X,Y,W,H), but all
%   parameters are packed into one array, whose dimensions is 4*1 or 5*1.
%
%   deprecated: use 'drawOrientedBox' instead
%
%   See Also :
%   drawRect
%
%   ---------
%
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 04/05/2004.
%

warning('polygons2d:deprecated', ...
    'This function is deprecated, use "drawOrientedBox" instead');

% default values
theta = 0;

% get entered values
if length(varargin)>3
    x = varargin{1};
    y = varargin{2};
    w = varargin{3};
    h = varargin{4};
    if length(varargin)>4
        theta = varargin{5};
    end
else
    coord = varargin{1};
    x = coord(:, 1);
    y = coord(:, 2);
    w = coord(:, 3);
    h = coord(:, 4);

    if length(coord)>4
        theta = coord(:, 5);
    else
        theta = zeros(size(x));
    end
end

% use only the half length of each rectanhle
w = w/2;
h = h/2;

hr = zeros(length(x), 1);
for i=1:length(x)
    tx = zeros(5, 1);
    ty = zeros(5, 1);

    tx(1) = x(i) - w(i)*cos(theta(i)) + h(i)*sin(theta(i));
    ty(1) = y(i) - w(i)*sin(theta(i)) - h(i)*cos(theta(i));

    tx(2) = x(i) + w(i)*cos(theta(i)) + h(i)*sin(theta(i));
    ty(2) = y(i) + w(i)*sin(theta(i)) - h(i)*cos(theta(i));

    tx(3) = x(i) + w(i)*cos(theta(i)) - h(i)*sin(theta(i));
    ty(3) = y(i) + w(i)*sin(theta(i)) + h(i)*cos(theta(i));

    tx(4) = x(i) - w(i)*cos(theta(i)) - h(i)*sin(theta(i));
    ty(4) = y(i) - w(i)*sin(theta(i)) + h(i)*cos(theta(i));

    tx(5) = x(i) - w(i)*cos(theta(i)) + h(i)*sin(theta(i));
    ty(5) = y(i) - w(i)*sin(theta(i)) - h(i)*cos(theta(i));

    hr(i) = line(tx, ty);
end

if nargout > 0
    varargout{1} = hr;
end


function im = vl_impattern(varargin)
% VL_IMPATTERN Generate an image from a stock pattern
%   IM=VLPATTERN(NAME) returns an instance of the specified
%   pattern. These stock patterns are useful for testing algoirthms.
%
%   All generated patterns are returned as an image of class
%   DOUBLE. Both gray-scale and colour images have range in [0,1].
%
%   VL_IMPATTERN() without arguments shows a gallery of the stock
%   patterns. The following patterns are supported:
%
%   Wedge::
%     The image of a wedge.
%
%   Cone::
%     The image of a cone.
%
%   SmoothChecker::
%     A checkerboard with Gaussian filtering on top. Use the
%     option-value pair 'sigma', SIGMA to specify the standard
%     deviation of the smoothing and the pair 'step', STEP to specfity
%     the checker size in pixels.
%
%   ThreeDotsSquare::
%     A pattern with three small dots and two squares.
%
%   UniformNoise::
%     Random i.i.d. noise.
%
%   Blobs:
%     Gaussian blobs of various sizes and anisotropies.
%
%   Blobs1:
%     Gaussian blobs of various orientations and anisotropies.
%
%   Blob:
%     One Gaussian blob. Use the option-value pairs 'sigma',
%     'orientation', and 'anisotropy' to specify the respective
%     parameters. 'sigma' is the scalar standard deviation of an
%     isotropic blob (the image domain is the rectangle
%     [-1,1]^2). 'orientation' is the clockwise rotation (as the Y
%     axis points downards). 'anisotropy' (>= 1) is the ratio of the
%     the largest over the smallest axis of the blob (the smallest
%     axis length is set by 'sigma'). Set 'cut' to TRUE to cut half
%     half of the blob.
%
%   A stock image::
%     Any of 'box', 'roofs1', 'roofs2', 'river1', 'river2', 'spotted'.
%
%   All pattern accept a SIZE parameter [WIDTH,HEIGHT]. For all but
%   the stock images, the default size is [128,128].

% Author: Andrea Vedaldi

% AUTORIGHTS

if nargin > 0
  pattern=varargin{1} ;
  varargin=varargin(2:end) ;
else
  pattern = 'gallery' ;
end

patterns = {'wedge','cone','smoothChecker','threeDotsSquare', ...
            'blob', 'blobs', 'blobs1', ...
            'box', 'roofs1', 'roofs2', 'river1', 'river2'} ;

% spooling
switch lower(pattern)
  case 'wedge', im = wedge(varargin) ;
  case 'cone', im = cone(varargin) ;
  case 'smoothchecker', im = smoothChecker(varargin) ;
  case 'threedotssquare', im = threeDotSquare(varargin) ;
  case 'uniformnoise', im = uniformNoise(varargin) ;
  case 'blob', im = blob(varargin) ;
  case 'blobs', im = blobs(varargin) ;
  case 'blobs1', im = blobs1(varargin) ;
  case {'box','roofs1','roofs2','river1','river2','spots'}
    im = stockImage(pattern, varargin) ;
  case 'gallery'
    clf ;
    num = numel(patterns) ;
    for p = 1:num
      vl_tightsubplot(num,p,'box','outer') ;
      imagesc(vl_impattern(patterns{p}),[0 1]) ;
      axis image off ;
      title(patterns{p}) ;
    end
    colormap gray ;
    return ;
  otherwise
    error('Unknown patter ''%s''.', pattern) ;
end

if nargout == 0
  clf ; imagesc(im) ; hold on ;
  colormap gray ; axis image off ;
  title(pattern) ;
  clear im ;
end

function [u,v,opts,args] = commonOpts(args)
opts.size = [128 128] ;
[opts,args] = vl_argparse(opts, args) ;
ur = linspace(-1,1,opts.size(2)) ;
vr = linspace(-1,1,opts.size(1)) ;
[u,v] = meshgrid(ur,vr);

function im = wedge(args)
[u,v,opts,args] = commonOpts(args) ;
im = abs(u) + abs(v) > (1/4) ;
im(v < 0) = 0 ;

function im = cone(args)
[u,v,opts,args] = commonOpts(args) ;
im = sqrt(u.^2+v.^2) ;
im = im / max(im(:)) ;

function im = smoothChecker(args)
opts.size = [128 128] ;
opts.step = 16 ;
opts.sigma = 2 ;
opts = vl_argparse(opts, args) ;
[u,v] = meshgrid(0:opts.size(1)-1, 0:opts.size(2)-1) ;
im = xor((mod(u,opts.step*2) < opts.step),...
         (mod(v,opts.step*2) < opts.step)) ;
im = double(im) ;
im = vl_imsmooth(im, opts.sigma) ;

function im = threeDotSquare(args)
[u,v,opts,args] = commonOpts(args) ;
im = ones(size(u)) ;
im(-2/3<u & u<2/3 & -2/3<v & v<2/3) = .75 ;
im(-1/3<u & u<1/3 & -1/3<v & v<1/3) = .50 ;
[drop,i] = min(abs(v(:,1))) ;
[drop,j1] = min(abs(u(1,:)-1/6)) ;
[drop,j2] = min(abs(u(1,:))) ;
[drop,j3] = min(abs(u(1,:)+1/6)) ;
im(i,j1) = 0 ;
im(i,j2) = 0 ;
im(i,j3) = 0 ;

function im = blobs(args)
[u,v,opts,args] = commonOpts(args) ;
im = zeros(size(u)) ;
num = 5 ;
square = 2 / num ;
sigma = square / 2 / 3 ;
scales = logspace(log10(0.5), log10(1), num) ;
skews = linspace(1,2,num) ;
for i=1:num
  for j=1:num
    cy = (i-1) * square + square/2 - 1;
    cx = (j-1) * square + square/2 - 1;
    A = sigma * diag([scales(i) scales(i)/skews(j)])  * [1 -1 ; 1 1] / sqrt(2)  ;
    C = inv(A'*A) ;
    x = u - cx ;
    y = v - cy ;
    im = im + exp(-0.5 *(x.*x*C(1,1) + y.*y*C(2,2) + 2*x.*y*C(1,2))) ;
  end
end
im = im / max(im(:)) ;

function im = blob(args)
[u,v,opts,args] = commonOpts(args) ;
opts.sigma = 0.15 ;
opts.anisotropy = .5 ;
opts.orientation = 2/3 * pi  ;
opts.cut = false ;
opts = vl_argparse(opts, args) ;
im = zeros(size(u)) ;
th = opts.orientation ;
R = [cos(th) -sin(th) ; sin(th) cos(th)] ;
A = opts.sigma * R * diag([opts.anisotropy 1]) ;
T = [0;0] ;
[x,y] = vl_waffine(inv(A),-inv(A)*T,u,v) ;
im = exp(-0.5 *(x.^2 + y.^2)) ;
if opts.cut
  im = im .* double(x > 0) ;
end

function im = blobs1(args)
[u,v,opts,args] = commonOpts(args) ;
opts.number = 5 ;
opts.sigma = [] ;
opts = vl_argparse(opts, args) ;
im = zeros(size(u)) ;
square = 2 / opts.number ;
num = opts.number ;
if isempty(opts.sigma)
  sigma = 1/6 * square ;
else
  sigma = opts.sigma * square ;
end
rotations = linspace(0,pi,num+1) ;
rotations(end) = [] ;
skews = linspace(1,2,num) ;
for i=1:num
  for j=1:num
    cy = (i-1) * square + square/2 - 1;
    cx = (j-1) * square + square/2 - 1;
    th = rotations(i) ;
    R = [cos(th) -sin(th); sin(th) cos(th)] ;
    A = sigma * R * diag([1 1/skews(j)]) ;
    C = inv(A*A') ;
    x = u - cx ;
    y = v - cy ;
    im = im + exp(-0.5 *(x.*x*C(1,1) + y.*y*C(2,2) + 2*x.*y*C(1,2))) ;
  end
end
im = im / max(im(:)) ;

function im = uniformNoise(args)
opts.size = [128 128] ;
opts.seed = 1 ;
opts = vl_argparse(opts, args) ;
state = vl_twister('state') ;
vl_twister('state',opts.seed) ;
im = vl_twister(opts.size([2 1])) ;
vl_twister('state',state) ;

function im = stockImage(pattern,args)
opts.size = [] ;
opts = vl_argparse(opts, args) ;
switch pattern
  case 'river1',  path='river1.jpg' ;
  case 'river2',  path='river2.jpg' ;
  case 'roofs1',  path='roofs1.jpg' ;
  case 'roofs2',  path='roofs2.jpg' ;
  case 'box',     path='box.pgm' ;
  case 'spots',   path='spots.jpg' ;
end
im = imread(fullfile(vl_root,'data',path)) ;
im = im2double(im) ;
if ~isempty(opts.size)
  im = imresize(im, opts.size) ;
  im = max(im,0) ;
  im = min(im,1) ;
end


function y = deadZone(u, thr)

    % DEADZONE implements a dead zone for the input u. If an element of u is
    %          lower (absolute value) than a user-defined threshold,
    %          consider that element of u as zero. u can be either a vector
    %          or a scalar.
    %
    % FORMAT: y = deadZone(u, thr)
    %
    % INPUT:  - u   = [n * 1] input vector;
    %         - thr = user-defined threshold;
    %
    % OUTPUT: - y   = [n * 1] filtered output.
    %
    % Authors: Daniele Pucci, Marie Charbonneau, Gabriele Nava
    %
    %          all authors are with the Italian Istitute of Technology (IIT)
    %          email: name.surname@iit.it
    %
    % Genoa, Dec 2018
    %

    %% --- Initialization ---

    % initialize output
    y = u;

    for i = 1:length(u)

        if abs(u(i)) < thr

            y(i) = 0;
        end
    end
end


function sF = acos(sF, varargin)
% cost of a function
% Syntax
%   sF = acos(sF)
%   sF = acos(sF, 'bandwidth', bandwidth)
%
% Input
%  sF - @S2FunHarmonic
%
% Output
%  sF - @S2FunHarmonic
%
% Options
%  bandwidth - minimal degree of the spherical harmonic
%

sF = sF.quadrature(@(v) acos(max(-1,min(1,sF.eval(v)))),varargin{:});

end


function K = kernelD(xp0,yp0,len)

D  = size(xp0,1);
N  = size(xp0,2);
M  = size(yp0,2);

% split M into chunks if on GPU to reduce memory usage
if isa(xp0,'gpuArray')
    K=gpuArray.zeros(N,M);
    cs  = 60;
elseif N > 10000
    K = zeros(N,M);
    cs = 10000;
else
    K= zeros(N,M);
    cs  = M;
end

for i = 1:ceil(M/cs)
    ii = [((i-1)*cs+1):min(M,i*cs)];
    mM = length(ii);
    xp = repmat(xp0,1,1,mM);
    yp = reshape(repmat(yp0(:,ii),N,1),D,N,mM);

    Kn = exp( -sum(bsxfun(@times,(xp - yp).^2,1./(len.^2))/2,1));
    K(:,ii)  = squeeze(Kn);

end


function Deff = electrolyteDiffusionCoefficients(ce,T,param,batterySection)
% electrolyteDiffusionCoefficients  Evaluates the diffusion coefficients for the electrolyte phase [m^2/s].
%
%   [Deff_p, Deff_s, Deff_n] = electrolyteDiffusionCoefficients(ce,T,param) evaluates
%   the diffusion coefficients for the anode, separator and cathode of the
%   battery.
%
%   Note that this is an interface for the main program. The authors
%   suggest to maintain the name of the function and its signature, while
%   modifying only the body of the script.
%
%   The diffusion coefficients can be evaluated in isothermal case
%   (param.TemperatureEnabled=0) or adiabatic case
%   (param.TemperatureEnabled=1 or 2).
%
%   You can modify the way that the diffusion coefficients are computed, as
%   function of electrolyte concentration and temperature. The main script
%   will pass also the param array.
%
%   The user can modify this script to meet particular requirements.

%   This file is part of the LIONSIMBA Toolbox
%
%	Official web-site: 	http://sisdin.unipv.it/labsisdin/lionsimba.php
% 	Official GitHUB: 	https://github.com/lionsimbatoolbox/LIONSIMBA
%
%   LIONSIMBA: A Matlab framework based on a finite volume model suitable for Li-ion battery design, simulation, and control
%   Copyright (C) 2016-2018 :Marcello Torchio, Lalo Magni, Davide Raimondo,
%                            University of Pavia, 27100, Pavia, Italy
%                            Bhushan Gopaluni, Univ. of British Columbia,
%                            Vancouver, BC V6T 1Z3, Canada
%                            Richard D. Braatz,
%                            Massachusetts Institute of Technology,
%                            Cambridge, Massachusetts 02142, USA
%
%   Main code contributors to LIONSIMBA 2.0:
%                           Ian Campbell, Krishnakumar Gopalakrishnan,
%                           Imperial college London, London, UK
%
%   LIONSIMBA is a free Matlab-based software distributed with an MIT
%   license.

if(param.TemperatureEnabled>=1)
    switch(batterySection)
        case 'p'
            Deff = param.eps_p^param.brugg_p*1e-4*10.^((-4.43-54./(T-229-5e-3*ce)-0.22e-3*ce));
        case 's'
            Deff = param.eps_s^param.brugg_s*1e-4*10.^((-4.43-54./(T-229-5e-3*ce)-0.22e-3*ce));
        case 'n'
            Deff = param.eps_n^param.brugg_n*1e-4*10.^((-4.43-54./(T-229-5e-3*ce)-0.22e-3*ce));
    end
else
    switch(batterySection)
        case 'p'
            Deff = repmat(param.Dp*param.eps_p^param.brugg_p,param.Np,1);
        case 's'
            Deff = repmat(param.Ds*param.eps_s^param.brugg_s,param.Ns,1);
        case 'n'
            Deff = repmat(param.Dn*param.eps_n^param.brugg_n,param.Nn,1);
    end
end

end


function [ a, b ] = p02_lim ( dim_num )

%*****************************************************************************80
%
%% P02_LIM returns the integration limits for problem 02.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the dimension of the argument.
%
%    Output, real A(DIM_NUM), B(DIM_NUM), the lower and upper
%    limits of integration.
%
  a(1:dim_num) = 0.0;
  b(1:dim_num) = 1.0;

  return
end


% eml_sps_os_test.m
% compare aspire and matlab versions of E-ML-SPS-OS
% Copyright Apr 2000, Jeff Fessler, The University of Michigan

%
% generate data
%
if ~isvar('yi'), printm 'data'
	if has_aspire
		f.dir	= test_dir;
		f.wtf	= [f.dir 't,g.wtf'];
		f.wtr	= strrep(f.wtf, 'wtf', 'wtr');
		f.yi	= [f.dir 'yi.fld'];
		f.ci	= [f.dir 'ci.fld'];
		f.ri	= [f.dir 'ri.fld'];
		f.mask	= [f.dir 'mask.fld'];
	end
	em_test_setup
%	em3_test_setup, n.a = n.n2; % kludge
prompt
end

if ~isvar('Gb'), printm 'make Gb'
	f.nblock = 5;
	Gb{1} = Gblock(G, 1);
	Gb{2} = Gblock(G, f.nblock);
prompt
end

%
% matlab iterations
%
if ~isvar('xmat'), printm 'matlab E-ML-SPS-OS'
	f.niter = 9;
	f.pixmax = 6;

	f.curvs = {'oc', 'pc'};

	xinit = ones(size(xtrue));
	for ic = 1:length(f.curvs)
		tmp = eql_sps_os(xinit(ig.mask), Gb{ic}, yi, ci, ri, [], ...
			f.niter, f.pixmax, f.curvs{ic});
		xmat{ic} = ig.embed(tmp);
	end
	im clf, im(xmat{1}, 'Matlab E-ML-SPS-OS iterations')
prompt
end

if ~has_aspire, return, end

%
% aspire iterations
%
if ~isvar('xasp'), printm 'aspire E-ML-SPS-OS'

	f.init	= [f.dir 'init.fld'];
	f.out	= [f.dir 'out.fld'];
	fld_write(f.init, xinit, 'check', 0)

	f.saver	= 'stack,1';
	f.fitype = ['2z@' f.wtr '@-'];

	for ic = 1:length(f.curvs)
		if exist(f.out, 'file'), delete(f.out), end
		f.alg = sprintf('ospsc,%s,%d,%d,1,0', f.curvs{ic}, Gb{ic}.nblock, sg.na);
		f.penal	= sprintf('%g,quad,0,-', -100);
		f.method = sprintf('@%d@%s@%s', f.niter-1, f.alg, f.penal);
		f.com = sprintf(['i -chat 0 empl3 %s %s  %s %s 1 %s 1 %s -' ...
				' %s %s 0 1 %g 0 -'], ...
			f.out, f.init, f.yi, f.ci, f.ri, f.fitype, ...
			f.method, f.saver, f.pixmax);
		os_run(f.com)

		xasp{ic} = double(fld_read(f.out));
	end
end

if 1
	for ic = 1:length(f.curvs)
		t = vcorrcoef(xasp{ic}, xmat{ic});
		printf('corr. [curv=%s block=%d] %g,%g', ...
			f.curvs{ic}, Gb{ic}.nblock, t, t-1)
	end
	ic = 2;

	im clf, im(221, xmat{ic}, 'xhat matlab')
	im(222, xasp{ic}, 'xhat aspire')
	im(223, (xasp{ic}-xmat{ic})/max(col(xmat{ic})), 'aspire-matlab'), cbar

	t1 = eql_obj(xmat{ic}, G, yi(:), ci(:), ri(:), [], ig.mask);
	t2 = eql_obj(xasp{ic}, G, yi(:), ci(:), ri(:), [], ig.mask);

	if im
		subplot(224)
		plot(0:f.niter-1, t1-t1(1), '-o', 0:f.niter-1, t2-t1(1), '-x')
		xlabel iteration, ylabel '\Phi change', legend('mat', 'asp', 4)
		title(sprintf('E-ML-SPS-OS, Nsubset=%d', Gb{ic}.nblock))
	end
end


% GP_COV_KRON - Covariance function as a product of two covariance
%                  functions.
%
% Usage:
%
%   COVFUNC = GP_COV_PRODUCT(COVFUNC1, COVFUNC2, ...)
%
% The returned covariance function is called as
%
%   K = COVFUNC(THETA)
%   [K, DK] = COVFUNC(THETA)
%
% where THETA is a vector of parameters. The parameters of COVFUNC1 and
% COVFUNC2 are concatenated into a single parameter vector.
%
% If no arguments are given, dimensionality information is returned:
%
%   [N_THETA, N1, N2] = COVFUNC()
%
% N_THETA : Number of non-fixed parameters
% N1      : Number of rows in the covariance matrix
% N2      : Number of columns in the covariance matrix
%
% See also GP_COV, GP_COV_SUM.

% Last modified 2012-03-14
% Copyright (c) Jaakko Luttinen (jaakko.luttinen@aalto.fi)

function func = gp_cov_kron(varargin)

if nargin < 2
  error('Must give at least two covariance functions')
end

func = @get_covariance;

covfuncs = varargin ;

% Number of covariance functions
n_funcs = nargin ;

% Number of parameters for each covariance function
n_theta = zeros(n_funcs,1) ;
% Dimensionalities of each covariance function
M = zeros(n_funcs,1) ;
N = zeros(n_funcs,1) ;
% Extract the values from the covariance functions
for i = 1:n_funcs
  [n_theta(i), M(i), N(i)] = varargin{i}();
end

% Indices of the hyperparameters for each covariance function
ind_theta = cell(n_funcs,1);
for i = 1:n_funcs
  ind_theta{i} = (1+sum(n_theta(1:(i-1)))):(sum(n_theta(1:i))) ;
end

%[n_theta2, M2, N2] = covfunc2();

%if M1 ~= M2 || N1 ~= N2
%  error('Can''t multiply covariance matrices with different dimensionalities');
%end

  function varargout = get_covariance(theta)

  if nargout == 0
    nout = 1;
  else
    nout = nargout;
  end

  varargout = cell(nout,1);

  out = cell(nout,1);
  %out2 = cell(nout,1);
  varargout = cell(nout,1);

  % Return only dimension information if requested
  if nargin == 0
    if nout >= 1
      varargout{1} = sum(n_theta); % number of parameters
      if nout >= 2
        varargout{2} = prod(M) ; % dimensionalities
        if nout >= 3
          varargout{3} = prod(N); % dimensionalities
        end
      end
    end
    return
  end

  if numel(theta) ~= sum(n_theta)
    error('Wrong number of parameters (%d), should be %d', numel(theta), ...
          sum(n_theta));
  end

  % Initialize covariance matrix and gradients
  varargout{1} = 1 ;
  if nout >= 2
    varargout{2} = cell(sum(n_theta),1) ;
    for i = 1:sum(n_theta)
      varargout{2}{i} = 1 ;
    end
  end

  % Compute the covariance matrix
  for i = 1:n_funcs
    [out{:}] = covfuncs{i}(theta(ind_theta{i}));
    varargout{1} = kron(varargout{1}, out{1});

    % Compute the derivative
    if nout >= 2 && ~isempty(ind_theta{i})
      % No derivative for these hyperparameters
      for n = 1:(ind_theta{i}(1)-1)
        varargout{2}{n} = kron(varargout{2}{n}, out{1}) ;
      end
      % Derivative for these hyperparameters
      for n = 1:n_theta(i)
        ind = ind_theta{i}(1) + n - 1 ;
        varargout{2}{ind} = kron(varargout{2}{ind}, out{2}{n}) ;
      end
      % No derivative for these hyperparameters
      for n = (ind_theta{i}(end)+1):sum(n_theta)
        varargout{2}{n} = kron(varargout{2}{n}, out{1}) ;
      end
    end
  end

  end

end

%function X = kronecker(varargin)

%X = varargin{1} ;
%for i = 2:nargin
%  X = kron(X, varargin{i}) ;
%end


function plotVR=SCARA_VR_PLOT(T1,T2,T4,d4b,dist)
SCARA30 = vrworld('SCARA30.wrl');
open(SCARA30)
    radian=T1*pi/180;
    SCARA30.a1.rotation = [1, 0, 0, radian];

    radian=-T2*pi/180;
    SCARA30.a2.rotation = [1, 0, 0, radian];

    radian=T4*pi/180;
    SCARA30.d4b.rotation = [0, 1, 0, radian];

    SCARA30.d4b.translation = [0, d4b, 0];

EndV1=SCARA30.EndV1.translation;
EndV2=SCARA30.EndV2.translation;
x1=EndV1(1);
x2=EndV2(1);
% y1=EndV1(2);
% y2=EndV2(2);
% sighn=sign([y1 y2]);
% y1f=.5*sighn(1)*dist
% y2f=.5*sighn(2)*dist
y1=-.5*dist;
y2=.5*dist;

SCARA30.EndV1.translation = [x1, y1, 0];
SCARA30.EndV2.translation = [x2, y2, 0];