%this is an example, demonstrating a Radial Basis Function method of vector
%acoustic tomography, using acoustic time-of-flight tomography as an
%example.
%This involves sending a sonic signal across a measurement area and timing
%how long it takes to travel.  A number of transducers are situated around
%the measurement area to achieve this.  Since the absolute sonic speed is
%effected by temperature and wind speed, so is the time of flight.  It is
%possible to reconstruct the temperature and wind velocity from the
%collection of time-of-flight data.
%For more information, please see ref [1] or http://blog.nutaksas.com
%
%References
%Wiens, Travis "Sensing of Turbulent Flows Using Real-Time Acoustic
%Tomography." X1Xth Biennial Conference of the NewZealand Acoustical
%Society, 2008.

%    Copyright Travis Wiens 2008
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%    If you would like to request that this software be licensed under a less
%    restrictive license (i.e. for commercial closed-source use) please
%    contact Travis at travis.mlfx@nutaksas.com

N_xd=16;%number of transducers
sig_dt=1e-6;%(s) std of error to add to dt
N_r=25;%number of radial basis functions

recalculate=true;%set this to false to skip recalculating
rbf_data_fname='gerris_rbf_data.mat';
if recalculate

    fprintf('Calculating forward problem...')
    gerris_fname='simsave-5.0.gfs';
    %this data was calculated using the Gerris Flow Solver
    %(http:gfs.sourceforge.net), from the Karman vortex street example

    %since Gerris data is not regular, we'll fit a RBF to the temperature
    %and velocity data, then use that to calculate the flight times
    data=load(gerris_fname);%load [x y z u v]

    N_rbf_f=300;%number of rbf centers for forward problem
    X_scale=10;%rescale data
    Sc_G=[3 3]*X_scale;%scale factor for gerris
    OS_G=[1 0];%(m) offset for gerris data

    X_limits=[-2 2;-2 2]*X_scale;%limits for training
    Xc_fu=[X_limits(1,1)+diff(X_limits(1,:))*rand(1,N_rbf_f);X_limits(2,1)+diff(X_limits(2,:))*rand(1,N_rbf_f)]';%model rbf centres
    Xc_fv=[X_limits(1,1)+diff(X_limits(1,:))*rand(1,N_rbf_f);X_limits(2,1)+diff(X_limits(2,:))*rand(1,N_rbf_f)]';
    Xc_fT=[X_limits(1,1)+diff(X_limits(1,:))*rand(1,N_rbf_f);X_limits(2,1)+diff(X_limits(2,:))*rand(1,N_rbf_f)]';

    x_G=(data(:,1)-OS_G(1))*Sc_G(1);%x for Gerris data
    y_G=(data(:,2)-OS_G(2))*Sc_G(2);%x for Gerris data
    U_idx=find((x_G>X_limits(1,1))&(x_G<X_limits(1,2))&(y_G>X_limits(2,1))&(y_G<X_limits(2,2)));
    x_G=x_G(U_idx);
    y_G=y_G(U_idx);

    k_fu=1*ones(N_rbf_f,1)/X_scale^2;%prescalar
    k_fv=1*ones(N_rbf_f,1)/X_scale^2;
    k_fT=4*ones(N_rbf_f,1)/X_scale^2;
    k_fu(1)=0;%allow for bias
    k_fv(1)=0;
    k_fT(1)=0;

    u0=mean(data(U_idx,4));%(m/s) base velocity
    v0=mean(data(U_idx,5));%(m/s) base velocity
    T=293+data(U_idx,6);%(K)  temperature
    T0=mean(T);%(K) base temperature
    [W_fu]=train_rbf([x_G y_G],data(U_idx,4)-u0,Xc_fu,k_fu);
    [W_fv]=train_rbf([x_G y_G],data(U_idx,5)-v0,Xc_fv,k_fv);
    [W_fT]=train_rbf([x_G y_G],T-T0,Xc_fT,k_fT);

    %set up transducers in a square
    N_dim=2;%number of dimensions
    X_xd=zeros(N_xd,N_dim);%XD positions
    phi=linspace(0,2*pi,N_xd+1);%angle of XD
    phi=phi+0.01*randn(size(phi));%move the xducers a bit
    r_xd=1*X_scale;%radius of circle inscribed in square
    X_xd_c=mean(X_limits,2)';%centre of circle
    for i=1:N_xd;
        if abs(tan(phi(i)))<1%intersects with verical lines
            X_xd(i,:)=X_xd_c+r_xd*[sign(cos(phi(i))) tan(phi(i))*sign(cos(phi(i)))];%set XD on a square
        else
            X_xd(i,:)=X_xd_c+r_xd*[ sign(sin(phi(i)))*tan(phi(i)).^-1 sign(sin(phi(i)))];%set XD on a square
        end
    end

    %now calculate pairs of XD to make paths
    X_xd0=[];
    X_xd1=[];
    idx=[];
    count=1;
    for i=1:N_xd
        for j=1:N_xd
            if i~=j%ignore path from XD to itself
                X_xd0(count,:)=X_xd(i,:);
                X_xd1(count,:)=X_xd(j,:);
                idx(count,:)=[i j];
                count=count+1;
            end
        end
    end
    N_paths=count-1;%number of paths

    X_limits_plot=(repmat(X_xd_c,2,1)+[-r_xd -r_xd;+r_xd +r_xd])';%limits to plot
    N_plot1=[25 25];%number of points to plot [x y]
    x_plot1=linspace(X_limits_plot(1,1),X_limits_plot(1,2),N_plot1(1))';
    y_plot1=linspace(X_limits_plot(2,1),X_limits_plot(2,2),N_plot1(2))';
    [x_mesh1 y_mesh1]=meshgrid(x_plot1,y_plot1);
    X_plot1=[reshape(x_mesh1,[],1) reshape(y_mesh1,[],1)];

    N_plot2=[100 100];%%higher resolution
    x_plot2=linspace(X_limits_plot(1,1),X_limits_plot(1,2),N_plot2(1))';
    y_plot2=linspace(X_limits_plot(2,1),X_limits_plot(2,2),N_plot2(2))';
    [x_mesh2 y_mesh2]=meshgrid(x_plot2,y_plot2);
    X_plot2=[reshape(x_mesh2,[],1) reshape(y_mesh2,[],1)];

    [u_rbf]=sim_rbf(Xc_fu,X_plot1,W_fu,k_fu);%simulate rbf fields
    [v_rbf]=sim_rbf(Xc_fv,X_plot1,W_fv,k_fv);
    [T_rbf]=sim_rbf(Xc_fT,X_plot1,W_fT,k_fT);

    [u_rbf2]=sim_rbf(Xc_fu,X_plot2,W_fu,k_fu);
    [v_rbf2]=sim_rbf(Xc_fv,X_plot2,W_fv,k_fv);
    [T_rbf2]=sim_rbf(Xc_fT,X_plot2,W_fT,k_fT);

    %calculate flight times analytically from RBF networks
    c0=340;%(m/s) sonic speed

    u_int=rbfn_integral(Xc_fu,X_xd0,X_xd1,W_fu,k_fu);%line integrals across rbfn
    v_int=rbfn_integral(Xc_fv,X_xd0,X_xd1,W_fv,k_fv);
    T_int=rbfn_integral(Xc_fT,X_xd0,X_xd1,W_fT,k_fT);
    theta=atan2(X_xd1(:,2)-X_xd0(:,2),X_xd1(:,1)-X_xd0(:,1));%(rad) angle of lines
    l=sqrt(sum((X_xd1-X_xd0).^2,2));%(m) path length
    dt0=l./c0.*(1-(u0*cos(theta)+v0*sin(theta))/c0)-...
            1/c0*(T_int/(2*T0)+u_int.*cos(theta)/c0+v_int.*sin(theta)/c0);%(s) time of flight

    save(rbf_data_fname,'dt0','l','theta','c0','T0','u_rbf','v_rbf','T_rbf','u_rbf2','v_rbf2','T_rbf2','X_plot1',...
        'X_plot2','x_plot1','x_plot2','y_plot1','y_plot2','N_plot1','N_plot2','N_paths','N_dim','X_xd','X_xd0',...
        'X_xd1','r_xd','u0','v0','X_xd_c','X_limits','X_scale','X_limits_plot')
    fprintf('done\n')
else
    load(rbf_data_fname)
end

%%%%%%%%%%%%%
%%%%%%%%%%%
%inversion
%%%%%%%%%%
%%%%%%%%%%%%

fprintf('Initializing inversion...')

basisfunction='gaussian';
k_scale=1/X_scale^2;%prescaler for basis function
alpha_scale=1.0e-6;%parameter for regularization alpha

dt=dt0+sig_dt*randn(size(dt0));%add noise to time of flight measurements

Xc_i=[X_limits(1,1)+diff(X_limits(1,:))*rand(1,N_r);X_limits(2,1)+diff(X_limits(2,:))*rand(1,N_r)]';%inversion rbf centres
k_i=k_scale*ones(N_r,1);
Omegapsi=Omegapsi_rbf(Xc_i,X_xd0,X_xd1,k_i,c0,basisfunction);
OmegaT=rbf_integral(Xc_i,X_xd0,X_xd1,k_i,basisfunction )/(c0*2*T0);
Omega=[OmegaT Omegapsi];
alpha_reg=alpha_scale*norm(Omega'*Omega);%regulatization parameter
A_rbf=pinv(Omega'*Omega+alpha_reg*eye(size(Omega,2)))*Omega';%solve!

%calculate matrices to get fields from weights
[zeta_u1 zeta_v1]=zeta_uv(Xc_i,X_plot1,k_i,basisfunction);
[zeta_u2 zeta_v2]=zeta_uv(Xc_i,X_plot2,k_i,basisfunction);
W_T_tmp=zeros(N_r,1);%placeholder
[tmp zeta_T1]=sim_rbf(Xc_i,X_plot1,W_T_tmp,k_i,basisfunction);
[tmp zeta_T2]=sim_rbf(Xc_i,X_plot2,W_T_tmp,k_i,basisfunction);

fprintf('done\n')

fprintf('Solving for weights...')
d_rbf=-dt+l/c0.*(1-(u0*cos(theta)+v0*sin(theta))/c0);%data vector
W=A_rbf*d_rbf;%weights
W_T=W(1:N_r);
W_U=W((N_r+1):end);
fprintf('done\n')

fprintf('Calculating fields...')
%calculate fields
u_hat1=zeta_u1*W_U;
v_hat1=zeta_v1*W_U;
u_hat2=zeta_u2*W_U;
v_hat2=zeta_v2*W_U;
T_hat1=zeta_T1*W_T;
T_hat2=zeta_T2*W_T;
fprintf('done\n')

EU_rms=sqrt(mean((u_rbf2-u_hat2).^2+(v_rbf2-v_hat2).^2));
ET_rms=sqrt(mean((T_rbf2-T_hat2).^2));

fprintf('EU_rms=%f m/s ET_rms=%f K\n',EU_rms,ET_rms)
fprintf('Cond(Omega^T*Omega)=%0.2e, Cond(Omega^T*Omega+alpha*eye)=%0.2e\n',cond(Omega'*Omega),cond(Omega'*Omega+alpha_reg*eye(size(Omega,2))))
fprintf('%d data, %d parameters, ratio=%f\n',size(Omega,1),size(Omega,2),size(Omega,2)/size(Omega,1))

figure(1)
clim=[min([T_rbf2; T_hat2]) max([T_rbf2; T_hat2])];
clf
subplot(2,1,1)
plot(nan,nan)
hold on
imagesc(x_plot2,y_plot2,reshape(T_rbf2,N_plot2(1),[]),clim)
plot([X_xd0(:,1) X_xd1(:,1)]',[X_xd0(:,2) X_xd1(:,2)]','wx:')
hold off
h=colorbar;
ylabel(h,'dT (K)')
axis tight
xlabel('x (m)')
ylabel('y (m)')
title('Target')

subplot(2,1,2)
plot(nan,nan)
hold on
imagesc(x_plot2,y_plot2,reshape(T_hat2,N_plot2(1),[]),clim)
plot([X_xd0(:,1) X_xd1(:,1)]',[X_xd0(:,2) X_xd1(:,2)]','wx:')
hold off
h=colorbar;
ylabel(h,'dT_{hat} (K)')
axis tight
xlabel('x (m)')
ylabel('y (m)')
title('Reconstruction')

figure(2)
plot(nan,nan)
hold on
imagesc(x_plot2,y_plot2,reshape(sqrt((T_hat2-T_rbf2).^2),N_plot2(1),[]))
%plot([X_xd0(:,1) X_xd1(:,1)]',[X_xd0(:,2) X_xd1(:,2)]','kx-')
hold off
h=colorbar;
ylabel(h,'RMSE (K)')
axis tight
xlabel('x (m)')
ylabel('y (m)')

figure(3)
plot(nan,nan)
hold on
imagesc(x_plot2,y_plot2,reshape(sqrt((u_hat2-u_rbf2).^2+(v_hat2-v_rbf2).^2),N_plot2(1),[]))
h=colorbar;
h1=quiver(x_plot1,y_plot1,reshape(u_rbf,N_plot1(1),[]),reshape(v_rbf,N_plot1(1),[]),'k');
h2=quiver(x_plot1,y_plot1,reshape(u_hat1,N_plot1(1),[]),reshape(v_hat1,N_plot1(1),[]));
hold off
axis tight
xlabel('x (m)')
ylabel('y (m)')
ylabel(h,'E (m/s)')
legend([h1;h2],'Target','Reconstruction')


% Copyright (C) 2013 Quan Wang <wangq10@rpi.edu>,
% Signal Analysis and Machine Perception Laboratory,
% Department of Electrical, Computer, and Systems Engineering,
% Rensselaer Polytechnic Institute, Troy, NY 12180, USA
%
% You are free to use this software for academic purposes if you cite our paper:
% Quan Wang and Kim L. Boyer.
% Feature Learning by Multidimensional Scaling and its Applications in Object Recognition.
% 2013 26th SIBGRAPI Conference on Graphics, Patterns and Images (Sibgrapi). IEEE, 2013.
%
% For commercial use, please contact the authors.

% The target function to be minimized at each step.

function f=MDS_cost_vector(x,V_dist,X)

X=bsxfun(@minus,X,x);
V=sum(X.*X,2);
f=sqrt(V)-V_dist;


% DEMROBOTWIRELESSFGPLVM2 Wireless Robot data from University of Washington, without dynamics and without back constraints.

% FGPLVM

% Fix seeds
randn('seed', 1e5);
rand('seed', 1e5);

dataSetName = 'robotWireless';
experimentNo = 2;

% load data
[Y, lbls] = lvmLoadData(dataSetName);

% Set up model
options = fgplvmOptions('ftc');
options.back = 'mlp';
options.backOptions = mlpOptions;

latentDim = 2;
d = size(Y, 2);

model = fgplvmCreate(latentDim, d, Y, options);

% Optimise the model.
iters = 1000;
display = 1;

model = fgplvmOptimise(model, display, iters);

% Save the results.
modelWriteResult(model, dataSetName, experimentNo);

if exist('printDiagram') & printDiagram
  lvmPrintPlot(model, lbls, dataSetName, experimentNo);
end

% Load the results and display dynamically.
lvmResultsDynamic(model.type, dataSetName, experimentNo, 'vector')


function [hr] = ns2hr(ns)
% Convert time from nanoseconds to hours.
% Chad Greene 2012
hr = ns*2.777777777778e-13 ;


function msm_to_mm_test17 ( )

%*****************************************************************************80
%
%% MSM_TO_MM_TEST17 tests MSM_TO_MM_COORDINATE_INTEGER_SYMMETRIC.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 November 2008
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'MSM_TO_MM_TEST17\n' );
  fprintf ( 1, '  Convert an MSM to MM coordinate integer symmetric format.\n' );

  output_filename = 'msm_to_mm_test17.mm';

  a = i4mat_indicator ( 4, 4 );
  a = a + a';
%
%  Have MSM_TO_MM write the matrix to a file.
%
  msm_to_mm ( output_filename, a, 'coordinate', 'integer', 'symmetric' );

  return
end


function new_hist = merge_histograms(sp, parts)
% Merges the histograms of several superpixels by weighting the individual
% histograms by the superpixel sizes. This gives the actual histogram of
% the combined superpixel.

partsize = zeros(1, length(parts));
for i = 1:length(parts)
    partsize(i) = sp{parts(i)}.size;
end

for fn = 1:length(sp{1}.hist)
    new_hist{fn} = zeros(length(sp{1}.hist{fn}),1);
    cc = 0;
    for i = 1:length(parts)
        cur_hist = sp{parts(i)}.hist{fn};
        if sum(cur_hist) > 0 % skip empty histograms
            new_hist{fn} = new_hist{fn} + partsize(i)*cur_hist;
            cc = cc + partsize(i);
        end
    end
    if cc > 0
        new_hist{fn} = new_hist{fn}/cc; % normalization
    else
        % If there are only empty histograms, the output histogram remains as a vector of zeros
    end
end


classdef RWMOP27 < PROBLEM
% <multi> <real> <constrained>
% Process flow sheeting problem

%------------------------------- Reference --------------------------------
% A. Kumar, G. Wu, M. Ali, Q. Luo, R. Mallipeddi, P. Suganthan, and S. Das,
% A benchmark-suite of real-world constrained multi-objective optimization
% problems and some baseline results, Swarm and Evolutionary Computation,
% 2021, 67: 100961.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    methods
        %% Initialization
        function Setting(obj)
            obj.M        = 2;
            obj.D        = 3;
            obj.lower    = [0.2,-2.22554,-0.49];
            obj.upper    = [1,-1,1.49];
            obj.encoding = ones(1,obj.D);
        end
        %% Evaluate multiple solutions
        function Population = Evaluation(obj,varargin)
            x  = varargin{1};
            x1 = x(:,1); x2 = x(:,2); x3 = x(:,3);
            % Objective function
            f(:,1) = -0.7.*x3 + 0.8 + 5.*(0.5 - x1).^2;
            f(:,2) = x1 - x3;
            % Constraints
            g(:,1) = -(exp(x1 - 0.2) + x2);
            g(:,2) = x2 + 1.1.*x3 - 1;
            g(:,3) = x1 - x3 - 0.2;
            Population = SOLUTION(varargin{1},f,g,varargin{2:end});
            obj.FE     = obj.FE + length(Population);
        end
        %% Generate a point for hypervolume calculation
        function R = GetOptimum(obj,~)
            R = [-2.4300000e-01   0.0000000e+00];
        end
    end
end


function [t,x_new,f_new,g_new,funEvals,H] = ArmijoBacktrack(...
    x,t,d,f,fr,g,gtd,c1,LS,tolX,debug,doPlot,saveHessianComp,funObj,varargin)
%
% Backtracking linesearch to satisfy Armijo condition
%
% Inputs:
%   x: starting location
%   t: initial step size
%   d: descent direction
%   f: function value at starting location
%   fr: reference function value (usually funObj(x))
%   gtd: directional derivative at starting location
%   c1: sufficient decrease parameter
%   debug: display debugging information
%   LS: type of interpolation
%   tolX: minimum allowable step length
%   doPlot: do a graphical display of interpolation
%   funObj: objective function
%   varargin: parameters of objective function
%
% Outputs:
%   t: step length
%   f_new: function value at x+t*d
%   g_new: gradient value at x+t*d
%   funEvals: number function evaluations performed by line search
%   H: Hessian at initial guess (only computed if requested

% Evaluate the Objective and Gradient at the Initial Step
if nargout == 6
    [f_new,g_new,H] = feval(funObj, x + t*d, varargin{:});
else
    [f_new,g_new] = feval(funObj, x + t*d, varargin{:});
end
funEvals = 1;

while f_new > fr + c1*t*gtd || ~isLegal(f_new)

    temp = t;
    if LS == 0 || ~isLegal(f_new)
        % Backtrack w/ fixed backtracking rate
        if debug
            fprintf('Fixed BT\n');
        end
        t = 0.5*t;
    elseif LS == 2 && isLegal(g_new)
        % Backtracking w/ cubic interpolation w/ derivative
        if debug
            fprintf('Grad-Cubic BT\n');
        end
        t = polyinterp([0 f gtd; t f_new g_new'*d],doPlot);
    elseif funEvals < 2 || ~isLegal(f_prev)
        % Backtracking w/ quadratic interpolation (no derivative at new point)
        if debug
            fprintf('Quad BT\n');
        end
        t = polyinterp([0 f gtd; t f_new sqrt(-1)],doPlot);
    else%if LS == 1
        % Backtracking w/ cubic interpolation (no derivatives at new points)
        if debug
            fprintf('Cubic BT\n');
        end
        t = polyinterp([0 f gtd; t f_new sqrt(-1); t_prev f_prev sqrt(-1)],doPlot);
    end

    % Adjust if change in t is too small/large

    if t < temp*1e-3
        if debug
            fprintf('Interpolated Value Too Small, Adjusting\n');
        end
        t = temp*1e-3;
    elseif t > temp*0.6
        if debug
            fprintf('Interpolated Value Too Large, Adjusting\n');
        end
        t = temp*0.6;
    end

    f_prev = f_new;
    t_prev = temp;
    if ~saveHessianComp && nargout == 6
        [f_new,g_new,H] = feval(funObj, x + t*d, varargin{:});
    else
        [f_new,g_new] = feval(funObj, x + t*d, varargin{:});
    end
    funEvals = funEvals+1;

    % Check whether step size has become too small
    if sum(abs(t*d)) <= tolX
        if debug
            fprintf('Backtracking Line Search Failed\n');
        end
        t = 0;
        f_new = f;
        g_new = g;
        break;
    end
end

% Evaluate Hessian at new point
if nargout == 6 && funEvals > 1 && saveHessianComp
    [f_new,g_new,H] = feval(funObj, x + t*d, varargin{:});
    funEvals = funEvals+1;
end

x_new = x + t*d;

end


function pass = test_volt(pref)

if ( nargin == 0 )
    pref = chebfunpref();
end

K = @(u, v) exp(-(u-v).^2);     % A simple kernel.
f = chebfun(@sin, pref);        % A simple chebfun.
F = volt(K, f);                 % Call volt().

% Test against some V4 results:
pass(1) = abs(F(.5) - (-0.013808570536509)) < 10*vscale(F)*eps;
pass(2) = abs(norm(F) - 0.334612395278957) < 10*vscale(F)*eps;

% Test 3rd input argument. (Simply make sure we don't crash!)
try
    F2 = volt(K, f, 1);
    pass(3) = 1;
catch
    pass(3) = 0;
end

end


% Digital Video Stabilization and Rolling Shutter Correction using Gyroscopes
% Copyright (C) 2011 Alexandre Karpenko
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

function nw = resample_rotation_rate(w, old_time, new_time)

dT = old_time(2:end) - old_time(1:end-1);
theta = cumsum( w(2:end) .* dT );

new_theta = interp1(old_time(2:end), theta(:,1), new_time);

%{
figure(1);
plot(old_time(2:end), theta, 'rx-'); hold on;
plot(new_time, new_theta, 'bo-'); hold off;
%}

nw = (new_theta(2:end) - new_theta(1:end-1)) ./ (new_time(2:end) - new_time(1:end-1));
nw(isnan(nw)) = 0;
nw = [0; nw];

%{
figure(2);
plot(old_time, w(:,1), 'rx-'); hold on;
plot(new_time, nw, 'bo-'); hold off;
%}


% a script to reproduce table 1 of paper :
%
%   ``Rotation, Scaling and Deformation Invariant Scattering
%   for Texture Discrimination"
%   Laurent Sifre, Stephane Mallat
%   Proc. IEEE CVPR 2013 Portland, Oregon
%
% Scattering classification rates for UIUC databases
%
% NOTE : Computing the scattering for the whole database takes time.
% We provide PRECOMPUTED scattering in the files
%   precomputed/uiuc/trans_scatt.mat
%   precomputed/uiuc/roto_trans_scatt.mat
%   precomputed/uiuc/roto_trans_scatt_log.mat
%   precomputed/uiuc/roto_trans_scatt_log_scale_avg.mat
%   precomputed/uiuc/roto_trans_scatt_log_scale_avg_multiscal_train.mat
% You can COMPUTE THE SCATTERING YOURSELF by changing the following line :
%   use_precomputed_scattering = 0;
%
% DOWNLOAD : The UIUC database can be downloaded at
%   http://www.nada.kth.se/cvap/databases/uiuc/kth_tips_grey_200x200.tar

%% load the database
clear; close all;
% NOTE : the following line must be modified with the path to the
% uiuc database in YOUR system.
path_to_db = '/Users/laurentsifre/TooBigForDropbox/Databases/cvr_uiuc';
src = uiuc_src(path_to_db);
db_name = 'uiuc';

use_precomputed_scattering = 0; % change to 0 to skip computation of scattering

grid_train = [5, 10, 20]; % number of training for classification
nb_split = 10; % number of split for classification

%% ---------------------------------------------------
%% ----------------- trans_scatt ---------------------
%% ---------------------------------------------------

%% compute scattering of all images in the database
feature_name = 'trans_scatt';
precomputed_path = sprintf('./precomputed/%s/%s.mat', db_name, feature_name);
if (use_precomputed_scattering)
    load(precomputed_path);
else
    %configure scattering
    options.J = 5; % number of octaves
    options.Q = 1; % number of scales per octave
    options.M = 2; % scattering orders

    % build the wavelet transform operators for scattering
    Wop = wavelet_factory_2d_spatial(options, options);

    % a function handle that
    %   - read the image
    %   - resize it to 200x200
    %   - compute its scattering
    fun = @(filename)(scat(imresize_notoolbox(imreadBW(filename)...
        ,[200 200]), Wop));

    % compute all scattering
    % (800 seconds on a 2.4 Ghz Intel Core i7)
    trans_scatt_all = srcfun(fun, src);

    % a function handle that
    %   - format the scattering in a 3d matrix
    %   - remove margins
    %   - average accross position
    % (10 seconds on a 2.4 Ghz Intel Core i7)
    fun = @(Sx)(mean(mean(remove_margin(format_scat(Sx),0),2),3));
    trans_scatt = cellfun_monitor(fun ,trans_scatt_all);

    % save scattering
    save(precomputed_path, 'trans_scatt');
end
% format the database of feature
db = cellsrc2db(trans_scatt, src);

%% classification
rsds_classif(db, db_name, feature_name, grid_train, nb_split);

%% ---------------------------------------------------
%% --------------- roto_trans_scatt ------------------
%% ---------------------------------------------------

%% compute scattering of all images in the database
feature_name = 'roto_trans_scatt';
precomputed_path = sprintf('./precomputed/%s/%s.mat', db_name, feature_name);
if (use_precomputed_scattering)
    load(precomputed_path);
else
    % configure scattering
    options.J = 5; % number of octaves
    options.Q = 1; % number of scales per octave
    options.M = 2; % scattering orders

    % build the wavelet transform operators for scattering
    Wop = wavelet_factory_3d_spatial(options, options, options);

    % a function handle that
    %   - read the image
    %   - resize it to 200x200
    %   - compute its scattering
    fun = @(filename)(scat(imresize_notoolbox(imreadBW(filename),[200 200]), Wop));
    % (1000 seconds on a 2.4 Ghz Intel Core i7)
    roto_trans_scatt_all = srcfun(fun, src);

    % a function handle that
    %   - format the scattering in a 3d matrix
    %   - remove margins
    %   - average accross position
    fun = @(Sx)(mean(mean(remove_margin(format_scat(Sx),1,[2,3]),2),3));
    % (10 seconds on a 2.4 Ghz Intel Core i7)
    roto_trans_scatt = cellfun_monitor(fun ,roto_trans_scatt_all);

    % save scattering
    save(precomputed_path, 'roto_trans_scatt');
end
% format the database of feature
db = cellsrc2db(roto_trans_scatt, src);

%% classification
rsds_classif(db, db_name, feature_name, grid_train, nb_split);

%% ---------------------------------------------------
%% ------------- roto_trans_scatt_log ----------------
%% ---------------------------------------------------

feature_name = 'roto_trans_scatt_log';
precomputed_path = sprintf('./precomputed/%s/%s.mat', db_name, feature_name);
if (use_precomputed_scattering)
    load(precomputed_path);
else
    % a function handle that
    %   - format the scattering in a 3d matrix
    %   - take the logarithm
    %   - remove margins
    %   - average accross position
    fun = @(Sx)(mean(mean(log(remove_margin(format_scat(Sx),1,[2,3])),2),3));
    roto_trans_scatt_log = cellfun_monitor(fun ,roto_trans_scatt_all);

    %save scattering
    save(precomputed_path);
end
% format the database of feature
db = cellsrc2db(roto_trans_scatt_log, src);

%% classification
rsds_classif(db, db_name, feature_name, grid_train, nb_split);

%% ---------------------------------------------------
%% ---------- roto_trans_scatt_log_scale_avg ---------
%% ---------------------------------------------------

%% compute scattering of all images in the database

feature_name = 'roto_trans_scatt_log_scale_avg';
precomputed_path = sprintf('./precomputed/%s/%s.mat', db_name, feature_name);

if (use_precomputed_scattering)
    load(precomputed_path);
else
    % configure scattering
    options.J = 5; % number of octaves
    options.Q = 1; % number of scales per octave
    options.M = 2; % scattering orders

    % build the wavelet transform operators for scattering
    Wop = wavelet_factory_3d_spatial(options, options, options);

    % a function handle that compute scattering given an image
    fun = @(x)(scat(x, Wop));

    % another function handle that
    %   - read the image
    %   - resize it to 200x200
    %   - apply fun to all scaled version of the image
    multi_fun = @(filename)(fun_multiscale(fun, ...
        imresize_notoolbox(imreadBW(filename),[200 200]), sqrt(2), 4));

    % (2748 seconds on a 2.4 Ghz Intel Core i7)
    roto_trans_scatt_multiscale = srcfun(multi_fun, src);

    %% log + spatial average
    fun = @(Sx)(mean(mean(log(remove_margin(format_scat(Sx),1,[2,3])),2),3));
    multi_fun = @(x)(cellfun_monitor(fun, x));
    roto_trans_scatt_multiscale_log_sp_avg = cellfun_monitor(multi_fun, roto_trans_scatt_multiscale);

    %% scale average
    fun = @(x)(mean(cell2mat(x),2));
    roto_trans_scatt_log_scale_avg = cellfun_monitor(fun, roto_trans_scatt_multiscale_log_sp_avg);

    % save scattering
    save(precomputed_path, 'roto_trans_scatt_log_scale_avg');

    % format the database of feature
    db = cellsrc2db(roto_trans_scatt_log_scale_avg, src);
end

%% classification
rsds_classif(db, db_name, feature_name, grid_train, nb_split);

%% ---------------------------------------------------
%% - roto_trans_scatt_log_scale_avg_multiscal_train --
%% ---------------------------------------------------


clear; clc; close all;

for repeat = 1:5
close all;

dataset = 'movielens10m';
load(strcat('../../noncvx-lowrank(ICDM 2015)/data/recsys/', dataset, '.mat'));
% load('matlab.mat');

clear item user Movie;

[row, col, val] = find(data);
idx = randperm(length(val));

val = val - mean(val);
val = val/std(val);

traIdx = idx(1:floor(length(val)*0.5));
tstIdx = idx(ceil(length(val)*0.5): end);

clear idx;

traData = sparse(row(traIdx), col(traIdx), val(traIdx), size(data,1), size(data,2));

para.maxIter = 100000;
para.tol = 1e-5;

para.test.row  = row(tstIdx);
para.test.col  = col(tstIdx);
para.test.data = val(tstIdx);
para.test.m = size(traData, 1);
para.test.n = size(traData, 2);

% ---------------------------------------------------------------
switch (dataset)
    case 'movielens100k'
        lambdaMax = 30;
        gridLambda = lambdaMax*(0.9).^(0:9);
    case 'movielens1m'
        lambdaMax = 35;
        gridLambda = lambdaMax*(0.95).^(0:9);
    case 'movielens10m'
        gridLambda = 60;
end

clear lambdaMax;

gridRMSE = zeros(2, size(gridLambda,2 ));
gridRank = zeros(1, size(gridLambda,2 ));
for g = 1:length(gridLambda)
    lambda = gridLambda(g);

    [U, S, V] = SoftImpute(traData, lambda, para );
    [U, S, V, out] = AISImpute(traData, lambda, para );
    gridRank(g) = nnz(S);

    gridRMSE(1, g) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));

    [ U, S, V ] = PostProcess(traData, U, V, S);

    gridRMSE(2, g) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));

    if(g > 1 && gridRMSE(2, g) > gridRMSE(2, g - 1))
        break;
    end
end

gridRMSE = gridRMSE(2,1:g);
[~, lambda] = min(gridRMSE);
gndRank = gridRank(lambda);

switch (dataset)
    case 'movielens100k'
        para.maxR = ceil(gndRank*1.2);
    case 'movielens1m'
        para.maxR = ceil(gndRank*1.2);
    case 'movielens10m'
        para.maxR = ceil(gndRank*1.5);
end

lambda = gridLambda(lambda);

clear gridRMSE gridRank g X U S V gridLambda out data;

% active --------------------------------------------------------
method = 1;
t = tic;
[U, S, V, out{method}] = ActiveSubspace(traData, lambda, para );
Time(method) = toc(t);
RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));

[ U, S, V ] = PostProcess(traData, U, V, S);
RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
clear U S V t;

out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));

figure(1);
plot(out{method}.Time, out{method}.RMSE);
hold on;
figure(2);
semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));
hold on;

% boost ---------------------------------------------------------
method = 2;
t = tic;
[U, S, V, out{method}] = Boost( traData, lambda, para);
Time(method) = toc(t);
Time(method) = toc(t);
RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));

[ U, S, V ] = PostProcess(traData, U, V, S);
RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
clear U S V t;

out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));

figure(1);
plot(out{method}.Time, out{method}.RMSE);
figure(2);
semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

% % TR ------------------------------------------------------------
% method = 3;
% t = tic;
% [U, S, V, out{method}] = MMBS( traData, lambda, para );
% Time(method) = toc(t);
% Time(method) = toc(t);
% RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
%
% [ U, S, V ] = PostProcess(traData, U, V, S);
% RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
% clear U S V t;
%
% out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));
%
% figure(1);
% plot(out{method}.Time, out{method}.RMSE);
% figure(2);
% semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

% ALT-Impute ----------------------------------------------------
method = 4;
t = tic;
[U, S, V, out{method}] = SoftImputeALS( traData, lambda, para.maxR, para );
Time(method) = toc(t);
RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));

[ U, S, V ] = PostProcess(traData, U, V, S);
RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
clear U S V t;

out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));

figure(1);
plot(out{method}.Time, out{method}.RMSE);
figure(2);
semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

% % SSGD ----------------------------------------------------------
% method = 5;
% t = tic;
% [U, S, V, out{method}] = SSGD( traData, lambda, gndRank, para );
% Time(method) = toc(t);
% RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
%
% [ U, S, V ] = PostProcess(traData, U, V, S);
% RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
% clear U S V t;
%
% out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));
%
% figure(1);
% plot(out{method}.Time, out{method}.RMSE);
% figure(2);
% semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

% LMaFit --------------------------------------------------------
% gridRMSE = zeros(1, 10);
% for g = 1:10
%     [U, S, V] = FixedRank( traData, g, para );
%
%     gridRMSE(g) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
%
% %     if(g > 1 && gridRMSE(g) > gridRMSE(g - 1))
% %         break;
% %     end
% end
%
% gridRMSE = gridRMSE(1:g);
% [~, rnk] = min(gridRMSE);
%
% clear gridRMSE X g U S V;

switch (dataset)
    case 'movielens100k'
        rnk = 3;
    case 'movielens1m'
        rnk = 7;
    case 'movielens10m'
        rnk = 12;
end

method = 6;
t = tic;
[U, S, V, out{method}] = FixedRank( traData, rnk, para );
Time(method) = toc(t);

RMSE(2, method) = out{method}.RMSE(end);

figure(1);
plot(out{method}.Time, out{method}.RMSE);
figure(2);
semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

% %% APG -----------------------------------------------------------
% method = 7;
% t = tic;
% [U, S, V, out{method}] = APGMatComp( traData, lambda, para );
% Time(method) = toc(t);
% RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
%
% [ U, S, V ] = PostProcess(traData, U, V, S);
% RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
% clear U S V t;
%
% out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));
%
% figure(1);
% plot(out{method}.Time, out{method}.RMSE);
% figure(2);
% semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

%% Soft-Impute ---------------------------------------------------
method = 8;
t = tic;
[U, S, V, out{method}] = SoftImpute( traData, lambda, para );
Time(method) = toc(t);
RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));

[ U, S, V ] = PostProcess(traData, U, V, S);
RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
clear U S V t;

out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));

figure(1);
plot(out{method}.Time, out{method}.RMSE);
figure(2);
semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

%% AISImpute -----------------------------------------------------
method = 9;
t = tic;
[U, S, V, out{method}] = AISImpute( traData, lambda, para );
Time(method) = toc(t);
RMSE(1, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));

[ U, S, V ] = PostProcess(traData, U, V, S);
RMSE(2, method) = MatCompRMSE(U, V, S, row(tstIdx), col(tstIdx), val(tstIdx));
clear U S V t;

out{method}.RMSE = out{method}.RMSE - (RMSE(1, method) - RMSE(2, method));

figure(1);
plot(out{method}.Time, out{method}.RMSE);
figure(2);
semilogy(out{method}.Time, out{method}.obj - min(out{method}.obj));

% clear col data gndRank lambda method para rnk row traData traIdx tstIdx val Age movies;

figure(1);
xlabel('time (sec)');
ylabel('testing RMSE');
legend('active', 'boost', 'TR', 'ALT-Impute', 'SSGD', 'LaMFit', 'APG', 'Soft-Impute', 'AIS-Impute')

figure(2);
xlabel('time (sec)');
ylabel('relative error(obj)');
legend('active', 'boost', 'TR', 'ALT-Impute', 'SSGD', 'LaMFit', 'APG', 'Soft-Impute', 'AIS-Impute')

clear traData lambda gndRank method row S t traIdx tstIdx U V val col rnk para;

save(strcat(dataset, '-', num2str(repeat),'.mat'));

end


function [Pj closest] = P_r2j(Pr, Pj, closest)
%P_R2J  Change reference frame of projection matrices
%
%   [Pk I] = P_r2j(Pr, Pj, closest)
%
% Tranforms the coordinate frame of a set of projection matrices such that
% a reference projection matrix becomes the identity matrix eye(3, 4). Can
% also select input matrices based on camera centre proximity to the
% reference frame.
%
%IN:
%   Pr - 3x4 projection matrix of the reference frame.
%   Pj - 3x4xN array of input projection matrices.
%   closest - 1xP indices of matrices of Pj to output, once arranged in
%             order of proximity of camera centre to Pr. Default: 1:N.
%
%OUT:
%   Pk - 3x4x(min(N,P)) array of transformed projection matrices.
%   I - 1x(min(N,P)) indices of matrices of Pj that make up Pk, such
%       that Pk = T(Pj(:,:,I)), T() being the coordinate transformation.

% $Id: P_r2j.m,v 1.2 2007/12/10 10:58:31 ojw Exp $

if nargin > 2
    % Determine which Pj matrices are required based on distance of optical
    % centres from that of Pr.
    T = zeros(3, size(Pj, 3));
    for a = 1:size(Pj, 3)
        T(:,a) = -Pj(:,1:3,a) \ Pj(:,4,a);
    end
    order = ojw_bsxfun(@minus, T, -Pr(:,1:3) \ Pr(:,4));
    [T order] = sort(sum(order .^ 2));
    closest = order(closest);
    Pj = Pj(:,:,closest);
end

% Calculate Pj relative to Pr
% Assume projection matrices make 0,0 the top left corner of the top left
% pixel. Convert to Matlab form, i.e. 0.5,0.5 is the top left corner of the
% top left pixel.
T = [1 0 0.5; 0 1 0.5; 0 0 1];
Pr = inv([T * Pr; 0 0 0 1]);
for a = 1:size(Pj, 3)
    Pj(:,:,a) = T * Pj(:,:,a) * Pr;
end
return


function plotHistConv(model, sample, rxnNames, nSubSamples)
% Plots convergence of sample histograms
%
% USAGE:
%
%    plotHistConv(model, sample, rxnNames, nSubSamples)
%
% INPUTS:
%    model:          COBRA model structure
%    sample:         Sampled fluxes
%    rxnNames:       List of reactions to plot
%    nSubSamples:    Number of sub samples
%
% EXAMPLE:
%
%    example 1:
%    rxnNames = {'R1', 'R2'}
%    plotHistConv(model, sample, rxnNames, nSubSamples)
%
% .. Author: - Markus Herrgard 8/14/06

nSkip = 10;
nBin = 20;

[nRxns,nSamples] = size(sample);

[isInModel,rxnInd] = ismember(rxnNames,model.rxns);
rxnInd = rxnInd(isInModel);

nPlotRxn = sum(isInModel);
rxnNames = rxnNames(isInModel);

nCol = ceil(sqrt(nPlotRxn));
nRow = ceil(nPlotRxn/nCol);

subSampleSize = floor(nSamples/nSubSamples);

clf
for rxnID = 1:nPlotRxn
    subplot(nRow,nCol,rxnID);
    hold on
    maxx = -1e9;
    minx = 1e9;
    maxy = 0;
    for subID = 1:nSubSamples
        [n,x] = hist(sample(rxnInd(rxnID), 1:nSkip:(subSampleSize * subID))', nBin);
        plot(x, n/sum(n));
        maxx = max([max(x) maxx]);
        minx = min([min(x) minx]);
        maxy = max([max(n/sum(n)) maxy]);
    end
    axis([minx maxx 0 maxy]);
    title(rxnNames{rxnID});
end


function y = vl_nnnoffset(x, param, dzdy)
%VL_NNNOFFSET CNN norm-dependent offset.
%   Y = VL_NNNOFFSET(X, PARAM) subtracts from each element of X the
%   weighted norm of the feature channels:
%
%     X(i,j,k) = X(i,j,k) - PARAM(1) * L(i,j) ^ PARAM(2)
%
%   where
%
%     L(i,j) = sum_K X(i,j,k)^2
%
%   DZDX = VL_NNNOFFSET(X, PARAM, DZDY) computes the derivative of the
%   block projected onto DZDY. DZDX and DZDY have the same dimensions
%   as X and Y respectively.

% Copyright (C) 2014 Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

L = sum(x.^2,3) ;
L = max(L, single(1e-8)) ;
param = single(param) ;

if nargin <= 2
  y = bsxfun(@minus, x, param(1)*L.^param(2)) ;
else
  y = dzdy - bsxfun(@times, (2*param(1)*param(2))* x, sum(dzdy,3) .* (L.^(param(2)-1))) ;
end


%==============================================================================
% This code is part of the Matlab-based toolbox
% FAIR - Flexible Algorithms for Image Registration.
% For details see
% - https://github.com/C4IR and
% - http://www.siam.org/books/fa06/
% ##2
%==============================================================================
%
%  Example for 2D registration of hand data,
%
%   - data                 hands, omega=(0,20)x(0,25), level=3:7, m=[128,128]
%   - viewer               viewImage2D
%   - image model          splineInter
%   - distance             SSD
%   - pre-registration     affine2D
%   - regularizer          mfElastic
%   - optimization         Gauss-Newton
% ===============================================================================

close all, help(mfilename)

setup2DhandData
viewImage('reset','viewImage','viewImage2D','colormap',bone(256),'axis','off');
imgModel('reset','imgModel','splineInter','regularizer','moments','theta',1e-2);
trafo('reset','trafo','affine2D');
distance('reset','distance','SSD');
regularizer('reset','regularizer','mfElastic','alpha',1e3,'mu',1,'lambda',0);

[yc,wc,his] = MLIR(ML,'parametric',1,'plotIter',1,'plotMLiter',1);

showResults(ML,yc)

%==============================================================================