function [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
           Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
           str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
           Diophantine_1 ( X_Real, X_Imag,  Y_Real, Y_Imag,  Ga2b2, Gc2d2,  ...
                           str_Det_fprt_Init )
%
% Subject  : A programme to generate more examples of Ramanujam's
%            Diophantine Equation Numbers
% Release  : R13
% Author   : Sundar Krishnan
% email id : sundark100@yahoo.com
% Date     : Read the article MATHEMATICAL MINIATURE 9.pdf in Aug 2003 ;
%            Skeleton Trial Programmes in Sep 2003 ;
%            Revisit and Fine Tuning in Sep 2004
%
% Introduction :
% --------------
% This programme is about finding many examples of Ramanujam's
% Diophantine Equation.
% For mathematical formulas used in making this programme, I have referred
% to the article MATHEMATICAL MINIATURE 9.pdf
% by John Butcher, butcher@math.auckland.ac.nz.
%
% To circumvent the problem of editing the Greek symbols, I have replaced
% them with suitable alphabets.
%
% The basic equation we are trying to solve is to get the numbers :
% x & y and u & v and N that satisfy the Diophantine equation :
% x^3 + y^3 = u^3 + v^3 = N
% where the four integers x, y, u, v have no common factor.
%
% For eg, the "lowest" Diophantine Number N of Ramanujam is :
% 1729 = 9^3 + 10^3 = 1^3 + 12^3          % see Usage Eg 1 below
%
% Other examples given in Butcher's article are :
%  9^3 + 15^3    =  2^3 + 16^3 =  4104    % see Usage Eg 3 below
% 33^3 + 15^3    =  2^3 + 34^3 = 39312    % see Usage Eg 4 below
%  6^3 + (-3)^3  =  5^3 + 4^3  =   189    % see Usage Eg 5 below
% (ie, 3^3 + 4^3 + 5^3 = 6^3)
%
% All these examples are covered in the various Usage Examples given below.
%
%                                    &&&&&&&&&&&&&&
%
% Derivation of Formulae, Notations followed and Step by Step Procedure :
% -----------------------------------------------------------------------
%
% If N is even, let us have :
% a2 = (x + y) / 2 ;    b2 = (x - y) / 2        % a', b' in the article
% c2 = (u + v) / 2 ;    d2 = (u - v) / 2        % c', d' in the article
%
% If N is odd, let us have :
% a2 = (x + y) ;        b2 = (x - y)
% c2 = (u + v) ;        d2 = (u - v)
%
% gcd (x, y,  u, v) = 1 => gcd (a2, b2,  c2, d2) = 1  % Theoretical Concept 1
%
% Let gcd (a2, b2) = Ga2b2                      % Myu  in the article
% and gcd (c2, d2) = Gc2d2                      % Veta in the article
%
% Note that gcd ( Ga2b2, Gc2d2 ) = 1                    % FULCRUM 1
%
% a = a2 / ( Ga2b2 * Gc2d2^3 ) ;    b = b2 / Ga2b2
% c = c2 / ( Gc2d2 * Ga2b2^3 ) ;    d = d2 / Gc2d2
%
%                                       ++++++++
%
% X_Mag  =  X_Real +  j * (sqrt(3) * X_Imag) ;        X_Sq  =  X_Mag^2 ;
%
% Y_Mag  =  Y_Real +  j * (sqrt(3) * Y_Imag) ;        Y_Sq  =  Y_Mag^2 ;
%
% Z_Mag  =  Z_Real +  j * (sqrt(3) * Z_Imag) ;        Z_Sq  =  Z_Mag^2 ;
%
% My interpretation : Initially assume the ratio "r" as 1 ;
% later, adjust r to get b and d as whole numbers.      % Logical Concept 1
% a = r * Y_Sq ;        c = r * X_Sq ;
%
% The "tricky" part here is to first assume r = 1
% and solve for Z_Real and Z_Imag using these 2 eqs.
% Gc2d2^3 * ( Y_Real^2 + 3 * Y_Imag^2 ) * r  =  ...
%     X_Real * Z_Real - 3 * X_Imag * Z_Imag
%
% Ga2b2^3 * ( X_Real^2 + 3 * X_Imag^2 ) * r  =  ...
%    Y_Real * Z_Real - 3 * Y_Imag * Z_Imag
%
% ie, in matrix form, solve for Z_Real and Z_Imag :
% [ X_Real,  - 3 * X_Imag ;    Y_Real,  - 3 * Y_Imag ] * [ Z_Real ;  Z_Imag ]
% = [ Gc2d2^3 * ( Y_Real^2 + 3 * Y_Imag^2 ) * r ;
%     Ga2b2^3 * ( X_Real^2 + 3 * X_Imag^2 ) * r ]
%
% Obtain b and d from :
% Gc2d2^6 * a^2  +  3 * b^2  =  X_Sq * Z_Sq
%
% Ga2b2^6 * c^2  +  3 * d^2  =  Y_Sq * Z_Sq
%
% Then, choose r in a way as to convert b and d to whole numbers.
% Also, correct a and c to reflect the change in r.
% Note that the "appropriate" roots b and d may be negative in some cases.
%
% Then, back-calculate to get a2, b2, c2, d2 :
%
% If a2 + b2 is odd, N is even, else N is odd.
% use appropriate formulae for obtaining x, y, u, v.
%
% If x^3 + y^3 and u^3 + v^3 don't match, try with negative roots -b, -d etc.
% But this probably may never happen - see below.
%
%                                    &&&&&&&&&&&&&&
%
% I wish to thank Prof John Butcher for his article which triggered
% and enabled me to write this Matlab code for "generating"
% Ramanujam's Diophantine Equation Numbers.
% I hope that this programme will be useful to many the world over.
% Time permitting, I may be improving on this programme to make it suitable
% for generating a series of Diophantine Numbers automatically.
% But the base groundwork is already laid now, and we need
% only to build further.
%
% Q1a : I am curious to know why Prof John Butcher has said that
% gcd (a, b) and gcd (c, d) should be 1.
% In the case of his own example : 9^3 + 15^3  =  2^3 + 16^3 =  4104,
% intermediate calculations give a = 12, b = 3, c = 9, d = 7.
% See Usage Eg Case 4 below. Obviously, gcd (a, b) = 3 (not 1).
% But, gcd (x, y,  u, v) = 1 (var name used in my programme is G_Gxy_Guv.)
%
% Also, in his second example : 33^3 + 15^3  =  2^3 + 34^3 = 39312,
% calculations give a = 3, b = 9, c = 9, d = 8. See Usage Eg Case 5 below.
% Obviously, gcd (a, b) = 3 (not 1). But, gcd (x, y,  u, v) = 1.
%
% Similarly, in his 3rd example too, gcd (a, b) = 3 (not 1) !
%
% In many of my own examples with randomly chosen values, I have mixed results:
% In Usage Eg 2, gcd (c, d) = 9 (not 1), but, gcd (x, y,  u, v) = 1.
% In Usage Eg 3, gcd (a, b) = 3 (not 1), but, gcd (x, y,  u, v) = 3 (not 1) !
% Egs 7 and 8 are similar to Eg 2 ; Egs 9, 10, and 11 are similar to Eg 3.
%
% Q1b) Therefore, I would like to know the condition or constraint,
% which when fulfilled, will ensure that we will certainly obtain
% x, y,  u, v such that gcd (x, y,  u, v) = 1
%
% Q2 : I would also like to know how the article's Theorem 1 is used
% in deriving the formulae for Diophantine Numbers.
% It says : ... "although beneath the surface" ...
%
%                                    &&&&&&&&&&&&&&
%
% % Usage Egs :
%
% % Usage Egs Case 6, Case 7 and Case 8 can be used as Regression Test Cases
% % after any modifications are done to this programme.
%
% % Case 1) : Ramanujam's Diophantine Equation : Lowest No 1729 :
% % 1729 = 9^3 + 10^3 = 1^3 + 12^3
% clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( 1, 2,  4, 1,  1, 1,   'Y' )
%
% % 10, 9,  12, 1,  1729, 1729, 1729,   1,  19, 1, 13, 11,   19, 1, 13, 11,
% % 1, -3,   1, 1, 1,   1, 1,   N_ODD, Pos_Pos,   0, 1.729e-7
% %               ---  ---
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 2) : With my own randomly chosen values : (G_Gxy_Guv = 1)
% % 321236^3  +  (-78236)^3  =  418185^3  +  (-343305)^3  =  32670295158384000
% % But gcd (x, y,  u, v) = 1 ;    gcd (c, d) = 9 (NOT 1)
% clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( 1, -2,  0, -3,  4, 5,   'Y' )
%
% % Note that this is a good example for 2 reasons :
% % a) We had to toggle our first choice of N_ODD to N_EVN.
% % b) error_Limit had to be used because the computed Calc_Error is 8,
% % but checking with the Calculator gives a difference of 0.
% % But I corrected this later by taking factored cube.
%
% % Note :
% Gcd          % = gcd ( c, d )     = 9 (not 1)      % See Q1a, b above.
% G_Gxy_Guv    % = gcd ( Gxy, Guv ) = 1              % But, = 3 in Case 3
%
% % 321236, -78236,  418185, -343305,
% % 32670295158384000, 32670295158384000,
% % 3.267029515838401e16 (32670295158384000),   9,
% % (RHS error of +8 later corrected to 0)
% % 243, 49934, 117, 76149,   121500, 199736, 37440, 380745,
% % 2820.333333333334, 92.44444444444444,   4, 45, 1,   1, 9,
% %                                               ---     ***
% % N_EVN, Pos_Pos,   8 (0), 3000    % Calc_Error later corrected to 0
% %                  *******
% %
% %                                    &&&&&&&&&&&&&&
%
% % Case 3) : With my own randomly chosen values : (G_Gxy_Guv = 3)
% % 115821^3  +  (-72045Z)^3  =  267420^3  +  (-261804)^3  =  1179732995041536
% % But gcd (x, y,  u, v) = 3 (NOT 1) ;    gcd (a, b) = 3 (NOT 1)
% clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( 1, 2,  3, 4,  3, 4,   'Y' )
%
% % Note :
% Gab          % = gcd ( a, b )     = 3 (not 1)      % See Q1a, b above.
% G_Gxy_Guv    % = gcd ( Gxy, Guv ) = 3              % But, = 1 in Case 1, 4, 5, 6
%
% % 115821, -72045,  267420, -261804,
% % 1179732995041536, 1179732995041536, 1179732995041536,   2,
% % 114, 31311, 26, 66153,   21888, 93933, 2808, 264612,
% % -6945, -1765.5,   9, 12, 3,   3, 1,   N_EVN, Pos_Pos,   0, 3000
% %                         ***  ***
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 4) : Butcher's 2nd example :
% %  9^3 + 15^3  =  2^3 + 16^3 =  4104
% clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( 0, 1,  1, 1,  1, 1,   'Y' )
%
% % Note :
% Gab          % = gcd ( a, b )     = 3 (not 1)      % See Q1a, b above.
% % But here, G_Gxy_Guv    % = gcd ( Gxy, Guv ) = 1  % But, = 3 in Case 3
%
% % 15, 9,  16, 2,  4104, 4104, 4104,  3,   12, 3, 9, 7,   12, 3, 9, 7,
% % -1, -1.33333333333333,   3, 2, 1,   3, 1,   N_EVN, Pos_Pos,   0, 4.104e-7
% %                               ---  ***
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 5) : Butcher's 3rd example :
% % 33^3 + 15^3  =  2^3 + 34^3 = 39312
% clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( 0, 1,  1, 0,  1, 2,   'Y' )
%
% % Note :
% Gab          % = gcd ( a, b )     = 3 (not 1)      % See Q1a, b above.
% % But here, G_Gxy_Guv    % = gcd ( Gxy, Guv ) = 1  % But, = 3 in Case 3
%
% % 33, 15,  34, 2,  39312, 39312, 39312,  3,   3, 9, 9, 8,   24, 9, 18, 16,
% % 3, -2.66666666666667,   3, 2, 1,   3, 1,   N_EVN, Pos_Pos,   0, 3.9312e-6
% %                              ---  ***
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 6) : Butcher's 4th example :
% % 6^3 + (-3)^3  =  5^3 + 4^3  =   189        % ie, 3^3 + 4^3 + 5^3 = 6^3
% clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( 0, 1,  -1, 0,  1, 1,   'Y' )
%
% % Note :
% Gab          % = gcd ( a, b )     = 3 (not 1)      % See Q1a, b above.
% % But here, G_Gxy_Guv    % = gcd ( Gxy, Guv ) = 1  % But, = 3 in Case 3
%
% % 6, -3,  5, 4,  189, 189, 189,  3,   3, 9, 9, 1,  3, 9, 9, 1,
% % -3, -0.33333333333333,   3, 1, 1,   3, 1,   N_ODD, Pos_Pos,   0, 1.89e-8
% %                               ---  ***
%
% %                                    &&&&&&&&&&&&&&
%
% % Many more Usage Egs are given at the end.
%
%                                 ********************

% 1) Inputs' Defaults and Checks :

if nargin < 4
    error ('Diophantine_1.m needs atleast 4 input args.' ) ;
end

if nargin < 5
    Ga2b2 = 1 ;    % Default Value of gcd (a2, b2)
    Gc2d2 = 1 ;    % Default Value of gcd (c2, d2)

    % Default is that we do NOT want extra Print-outs.
    str_Det_fprt_Init = 'N' ;
end

if nargin < 6
    Gc2d2 = 1 ;    % Default Value of gcd (c2, d2)

    str_Det_fprt_Init = 'N' ;
end

if nargin < 7
    str_Det_fprt_Init = 'N' ;
end

G_Ga2b2_Gc2d2 = gcd ( Ga2b2, Gc2d2 ) ;        % FULCRUM 1

if G_Ga2b2_Gc2d2 ~= 1
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    fprintf ( '\n**** Diophantine_1.m : ' ) ;
    fprintf ( 'gcd ( Ga2b2, Gc2d2 ) = %d **** \n', G_Ga2b2_Gc2d2 ) ;
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    % Note : Actually, we should exit here with an error stmt.
end

%                                    &&&&&&&&&&&&&&

% 2) Inits :
format long

% Constant repeatedly used in the programme :
root_3 = sqrt (3) ;

% Initially assume the ratio "r" as 1        % Logical Concept 1
r = 1 ;

% If there is no convergence, let us show it as N = -1
N = -1 ;

LHS = -1 ;
RHS = -1 ;

%                                    &&&&&&&&&&&&&&

% 3) Calculate X_Sq and Y_Sq :

X_Mag  =  abs ( X_Real  +  j * X_Imag * root_3 ) ;
X_Sq   =  X_Mag^2 ;

Y_Mag  =  abs ( Y_Real  +  j * Y_Imag * root_3 ) ;
Y_Sq   =  Y_Mag^2 ;

%                                    &&&&&&&&&&&&&&

% 4) Calculate a and c :

a = r * Y_Sq ;
c = r * X_Sq ;

%                                    &&&&&&&&&&&&&&

% 5a) Solve for s (Z_Real) and t (Z_Imag) :

% NOTE that if you choose a case like :
% ... = Diophantine_1 ( -3, -4,  -3, -4,  11, 7 )
% A_st will be singular !
% This will also lead to a problem below in : r = lcm ( Den_b, Den_d ) ;

A_st = [ X_Real,  -3 * X_Imag ;
         Y_Real,  -3 * Y_Imag ] ;

B_st = [ Gc2d2^3 * ( Y_Real^2 + 3 * Y_Imag^2 ) * r ;
         Ga2b2^3 * ( X_Real^2 + 3 * X_Imag^2 ) * r ] ;

% The 'mldivide' operator may only produce a single output.
% So, we do this in 3 steps.
st_Soln = A_st \ B_st ;

Z_Real = st_Soln(1) ;
Z_Imag = st_Soln(2) ;

%                                       ++++++++

% 5b) Compute Z_Mag and Z_Sq :

Z_Mag  =  abs ( Z_Real  +  j * Z_Imag * root_3 ) ;
Z_Sq   =  Z_Mag^2 ;

%                                    &&&&&&&&&&&&&&

% 6) The important logical step in this programme :

% 6a) Obtain b and d :

b_pos = sqrt ( ( X_Sq * Z_Sq  -  Gc2d2^6 * a^2 ) / 3 ) ;

d_pos = sqrt ( ( Y_Sq * Z_Sq  -  Ga2b2^6 * c^2 ) / 3 ) ;

% Because of sqrt, b_pos and d_pos may not come out exactly as
% whole integers in the calculations due to FP errors.
% We correct this below.

%                                       ++++++++

% 5b) Choose r in a way as to convert b and d to whole numbers.

[ Num_b, Den_b ]  =  rat (b_pos) ;
[ Num_d, Den_d ]  =  rat (d_pos) ;

r = lcm ( Den_b, Den_d ) ;        % Logical Concept 1

% Try with positive roots first.
% Note that the "appropriate" roots b and d may be negative in some cases.
b_pos = r * b_pos ;
d_pos = r * d_pos ;

%                                       ++++++++

% 5c) Correct a and c to reflect the change in r :
a = r * Y_Sq ;
c = r * X_Sq ;

%                                    &&&&&&&&&&&&&&

% 6) Because of sqrt, b_pos and d_pos may not come out exactly as
% whole integers in the calculations due to FP errors.

if abs ( a - round(a) ) < 1e-6 * abs (a)
    a = round(a) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** a is NOT a whole integer. ' ) ;
        fprintf ( 'a = %d **** \n' ) ;
    end
end

if abs ( c - round(c) ) < 1e-6 * abs (c)
    c = round(c) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** c is NOT a whole integer. ' ) ;
        fprintf ( 'c = %d **** \n' ) ;
    end
end

%                                       ++++++++

if abs ( b_pos - round(b_pos) ) < 1e-6 * abs (b_pos)
    b_pos = round(b_pos) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** b_pos is NOT a whole integer. ' ) ;
        fprintf ( 'b_pos = %d **** \n' ) ;
    end
end

if abs ( d_pos - round(d_pos) ) < 1e-6 * abs (d_pos)
    d_pos = round(d_pos) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** d_pos is NOT a whole integer. ' ) ;
        fprintf ( 'd_pos = %d **** \n' ) ;
    end
end

%                                    &&&&&&&&&&&&&&

% 7a) As per Butcher's article, gcd(a, b) and gcd(c, d) should be = 1.

Gab = gcd (a, b_pos) ;    % should be the same as gcd (a, b) calculated below
Gcd = gcd (c, d_pos) ;    % should be the same as gcd (c, d) calculated below

if Gab ~= 1 | Gcd ~= 1
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    fprintf ( '\n** Diophantine_1.m : gcd ( a, b_pos ) = %d ** \n', Gab ) ;
    fprintf ( '\n** Diophantine_1.m : gcd ( c, d_pos ) = %d ** \n', Gcd ) ;
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    % Note : Actually, we should exit here with an error stmt.
end

%                                    &&&&&&&&&&&&&&

% 8) Back calculate a2, b2, c2, d2 :
a2 = a * Ga2b2 * Gc2d2^3 ;
b2_pos = b_pos * Ga2b2 ;

c2 = c * Gc2d2 * Ga2b2^3 ;
d2_pos = d_pos * Gc2d2 ;

%                                    &&&&&&&&&&&&&&

% 9) Because of sqrt in b_pos and d_pos, let us check
% a2, c2, b2_pos, d2_pos also for wholeness.

if abs ( a2 - round(a2) ) < 1e-6 * abs (a2)
    a2 = round(a2) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** a2 is NOT a whole integer. ' ) ;
        fprintf ( 'a2 = %d **** \n' ) ;
    end
end

if abs ( c2 - round(c2) ) < 1e-6 * abs (c2)
    c2 = round(c2) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** c2 is NOT a whole integer. ' ) ;
        fprintf ( 'c2 = %d **** \n' ) ;
    end
end

%                                       ++++++++

if abs ( b2_pos - round(b2_pos) ) < 1e-6 * abs (b2_pos)
    b2_pos = round(b2_pos) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** b2_pos is NOT a whole integer. ' ) ;
        fprintf ( 'b2_pos = %d **** \n' ) ;
    end
end

if abs ( d2_pos - round(d2_pos) ) < 1e-6 * abs (d2_pos)
    d2_pos = round(d2_pos) ;
else
    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n    **** d2_pos is NOT a whole integer. ' ) ;
        fprintf ( 'd2_pos = %d **** \n' ) ;
    end
end

%                                    &&&&&&&&&&&&&&

% 10) As a first choice, if a2 + b2 is even, N is odd, else N is even.
% N_ODD or N_EVN may be reqd to be decided again in xyuv_from_a2b2c2d2
% For eg, it is necessary to toggle the first choice in the case of Usage Eg 6.
%
% Note that a and b are positive because X_Sq and Y_Sq are pos,
% and r = 1 or lcm is also pos.
% So, a2 and b2 must also be pos.
if mod ( (a2 + b2_pos), 2 ) < 1e-6 * min ( abs (a2), abs (b2_pos) )
% mod is preferable to rem here : rem (-5, 2) = -1 ;  mod (-5, 2) = -1 + 2 = +1
% Note that mod ( 19.999999, 2 ) = 1.999999
    str_N_odd_even = 'N_ODD' ;
else
    str_N_odd_even = 'N_EVN' ;

end

%                                    &&&&&&&&&&&&&&

% 11a) Calculate x & y and u & v using b2_pos and d2_pos :
b2 = b2_pos ;
d2 = d2_pos ;

[ x, y,  u, v ] = xyuv_from_a2b2c2d2 ( a2, b2,  c2, d2,  str_N_odd_even ) ;

% If the above choice of N_ODD or N_EVN was not correct, we will have
% a factor of 0.5 in either or both pairs : x, y or u, v
% So, we need to change the choice.
% To account for cascading FP errors, I have taken 0.25 instead of 0.5
if abs ( x - round(x) ) > 0.25 |  abs ( u - round(u) ) > 0.25 | ...
   abs ( y - round(y) ) > 0.25 |  abs ( v - round(v) ) > 0.25

    if str_N_odd_even == 'N_ODD'
        str_N_odd_even = 'N_EVN' ;
    elseif str_N_odd_even == 'N_EVN'
        str_N_odd_even = 'N_ODD' ;
    end

    if str_Det_fprt_Init == 'Y'
        fprintf ( '\n**** Choice of str_N_odd_even toggled. **** \n' ) ;
        % Usage Eg 6 needs this toggling.
        str_N_odd_even
    end

    % Note that this final choice of N_EVN or N_ODD will stay valid even for
    % the other match tests between x^3 + y^3 and u^3 + v^3 below.

    % Don't forget to call xyuv_from_a2b2c2d2 again.
    [ x, y,  u, v ] = xyuv_from_a2b2c2d2 ( a2, b2,  c2, d2,  str_N_odd_even ) ;

end

%                                    &&&&&&&&&&&&&&

% 11b) Check with pos roots b2_pos and d2_pos if x^3 + y^3 and u^3 + v^3 match:

% LHS = x^3 + y^3
% RHS = u^3 + v^3

% As values of x and y increases, errors creep in the computation
% of x^3 + y^3 due to cascading FP errors.
% Instead, we factorise and try.

LHS = ( x + y ) * ( x^2 + y^2 - x*y ) ;    % instead of : LHS = x^3 + y^3
RHS = ( u + v ) * ( u^2 + v^2 - u*v ) ;    % instead of : RHS = u^3 + v^3

Calc_Error  =  abs ( LHS - RHS ) ;

% If LHS or RHS becomes very large like say, of the order of 1e20,
% a multiplying factor 1e-4 is not enough.
% For eg, in the case of Usage Eg 6, Calc_Error computed above is 8,
% but checking with the Calculator gives a difference of 0.
error_Limit = compute_error_Limit ( LHS, RHS ) ;

if str_Det_fprt_Init == 'Y'
    fprintf ( '\nCalc_Error with pos roots b_pos and d_pos = %d \n', ...
              Calc_Error ) ;
    error_Limit
end

% if x^3 + y^3 == u^3 + v^3        % ideal if no FP errors creep in !
if Calc_Error < error_Limit        % if b_pos, d_pos

    b = b_pos ;
    d = d_pos ;

    str_b_d = 'Pos_Pos' ;

else
    % I discovered later during development that the solution will "converge"
    % in all (almost or really all ?) cases with pos roots b_pos and d_pos ;
    % it (probably) really makes no difference to the end result at all.
    % But since I had already written more than 50 % of the foll code, and
    % also tested it partly, I have let it remain - ofcourse after testing it
    % sufficiently - no harm in retaining it.
    % One secret ? : It was actually an error in my hand calculations which
    % initially prompted me to write the foll code for different signs
    % for b and d !

    % 11c) Check if x^3 + y^3 and u^3 + v^3 match with b2_neg and d2_pos :
    b2_neg = -b2_pos ;    b2 = b2_neg ;
    d2 = d2_pos ;

    [ x, y,  u, v ] = ...
        xyuv_from_a2b2c2d2 ( a2, b2,  c2, d2,  str_N_odd_even ) ;

    LHS = ( x + y ) * ( x^2 + y^2 - x*y ) ;    % instead of : LHS = x^3 + y^3
    RHS = ( u + v ) * ( u^2 + v^2 - u*v ) ;    % instead of : RHS = u^3 + v^3

    Calc_Error  =  abs ( LHS - RHS ) ;

    error_Limit = compute_error_Limit ( LHS, RHS ) ;

    if str_Det_fprt_Init == 'Y'
        fprintf ( '\nCalc_Error with b_neg and d_pos = %d \n', ...
                  Calc_Error ) ;
        error_Limit
    end

    if Calc_Error < error_Limit       % if b_neg, d_pos

        b = -b_pos ;    % b_neg = -b_pos ;
        d = d_pos ;

        str_b_d = 'Neg_Pos' ;

    else

        % 11d) Check if x^3 + y^3 and u^3 + v^3 match with b2_pos and d2_neg :
        b2 = b2_pos ;
        d2_neg = -d2_pos ;    d2 = d2_neg ;

        [ x, y,  u, v ] = ...
            xyuv_from_a2b2c2d2 ( a2, b2,  c2, d2,  str_N_odd_even ) ;

        LHS = ( x + y ) * ( x^2 + y^2 - x*y ) ;
        RHS = ( u + v ) * ( u^2 + v^2 - u*v ) ;

        Calc_Error  =  abs ( LHS - RHS ) ;

        error_Limit = compute_error_Limit ( LHS, RHS ) ;

        if str_Det_fprt_Init == 'Y'
            fprintf ( '\nCalc_Error with b_pos and d_neg = %d \n', ...
                      Calc_Error ) ;
            error_Limit
        end

        if Calc_Error < error_Limit  % if b_pos, d_neg

            b = b_pos ;
            d = -d_pos ;    % d_neg = -d_pos ;

            str_b_d = 'Pos_Neg' ;

        else

            % 11e) Check if x^3 + y^3 and u^3 + v^3 match
            % with b2_neg and d2_neg :
            b2_neg = -b2_pos ;    b2 = b2_neg ;
            d2_neg = -d2_pos ;    d2 = d2_neg ;

            b = -b_pos ;    % b_neg = -b_pos ;
            d = -d_pos ;    % d_neg = -d_pos ;

            str_b_d = 'Neg_Neg' ;

            [ x, y,  u, v ] = ...
                xyuv_from_a2b2c2d2 ( a2, b2,  c2, d2,  str_N_odd_even ) ;

            LHS = ( x + y ) * ( x^2 + y^2 - x*y ) ;
            RHS = ( u + v ) * ( u^2 + v^2 - u*v ) ;

            Calc_Error  =  abs ( LHS - RHS ) ;

            error_Limit = compute_error_Limit ( LHS, RHS ) ;

            if str_Det_fprt_Init == 'Y'
                fprintf ( '\nCalc_Error with b_neg and d_neg = %d \n', ...
                          Calc_Error ) ;
                error_Limit
            end

            if Calc_Error > error_Limit    % if b_neg, d_neg

                fprintf ( '\n\n**** NO MATCH found. INVESTIGATE. **** \n' ) ;

                fprintf ( '\n**** Values calculated so far :   **** \n' ) ;
                x, y,  u, v,  N, LHS, RHS,  r
                a, b, c, d,   a2, b2, c2, d2
                str_N_odd_even, str_b_d,   Calc_Error, error_Limit
                Gab = gcd (a, b)
                Gcd = gcd (c, d)

                Gxy = gcd (x, y)
                Guv = gcd (u, v)

                fprintf ( '\n************************************ \n\n' ) ;

                error ( 'Can''t find matching x & y and u & v ! INVESTIGATE.');

            end    % if b_neg, d_neg

        end    % if b_pos, d_neg

    end    % if b_neg, d_pos

end    % if b_pos, d_pos

%                                    &&&&&&&&&&&&&&

% 12) Compute N :

N = x^3 + y^3 ;

%                                    &&&&&&&&&&&&&&

% 13) Compute gcd of x, y  &  u, v  and  a, b  &  c, d :
% a, c,  b, d
% x, y,  u, v

Gxy = gcd (x, y) ;    % If these are not integers, we could get this error :
Guv = gcd (u, v) ;    % Error using ==> gcd : Requires integer input arguments.

Gab = gcd (a, b) ;    % should be the same as gcd (a, b_pos) calculated above
Gcd = gcd (c, d) ;    % should be the same as gcd (c, d_pos) calculated above

%                                    &&&&&&&&&&&&&&

% 14) Check if gcd of (x, y,  u, v ) = 1
% gcd (x, y,  u, v) = 1 => gcd (a2, b2,  c2, d2) = 1  % Theoretical Concept 1

G_Gxy_Guv = gcd ( Gxy, Guv ) ;

if G_Gxy_Guv ~= 1
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    fprintf ( '\n**** Diophantine_1.m : gcd ( Gxy, Guv ) = %d **** \n', ...
              G_Gxy_Guv ) ;
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    % Note : Actually, we should exit here with an error stmt.
end

% 7b) Similarly, we should exit if Gab ~= 1 | Gcd ~= 1   % Yes, it is NOT 14b !
% Note that this condition (eqvt) has already been addressed above as :
% gcd (a, b_pos) and gcd (c, d_pos).
if Gab ~= 1 | Gcd ~= 1
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    fprintf ( '\n** Diophantine_1.m : gcd ( a, b ) = %d ** \n', Gab ) ;
    fprintf ( '\n** Diophantine_1.m : gcd ( c, d ) = %d ** \n', Gcd ) ;
    fprintf ( '\n********************* NOTE ********************* \n' ) ;
    % Note : Actually, we should exit here with an error stmt.
end

%                                    &&&&&&&&&&&&&&

fprintf ( '\n\n************  Pgm output begins here.  ************ \n ' ) ;

%                                    &&&&&&&&&&&&&&

%                                 ********************
%                                 ********************

% 16)
function [ error_Limit ] = compute_error_Limit ( LHS, RHS )

min_L_R = min ( abs (LHS), abs (RHS) ) ;

if min_L_R < 1e6
    error_Limit = 1e-10 * min_L_R ;
    % max = 1e-4 for 1e6 - 1

elseif min_L_R < 1e10
    error_Limit = max ( 1e-8 * min_L_R, 5e-4 ) ;
    % 5e-4 for 1e6 ; 100 for 1e10 - 1

elseif min_L_R < 1e15
    error_Limit = max ( 1e-12 * min_L_R, 300 ) ;
    % 300 for 1e10 ; 1000 for 1e15 - 1

elseif min_L_R < 1e20
    error_Limit = max ( 1e-16 * min_L_R, 3000 ) ;
    % 3000 for 1e15 ; 10000 for 1e20 - 1

elseif min_L_R < 1e25
    error_Limit = max ( 1e-19 * min_L_R, 30000 ) ;
    % 30000 for 1e20 ; 100000 for 1e25 - 1

else
    error_Limit = 2e6 ;

end

%                                 ********************
%                                 ********************

% 17)
function [ x, y,  u, v ] = ....
    xyuv_from_a2b2c2d2 ( a2, b2,  c2, d2,  str_N_odd_even )

% Note : As a first choice, if a2 + b2 is even, str_N_odd_even is supplied
% as N_ODD to this subfunction, and vice-versa.
% N_ODD or N_EVN may be reqd to be decided again based on the results.

if str_N_odd_even == 'N_ODD'

    x = ( a2 + b2 ) / 2 ;
    y = ( a2 - b2 ) / 2 ;

    u = ( c2 + d2 ) / 2 ;
    v = ( c2 - d2 ) / 2 ;

else

    x = ( a2 + b2 ) ;
    y = ( a2 - b2 ) ;

    u = ( c2 + d2 ) ;
    v = ( c2 - d2 ) ;

end

%                                 ********************
%                                 ********************

% Some more Usage Egs are given below.
%
% % Case 7) : With my own randomly chosen values : (G_Gxy_Guv = 1)
% % 116244^3  +  (-115872)^3  =  37249^3  +  (-33217)^3  =  15031929519936
%
% clear, clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( -3, 5,  2, -3,  2, 1, 'Y' )
%
% Gab        % = gcd ( a, b )     = 3 (not 1)     % See Q1a, b above.
% G_Gxy_Guv  % = gcd ( Gxy, Guv ) = 1
%
% r % = 3
%
% Z_Real % = 3453
% Z_Imag % = -692.6666666666666
%
% % N_EVN, Pos_Pos
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 8) : With my own randomly chosen values : (G_Gxy_Guv = 1)
% % (-107766)^3  +  (-634932)^3  =  (-2013055)^3  +  1991671^3
% % = -257217167508536664 (Calculator)   { -2.572171675085367e+017 (Matlab) }
% % ie, 2013055^3 = 107766^3  +  634932^3  +  1991671^3
%
% % Since we have the successful special case of 3 negatives and 1 positive,
% % this is an important Regression Test Case.
%
% clear, clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( -3, 1,  2, -3,  3, -11, 'Y' )
%
% % -107766, -634932, -2013055, 1991671,
% % -257217167508536664, -257217167508536664, -257217167508536664,
% % 3,   93, 87861, 36, 182033,   -371349, 263583, -10692, -2002363,
% % 17637, -3883.333333333333,   18, 11, 1,   3, 1, N_EVN, Pos_Pos, 3000
%
% Gab        % = gcd ( a, b )     = 3 (not 1)     % See Q1a, b above.
% G_Gxy_Guv  % = gcd ( Gxy, Guv ) = 1
%
% r % = 3
%
% Z_Real % = 17637
% Z_Imag % = -3883.333333333333
%
% % str_N_odd_even toggled from N_ODD to N_EVN, Pos_Pos
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 9) : With my own randomly chosen values : (G_Gxy_Guv = 343)
% % 327908^3  +  (-72716)^3  =  360493^3  +  (-228781)^3
% % =  3.487337281103962e+016
% % But gcd (x, y,  u, v) = 343 (NOT 1) ;    gcd (c, d) = 49 (NOT 1)
%
% clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( 1, -4,  2, -3,  4, 7,   'Y' )
%
% Gcd        % = gcd ( c, d )     = 49 (not 1)     % See Q1a, b above.
%
% G_Gxy_Guv  % = gcd ( Gxy, Guv ) = 343  % = 3 in Case 2 ; = 1 in Case 1, 4, 5, 6
%
% r % = 3
%
% Z_Real % = 3871
% Z_Imag % = 1208.666666666667
%
% % N_EVN, Pos_Pos
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 10) : With my own randomly chosen values : (G_Gxy_Guv = 7)
% % 50932^3  +  (-21448)^3  =  102543^3  +  (-98511)^3  =  1.222546648901760e+014
%
% clear, clc
% [ x, y,  u, v,  N, LHS, RHS,  r,   a, b, c, d,   a2, b2, c2, d2,   ...
%   Z_Real, Z_Imag,   Gxy, Guv, G_Gxy_Guv,   Gab, Gcd,               ...
%   str_N_odd_even, str_b_d,   Calc_Error, error_Limit ] =           ...
%       Diophantine_1 ( -3, -5,  9, 8,  2, 3 )
%
% % Note :
% Gab        % = gcd ( a, b )     = 7 (not 1)     % See Q1a, b above.
% Gcd        % = gcd ( c, d )     = 7 (not 1)     % See Q1a, b above.
%
% G_Gxy_Guv  % = gcd ( Gxy, Guv ) = 7  % = 3 in Case 2 ; = 1 in Case 1, 4, 5, 6
%
% r % = 1
%
% Z_Real % = 2968
% Z_Imag % = 1085
%
% % N_EVN, Pos_Pos
%
% %                                    &&&&&&&&&&&&&&
%
% % Case 11) :
% Diophantine_1 (  1, -2,  -3, -4,  3,  8,   'Y' )
% % 1483821^3 + 267219^3 = 4444392^3 + (-4388232)^3 = 3.286046473469061e+018
% % G_Gxy_Guv % = 3 ;
% % Gab % = 1
%
% %                                    &&&&&&&&&&&&&&
%
% % Cases of type : Can't find matching x & y and u & v ! INVESTIGATE.
% Diophantine_1 (  1, -2,   5, -3,  4,  7,   'Y' )
% Diophantine_1 ( -3, -4,   4,  3,  11, 7 )
%
% %                                    &&&&&&&&&&&&&&
%
% % A_st is singular for this case.
% Diophantine_1 ( -3, -4,  -3, -4,  11, 7 )
%
%                                 ********************
%                                 ********************


% Test file for trigtech/diffmat.m

function pass = test_diffmat(pref)

% Get preferences.
if ( nargin < 1 )
    pref = trigtech.techPref();
end

testclass = trigtech();
valsDiscretizationclass = trigcolloc();

%% 1st-order derivative:

%% Force n to be odd:
op = @(x) exp(cos(pi*x));
f = testclass.make(op, [], pref);
n = length(f);
if ( ~rem(n,2) )
    n = n+1;
    x = trigpts(n);
    v = op(x);
else
    x = trigpts(n);
    v = get(f, 'values');
end
D = valsDiscretizationclass.diffmat(n, 1);
df = D*v;
df_exact = @(x) -pi*sin(pi*x).*exp(cos(pi*x));
err = df_exact(x) - df;
pass(1) = ( norm(err, inf) < 1e3*vscale(f)*eps );

a = 10; b = 20;
f = testclass.make(@(x) cos(a*pi*sin(b*pi*x)), [], pref);
n = length(f);
if ( ~rem(n,2) )
    n = n+1;
    x = trigpts(n);
    v = op(x);
else
    x = trigpts(n);
    v = get(f, 'values');
end
D = valsDiscretizationclass.diffmat(n, 1);
df = D*v;
df_exact = @(x) -pi^2*a*b*cos(b*pi*x).*sin(a*pi*sin(b*pi*x));
err = df_exact(x) - df;
pass(2) = ( norm(err, inf) < 1e7*vscale(f)*eps );

%% Force n to be even:
op = @(x) exp(-50*x.^2);
f = testclass.make(op, [], pref);
n = length(f);
if ( rem(n,2) )
    n = n+1;
    x = trigpts(n);
    v = op(x);
else
    x = trigpts(n);
    v = get(f, 'values');
end
D = valsDiscretizationclass.diffmat(n, 1);
df = D*v;
df_exact = @(x) - 100*x.*exp(-50*x.^2);
err = df_exact(x) - df;
pass(3) = ( norm(err, inf) < 1e3*vscale(f)*eps );

a1 = 4; b1 = 3; a2 = 6; b2 = 4;
op = @(x) cos(a1*pi*sin(b1*pi*x)) + 1i*cos(a2*pi*sin(b2*pi*x));
f = testclass.make(op, [], pref);
n = length(f);
if ( rem(n,2) )
    n = n+1;
    x = trigpts(n);
    v = op(x);
else
    x = trigpts(n);
    v = get(f, 'values');
end
D = valsDiscretizationclass.diffmat(n, 1);
df = D*v;
df_exact = @(x) -pi^2*a1*b1*cos(b1*pi*x).*sin(a1*pi*sin(b1*pi*x)) ...
    - 1i*pi^2*a2*b2*cos(b2*pi*x).*sin(a2*pi*sin(b2*pi*x));
err = df_exact(x) - df;
pass(4) = ( norm(err, inf) < 1e5*vscale(f)*eps );

%% 2nd-order derivative (odd n & even n):
op = @(x) exp(cos(4*pi*x))-1;
f = testclass.make(op, [], pref);
n = length(f);
x = trigpts(n);
v = get(f, 'values');
D2 = valsDiscretizationclass.diffmat(n, 2);
df2 = D2*v;
df2_exact = @(x) -16*pi^2*exp(cos(4*pi*x)).*(cos(4*pi*x) + cos(4*pi*x).^2 - 1);
err = df2_exact(x) - df2;
pass(5) = ( norm(err, inf) < 5e5*vscale(f)*eps );

n = n+1;
x = trigpts(n);
v = op(x);
D2 = valsDiscretizationclass.diffmat(n, 2);
df2 = D2*v;
err = df2_exact(x) - df2;
pass(6) = ( norm(err, inf) < 5e5*vscale(f)*eps );

%% Check higher-order derivatives:

% Odd p:
op = @(x) sin(pi*x);
f = testclass.make(op, [], pref);
n = length(f);
x = trigpts(n);
v = get(f, 'values');
D5 = valsDiscretizationclass.diffmat(n, 5);
df5 = D5*v;
df5_exact = @(x) pi^5*cos(pi*x);
err = df5_exact(x) - df5;
pass(7) = ( norm(err, inf) < 1e3*vscale(f)*eps );

n = n+1;
x = trigpts(n);
v = op(x);
D5 = valsDiscretizationclass.diffmat(n, 5);
df5 = D5*v;
err = df5_exact(x) - df5;
pass(8) = ( norm(err, inf) < 1e3*vscale(f)*eps );

% Even p:
op = @(x) sin(pi*x);
f = testclass.make(op, [], pref);
n = length(f);
x = trigpts(n);
v = get(f, 'values');
D6 = valsDiscretizationclass.diffmat(n, 6);
df6 = D6*v;
df6_exact = @(x) -pi^6*sin(pi*x);
err = df6_exact(x) - df6;
pass(9) = ( norm(err, inf) < 1e4*vscale(f)*eps );

n = n+1;
x = trigpts(n);
v = op(x);
D6 = valsDiscretizationclass.diffmat(n, 6);
df6 = D6*v;
err = df6_exact(x) - df6;
pass(10) = ( norm(err, inf) < 1e5*vscale(f)*eps );

end


function beta_values_test ( )

%*****************************************************************************80
%
%% BETA_VALUES_TEST demonstrates the use of BETA_VALUES.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 February 2009
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BETA_VALUES_TEST:\n' );
  fprintf ( 1, '  BETA_VALUES stores values of\n' );
  fprintf ( 1, '  the Beta function.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '      X              Y         BETA(X,Y)\n' );
  fprintf ( 1, '\n' );

  n_data = 0;

  while ( 1 )

    [ n_data, x, y, fxy ] = beta_values ( n_data );

    if ( n_data == 0 )
      break
    end

    fprintf ( 1, '  %12f  %12f  %24.16f\n', x, y, fxy );

  end

  return
end


function [ n_data, x, fx ] = psi_values ( n_data )

%*****************************************************************************80
%
%% PSI_VALUES returns some values of the Psi or Digamma function.
%
%  Discussion:
%
%    In Mathematica, the function can be evaluated by:
%
%      PolyGamma[x]
%
%    or
%
%      PolyGamma[0,x]
%
%    PSI(X) = d ln ( Gamma ( X ) ) / d X = Gamma'(X) / Gamma(X)
%
%    PSI(1) = -Euler's constant.
%
%    PSI(X+1) = PSI(X) + 1 / X.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Milton Abramowitz and Irene Stegun,
%    Handbook of Mathematical Functions,
%    US Department of Commerce, 1964.
%
%    Stephen Wolfram,
%    The Mathematica Book,
%    Fourth Edition,
%    Wolfram Media / Cambridge University Press, 1999.
%
%  Parameters:
%
%    Input/output, integer N_DATA.  The user sets N_DATA to 0 before the
%    first call.  On each call, the routine increments N_DATA by 1, and
%    returns the corresponding data; when there is no more data, the
%    output value of N_DATA will be 0 again.
%
%    Output, real X, the argument of the function.
%
%    Output, real FX, the value of the function.
%
  n_max = 11;

  fx_vec = [ ...
     -0.5772156649015329E+00, ...
     -0.4237549404110768E+00, ...
     -0.2890398965921883E+00, ...
     -0.1691908888667997E+00, ...
     -0.6138454458511615E-01, ...
      0.3648997397857652E-01, ...
      0.1260474527734763E+00, ...
      0.2085478748734940E+00, ...
      0.2849914332938615E+00, ...
      0.3561841611640597E+00, ...
      0.4227843350984671E+00 ];

  x_vec = [ ...
     1.0E+00, ...
     1.1E+00, ...
     1.2E+00, ...
     1.3E+00, ...
     1.4E+00, ...
     1.5E+00, ...
     1.6E+00, ...
     1.7E+00, ...
     1.8E+00, ...
     1.9E+00, ...
     2.0E+00 ];

  if ( n_data < 0 )
    n_data = 0;
  end

  n_data = n_data + 1;

  if ( n_max < n_data )
    n_data = 0;
    x = 0.0;
    fx = 0.0;
  else
    x = x_vec(n_data);
    fx = fx_vec(n_data);
  end

  return
end


function plot_boundary_orange(V,F)
%PLOT_BOUNDARY_ORANGE  plots the boundary vertices of a triangle mesh in
%orange, and its interior in blue.
%
% plot_boundary_orange(V,F);
%
% Input:
%  V,F  mesh whose boundary is to be plotted

%Compute a function u that is 0 on all interior vertices and 1 on all
%boundary vertices.
b = unique(outline(F)); %find all boundary vertices
u = zeros(size(V,1),1); %construct a constant zero function
u(b) = 1; %set all boundary vertices to 1

%Plot the function u with the right colors.
t = tsurf(F,V, 'CData',u);
shading interp;
axis equal;
axis off;
cm = flipud(cbrewer('RdYlBu', 500));
colormap(cm(100:450,:));
light('Position',[-1.5 1 1],'Style','local');
lights = camlight;
set(t, 'FaceLighting','gouraud', 'FaceColor','interp');
set(t, 'DiffuseStrength',0.5, 'SpecularStrength',0.2, 'AmbientStrength',0.3);
camproj('perspective');
add_shadow([t],lights);

end


clear, clc;

% This is an example for running the function nnLogisticC
%
%  Problem:
%
%  min  f(x,c) = - weight_i * log (p_i) + 1/2 * rsL2 * ||x||_2^2
%  s.t. \|x\|_1 <=z, x>=0
%
%  a_i denotes a training sample,
%      and a_i' corresponds to the i-th row of the data matrix A
%
%  y_i (either 1 or -1) is the response
%
%  p_i= 1/ (1+ exp(-y_i (x' * a_i + c) ) ) denotes the probability
%
%  weight_i denotes the weight for the i-th sample
%
% For detailed description of the function, please refer to the Manual.
%
%% Related papers
%
% [1]  Jun Liu and Jieping Ye, Efficient Euclidean Projections
%      in Linear Time, ICML 2009.
%
% [2]  Jun Liu and Jieping Ye, Sparse Learning with Efficient Euclidean
%      Projections onto the L1 Ball, Technical Report ASU, 2008.
%
% [3]  Jun Liu, Jianhui Chen, and Jieping Ye,
%      Large-Scale Sparse Logistic Regression, KDD, 2009.
%
%% ------------   History --------------------
%
% First version on August 10, 2009.
%
% September 5, 2009: adaptive line search is added
%
% For any problem, please contact Jun Liu (j.liu@asu.edu)

cd ..
cd ..

root=cd;
addpath(genpath([root '/SLEP']));
                     % add the functions in the folder SLEP to the path

% change to the original folder
cd Examples/L1;

m=1000;  n=1000;    % The data matrix is of size m x n

randNum=1;          % a random number

% ---------------------- generate random data ----------------------
randn('state',(randNum-1)*3+1);
A=randn(m,n);         % the data matrix

y=[ones(n/2,1);...
    -ones(n/2, 1)];  % the response

z=40;                % the radius of the L1 ball

%----------------------- Set optional items -----------------------
opts=[];

% Starting point
opts.init=2;        % starting from a zero point

% Termination
opts.tFlag=5;       % run .maxIter iterations
opts.maxIter=40;    % maximum number of iterations

% Normalization
opts.nFlag=0;       % without normalization

% Regularization
opts.rsL2=0;        % the squared two norm term

% Group Property
opts.sWeight=[1,1]; % set the weight for positive and negative samples

%----------------------- Run the code LogisticC -----------------------
[x, c, funVal]=nnLogisticC(A, y, z, opts);

figure;
plot(funVal);
xlabel('Iteration (i)');
ylabel('The objective function value');

% --------------------- compute the pathwise solutions ----------------
opts.fName='nnLogisticC';      % set the function name to 'LogisticC'
Z=[10, 20, 30, 40];          % set the parameters

% run the function pathSolutionLogistic
fprintf('\n Compute the pathwise solutions, please wait...');
[X,C]=pathSolutionLogistic(A, y, Z, opts);


% EX_ARTICLE_SECTION_513: short example with macro-element integration rule.
%
% Example to solve the problem
%
%    - div ( grad (u)) = (8-9*sqrt(x.^2+y.^2)).*sin(2*atan(y./x))./(x.^2+y.^2)  in Omega
%                    u = 0                                                      on Gamma
%
% with                Omega = (1 < x^2+y^2 < 4) & (x > 0) & (y > 0)
% and exact solution      u = (x.^2+y.^2-3*sqrt(x.^2+y.^2)+2).*sin(2.*atan(y./x))
%
% using a quadrature rule on macro-elements as proposed in
%
%
% [1] Hughes, Reali, Sangalli. Comput. Methods Appl. Mech. Engrg.
% Volume 199, Issues 5-8, 1 January 2010, Pages 301-313
%
% This is the example of Section 5.1.3 in the article
%
% C. De Falco, A. Reali, R. Vazquez
% GeoPDEs: a research tool for IsoGeometric Analysis of PDEs
%
% Copyright (C) 2009, 2010 Carlo de Falco
% Copyright (C) 2011, 2015 Rafael Vazquez
%
%    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/>.

nodes   = [5.168367524056075e-02, 2.149829914261059e-01, ...
           3.547033685486441e-01, 5.000000000000000e-01, ...
           6.452966314513557e-01, 7.850170085738940e-01, ...
           9.483163247594394e-01];
weights = [1.254676875668223e-01, 1.708286087294738e-01, ...
           1.218323586744639e-01, 1.637426900584793e-01, ...
           1.218323586744638e-01, 1.708286087294741e-01, ...
           1.254676875668223e-01];
rule    = [nodes; weights];

geometry = geo_load ({@ring_polar_map, @ring_polar_map_der});

[knots, breaks] = kntuniform ([10 10], [2 2], [1 1]);
breaks{1} ([2:3:end-2,3:3:end-1]) = [];
breaks{2} ([2:3:end-2,3:3:end-1]) = [];
[qn, qw]  = msh_set_quad_nodes (breaks, {rule, rule}, [0 1]);
msh = msh_cartesian (breaks, qn, qw, geometry);

space = sp_bspline (knots, [2, 2], msh);

mat = op_gradu_gradv_tp (space, space, msh);
rhs = op_f_v_tp (space, msh, @(x, y) (8-9*sqrt(x.^2+y.^2)).*sin(2*atan(y./x))./(x.^2+y.^2));

drchlt_dofs = [];
for iside = 1:4
  drchlt_dofs = union (drchlt_dofs, space.boundary(iside).dofs);
end
int_dofs = setdiff (1:space.ndof, drchlt_dofs);

u = zeros (space.ndof, 1);
u(int_dofs) = mat(int_dofs, int_dofs) \ rhs(int_dofs);

sp_to_vtk (u, space, geometry, [20 20], 'laplace_solution.vts', 'u')
err = sp_l2_error (space, msh, u, @(x,y)(x.^2+y.^2-3*sqrt(x.^2+y.^2)+2).*sin(2.*atan(y./x)))

%!demo
%! ex_article_section_513;

%!test
%! nodes   = [5.168367524056075e-02, 2.149829914261059e-01, ...
%!            3.547033685486441e-01, 5.000000000000000e-01, ...
%!            6.452966314513557e-01, 7.850170085738940e-01, ...
%!            9.483163247594394e-01];
%! weights = [1.254676875668223e-01, 1.708286087294738e-01, ...
%!            1.218323586744639e-01, 1.637426900584793e-01, ...
%!            1.218323586744638e-01, 1.708286087294741e-01, ...
%!            1.254676875668223e-01];
%! rule    = [nodes; weights];
%! geometry = geo_load ({@ring_polar_map, @ring_polar_map_der});
%! [knots, breaks] = kntuniform ([10 10], [2 2], [1 1]);
%! breaks{1} ([2:3:end-2,3:3:end-1]) = [];
%! breaks{2} ([2:3:end-2,3:3:end-1]) = [];
%! [qn, qw]  = msh_set_quad_nodes (breaks, {rule, rule}, [0 1]);
%! msh = msh_cartesian (breaks, qn, qw, geometry);
%! space = sp_bspline (knots, [2, 2], msh);
%! mat = op_gradu_gradv_tp (space, space, msh, @(x, y) ones (size (x)));
%! rhs = op_f_v_tp (space, msh, @(x, y) (8-9*sqrt(x.^2+y.^2)).*sin(2*atan(y./x))./(x.^2+y.^2));
%! drchlt_dofs = [];
%! for iside = 1:4
%! drchlt_dofs = union (drchlt_dofs, space.boundary(iside).dofs);
%! end
%! int_dofs = setdiff (1:space.ndof, drchlt_dofs);
%! u = zeros (space.ndof, 1);
%! u(int_dofs) = mat(int_dofs, int_dofs) \ rhs(int_dofs);
%! err = sp_l2_error (space, msh, u, @(x,y)(x.^2+y.^2-3*sqrt(x.^2+y.^2)+2).*sin(2.*atan(y./x)));
%! assert (msh.nel, 9)
%! assert (space.ndof, 121)
%! assert (err, 4.71881595641687e-05, 1e-16)


function [X,err,iter] = ksupport(A,B,k,opts)

% Solve the k support norm minimization problem by ADMM
%
% min_X 0.5*||vec(X)||_ksp^2, s.t. AX=B
% ---------------------------------------------
% Input:
%       A       -    d*na matrix
%       B       -    d*nb matrix
%       k       -    >0, integer, parameter
%       opts    -    Structure value in Matlab. The fields are
%           opts.tol        -   termination tolerance
%           opts.max_iter   -   maximum number of iterations
%           opts.mu         -   stepsize for dual variable updating in ADMM
%           opts.max_mu     -   maximum stepsize
%           opts.rho        -   rho>=1, ratio used to increase mu
%           opts.DEBUG      -   0 or 1
%
% Output:
%       X       -    na*nb matrix
%       err     -    residual
%       iter    -    number of iterations
%
% version 1.0 - 27/06/2016
%
% Written by Canyi Lu (canyilu@gmail.com)
%

tol = 1e-8;
max_iter = 500;
rho = 1.1;
mu = 1e-4;
max_mu = 1e10;
DEBUG = 0;

if ~exist('opts', 'var')
    opts = [];
end
if isfield(opts, 'tol');         tol = opts.tol;              end
if isfield(opts, 'max_iter');    max_iter = opts.max_iter;    end
if isfield(opts, 'rho');         rho = opts.rho;              end
if isfield(opts, 'mu');          mu = opts.mu;                end
if isfield(opts, 'max_mu');      max_mu = opts.max_mu;        end
if isfield(opts, 'DEBUG');       DEBUG = opts.DEBUG;          end

[d,na] = size(A);
[~,nb] = size(B);

X = zeros(na,nb);
Z = X;
Y1 = zeros(d,nb);
Y2 = X;

AtB = A'*B;
I = eye(na);
invAtAI = (A'*A+I)\I;

iter = 0;
for iter = 1 : max_iter
    Xk = X;
    Zk = Z;
    % update X
    temp = Z-Y2/mu;
    temp = prox_ksupport(temp(:),k,1/mu);
    X = reshape(temp,na,nb);
    % update Z
    Z = invAtAI*(-A'*Y1/mu+AtB+Y2/mu+X);
    dY1 = A*Z-B;
    dY2 = X-Z;
    chgX = max(max(abs(Xk-X)));
    chgZ = max(max(abs(Zk-Z)));
    chg = max([chgX chgZ max(abs(dY1(:))) max(abs(dY2(:)))]);
    if DEBUG
        if iter == 1 || mod(iter, 10) == 0
            err = sqrt(norm(dY1,'fro')^2+norm(dY2,'fro')^2);
            disp(['iter ' num2str(iter) ', mu=' num2str(mu) ...
                    ', err=' num2str(err)]);
        end
    end

    if chg < tol
        break;
    end
    Y1 = Y1 + mu*dY1;
    Y2 = Y2 + mu*dY2;
    mu = min(rho*mu,max_mu);
end
err = sqrt(norm(dY1,'fro')^2+norm(dY2,'fro')^2);


function [ r, seed ] = r8_uniform_01 ( seed )

%*****************************************************************************80
%
%% R8_UNIFORM_01 returns a unit pseudorandom R8.
%
%  Discussion:
%
%    This routine implements the recursion
%
%      seed = 16807 * seed mod ( 2**31 - 1 )
%      r8_uniform_01 = seed / ( 2**31 - 1 )
%
%    The integer arithmetic never requires more than 32 bits,
%    including a sign bit.
%
%    If the initial seed is 12345, then the first three computations are
%
%      Input     Output      R8_UNIFORM_01
%      SEED      SEED
%
%         12345   207482415  0.096616
%     207482415  1790989824  0.833995
%    1790989824  2035175616  0.947702
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 September 2006
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Paul Bratley, Bennett Fox, Linus Schrage,
%    A Guide to Simulation,
%    Springer Verlag, pages 201-202, 1983.
%
%    Pierre L'Ecuyer,
%    Random Number Generation,
%    in Handbook of Simulation,
%    edited by Jerry Banks,
%    Wiley Interscience, page 95, 1998.
%
%    Bennett Fox,
%    Algorithm 647:
%    Implementation and Relative Efficiency of Quasirandom
%    Sequence Generators,
%    ACM Transactions on Mathematical Software,
%    Volume 12, Number 4, pages 362-376, 1986.
%
%    Peter Lewis, Allen Goodman, James Miller,
%    A Pseudo-Random Number Generator for the System/360,
%    IBM Systems Journal,
%    Volume 8, pages 136-143, 1969.
%
%  Parameters:
%
%    Input, integer SEED, the integer "seed" used to generate
%    the output random number.  SEED should not be 0.
%
%    Output, real R, a random value between 0 and 1.
%
%    Output, integer SEED, the updated seed.  This would
%    normally be used as the input seed on the next call.
%
  if ( seed == 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8_UNIFORM_01 - Fatal error!\n' );
    fprintf ( 1, '  Input SEED = 0!\n' );
    error ( 'R8_UNIFORM_01 - Fatal error!' );
  end

  seed = floor ( seed );

  seed = mod ( seed, 2147483647 );

  if ( seed < 0 )
    seed = seed + 2147483647;
  end

  k = floor ( seed / 127773 );

  seed = 16807 * ( seed - k * 127773 ) - k * 2836;

  if ( seed < 0 )
    seed = seed + 2147483647;
  end

  r = seed * 4.656612875E-10;

  return
end


%%*******************************************************
%%  Doptdesign: D-optimal experiment design.
%%
%%  max  log(det(sum_{i=1}^p lambda_i v_i v_i^T)) + const
%%
%%  s.t. lambda_i >= 0, sum_{i=1}^p lambda_i = 1.
%%
%%  Note: const = n.
%%  V:       nxp matrix with n <= p.
%%  lambda:  lambda_i is the fraction of the experiments
%%           allocated to test vector v_i.
%%  S: = V*diag(lambda)*V'.
%%
%%
%% SDPT3: version 3.0
%% Copyright (c) 1997 by
%% K.C. Toh, M.J. Todd, R.H. Tutuncu
%% Last modified: 2 Feb 01
%%*******************************************************

   function [blk,At,C,b,OPTIONS,lambda,bblk,AAt] = Doptdesign(V,solve);

   if (nargin == 1); solve = 0; end

   [n,p] = size(V);
   if (n > p);
     error(' size(V,1) > size(V,2)');
   end
%%
%% form blk, At, C, b
%%
   b = zeros(p,1);

   blk{1,1} = 's'; blk{1,2} = n;
   F = cell(1,p);
   for k = 1:p
      F{1,k} = -V(:,k)*V(:,k)';
   end
   At(1) = svec(blk(1,:),F,1);
   C{1,1} = sparse(n,n);

   blk{2,1} = 'l'; blk{2,2} = p;
   At{2,1} = -speye(p,p);
   C{2,1} = zeros(p,1);

   blk{3,1} = 'u'; blk{3,2} = 1;
   At{3,1} = ones(1,p);
   C{3,1} = 1;

   OPTIONS.parbarrier{1,1} = 1;
   OPTIONS.parbarrier{2,1} = 0;
   OPTIONS.parbarrier{3,1} = 0;
%%
%% form bblk, AAt to take into account of
%% low-rank constraint matrices of the form: -vk*vk'.
%%
    bblk = blk; AAt = At;
    bblk{1,1} = 's'; bblk{1,2} = n; bblk{1,3} = ones(1,p);
    AAt{1,1} = []; AAt{1,2} = V; AAt{1,3} = -ones(p,1);
%%
   if (solve)
      [obj,X,y,Z] = sqlp(blk,At,C,b,OPTIONS);
      lambda = -y;
   else
      lambda = [];
   end
%%*******************************************************


function [adm,admu,tdmu] = som_distortion(sM, D, arg1, arg2)

%SOM_DISTORTION Calculate distortion measure for the map.
%
% [adm,admu,tdmu] = som_distortion(sMap, D, [radius], ['prob'])
%
%  adm = som_distortion(sMap,D);
%  [adm,admu] = som_distortion(sMap,D);
%  som_show(sMap,'color',admu);
%
%  Input and output arguments:
%   sMap     (struct) a map struct
%   D        (struct) a data struct
%            (matrix) size dlen x dim, a data matrix
%   [radius] (scalar) neighborhood function radius to be used.
%                     Defaults to the last radius_fin in the
%                     trainhist field of the map struct, or 1 if
%                     that is missing.
%   ['prob'] (string) If given, this argument forces the
%                     neigborhood function values for each map
%                     unit to be normalized so that they sum to 1.
%
%   adm      (scalar) average distortion measure (sum(dm)/dlen)
%   admu     (vector) size munits x 1, average distortion in each unit
%   tdmu     (vector) size munits x 1, total distortion for each unit
%
% The distortion measure is defined as:
%                                           2
%    E = sum sum h(bmu(i),j) ||m(j) - x(i)||
%         i   j
%
% where m(i) is the ith prototype vector of SOM, x(j) is the jth data
% vector, and h(.,.) is the neighborhood function. In case of fixed
% neighborhood and discreet data, the distortion measure can be
% interpreted as the energy function of the SOM. Note, though, that
% the learning rule that follows from the distortion measure is
% different from the SOM training rule, so SOM only minimizes the
% distortion measure approximately.
%
% If the 'prob' argument is given, the distortion measure can be
% interpreted as an expected quantization error when the neighborhood
% function values give the likelyhoods of accidentally assigning
% vector j to unit i. The normal quantization error is a special case
% of this with zero incorrect assignement likelihood.
%
% NOTE: when calculating BMUs and distances, the mask of the given
%       map is used.
%
% See also SOM_QUALITY, SOM_BMUS, SOM_HITS.

% Reference: Kohonen, T., "Self-Organizing Map", 2nd ed.,
%    Springer-Verlag, Berlin, 1995, pp. 120-121.
%
%    Graepel, T., Burger, M. and Obermayer, K.,
%    "Phase Transitions in Stochastic Self-Organizing Maps",
%    Physical Review E, Vol 56, No 4, pp. 3876-3890 (1997).

% Contributed to SOM Toolbox vs2, Feb 3rd, 2000 by Juha Vesanto
% Copyright (c) by Juha Vesanto
% http://www.cis.hut.fi/projects/somtoolbox/

% Version 2.0beta juuso 030200

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% check arguments

% input arguments
if nargin < 2, error('Not enough input arguments.'); end

% map
M = sM.codebook;
munits = prod(sM.topol.msize);

% data
if isstruct(D), D = D.data; end
[dlen dim] = size(D);

% arg1, arg2
rad = NaN;
normalize = 0;
if nargin>2,
  if isnumeric(arg1), rad = arg1;
  elseif ischar(arg1) && strcmp(arg1,'prob'), normalize = 0;
  end
end
if nargin>3,
  if isnumeric(arg2), rad = arg2;
  elseif ischar(arg2) && strcmp(arg2,'prob'), normalize = 0;
  end
end

% neighborhood radius
if isempty(rad) || isnan(rad),
  if ~isempty(sM.trainhist), rad = sM.trainhist(end).radius_fin;
  else rad = 1;
  end
end
if rad<eps, rad = eps; end

% neighborhood
Ud = som_unit_dists(sM.topol);
switch sM.neigh,
 case 'bubble',   H = (Ud <= rad);
 case 'gaussian', H = exp(-(Ud.^2)/(2*rad*rad));
 case 'cutgauss', H = exp(-(Ud.^2)/(2*rad*rad)) .* (Ud <= rad);
 case 'ep',       H = (1 - (Ud.^2)/rad) .* (Ud <= rad);
end
if normalize,
  for i=1:munits, H(:,i) = H(:,i)/sum(H(:,i)); end
end

% total distortion measure
mu_x_1 = ones(munits,1);
tdmu = zeros(munits,1);
hits = zeros(munits,1);
for i=1:dlen,
  x = D(i,:);                        % data sample
  known = ~isnan(x);                 % its known components
  Dx = M(:,known) - x(mu_x_1,known); % each map unit minus the vector
  dist2 = (Dx.^2)*sM.mask(known);    % squared distances
  [qerr bmu] = min(dist2);           % find BMU
  tdmu = tdmu + dist2.*H(:,bmu);     % add to distortion measure
  hits(bmu) = hits(bmu)+1;           % add to hits
end

% average distortion per unit
admu = tdmu;
ind = find(hits>0);
admu(ind) = admu(ind) ./ hits(ind);

% average distortion measure
adm = sum(tdmu)/dlen;

return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


function A = add_hhmm_end_state(transprob, termprob)
% ADD_HMM_END_STATE Combine trans and term probs into transmat for automaton with an end state
% function A = add_hhmm_end_state(transprob, termprob)
%
% A(i,k,j) = Pr( i->j | Qps=k), where i in 1:Q, j in 1:(Q+1), and Q+1 is the end state
% This implements the equation in sec 4.6 of my tech report, where
% transprob(i,k,j) = \tilde{A}_k(i,j), termprob(k,j) = \tau_k(j)
%
% For the top level, the k index is missing.

Q = size(transprob,1);
toplevel = (ndims(transprob)==2);
if toplevel
  Qk = 1;
  transprob = reshape(transprob, [Q 1 Q]);
  termprob = reshape(termprob, [1 Q]);
else
  Qk = size(transprob, 2);
end

A = zeros(Q, Qk, Q+1);
A(:,:,Q+1) = termprob';

for k=1:Qk
  for i=1:Q
    for j=1:Q
      A(i,k,j) = transprob(i,k,j) * (1-termprob(k,i));
    end
  end
end

if toplevel
  A = squeeze(A);
end


%
% Usage:   [D [model]]=mexTrainDL(X,param[,model]);
%          model is optional
%
% Name: mexTrainDL
%
% Description: mexTrainDL is an efficient implementation of the
%     dictionary learning technique presented in
%
%     "Online Learning for Matrix Factorization and Sparse Coding"
%     by Julien Mairal, Francis Bach, Jean Ponce and Guillermo Sapiro
%     arXiv:0908.0050
%
%     "Online Dictionary Learning for Sparse Coding"
%     by Julien Mairal, Francis Bach, Jean Ponce and Guillermo Sapiro
%     ICML 2009.
%
%     Note that if you use param.mode=1 or 2, if the training set has a
%     reasonable size and you have enough memory on your computer, you
%     should use mexTrainDL_Memory instead.
%
%
%     It addresses the dictionary learning problems
%        1) if param.mode=0
%     min_{D in C} (1/n) sum_{i=1}^n (1/2)||x_i-Dalpha_i||_2^2  s.t. ...
%                                                  ||alpha_i||_1 <= lambda
%        2) if param.mode=1
%     min_{D in C} (1/n) sum_{i=1}^n  ||alpha_i||_1  s.t.  ...
%                                           ||x_i-Dalpha_i||_2^2 <= lambda
%        3) if param.mode=2
%     min_{D in C} (1/n) sum_{i=1}^n (1/2)||x_i-Dalpha_i||_2^2 + ...
%                                  lambda||alpha_i||_1 + lambda_2||alpha_i||_2^2
%        4) if param.mode=3, the sparse coding is done with OMP
%     min_{D in C} (1/n) sum_{i=1}^n (1/2)||x_i-Dalpha_i||_2^2  s.t. ...
%                                                  ||alpha_i||_0 <= lambda
%        5) if param.mode=4, the sparse coding is done with OMP
%     min_{D in C} (1/n) sum_{i=1}^n  ||alpha_i||_0  s.t.  ...
%                                           ||x_i-Dalpha_i||_2^2 <= lambda
%        6) if param.mode=5, the sparse coding is done with OMP
%     min_{D in C} (1/n) sum_{i=1}^n 0.5||x_i-Dalpha_i||_2^2 +lambda||alpha_i||_0
%
%
%     C is a convex set verifying
%        1) if param.modeD=0
%           C={  D in Real^{m x p}  s.t.  forall j,  ||d_j||_2^2 <= 1 }
%        2) if param.modeD=1
%           C={  D in Real^{m x p}  s.t.  forall j,  ||d_j||_2^2 + ...
%                                                  gamma1||d_j||_1 <= 1 }
%        3) if param.modeD=2
%           C={  D in Real^{m x p}  s.t.  forall j,  ||d_j||_2^2 + ...
%                                  gamma1||d_j||_1 + gamma2 FL(d_j) <= 1 }
%        4) if param.modeD=3
%           C={  D in Real^{m x p}  s.t.  forall j,  (1-gamma1)||d_j||_2^2 + ...
%                                  gamma1||d_j||_1 <= 1 }
%
%     Potentially, n can be very large with this algorithm.
%
% Inputs: X:  double m x n matrix   (input signals)
%               m is the signal size
%               n is the number of signals to decompose
%         param: struct
%            param.D: (optional) double m x p matrix   (dictionary)
%              p is the number of elements in the dictionary
%              When D is not provided, the dictionary is initialized
%              with random elements from the training set.
%           param.K (size of the dictionary, optional is param.D is provided)
%           param.lambda  (parameter)
%           param.lambda2  (optional, by default 0)
%           param.iter (number of iterations).  If a negative number is
%              provided it will perform the computation during the
%              corresponding number of seconds. For instance param.iter=-5
%              learns the dictionary during 5 seconds.
%           param.mode (optional, see above, by default 2)
%           param.posAlpha (optional, adds positivity constraints on the
%             coefficients, false by default, not compatible with
%             param.mode =3,4)
%           param.modeD (optional, see above, by default 0)
%           param.posD (optional, adds positivity constraints on the
%             dictionary, false by default, not compatible with
%             param.modeD=2)
%           param.gamma1 (optional parameter for param.modeD >= 1)
%           param.gamma2 (optional parameter for param.modeD = 2)
%           param.batchsize (optional, size of the minibatch, by default
%              512)
%           param.iter_updateD (optional, number of BCD iterations for the dictionary
%              update step, by default 1)
%           param.modeParam (optimization mode).
%              1) if param.modeParam=0, the optimization uses the
%                 parameter free strategy of the ICML paper
%              2) if param.modeParam=1, the optimization uses the
%                 parameters rho as in arXiv:0908.0050
%              3) if param.modeParam=2, the optimization uses exponential
%                 decay weights with updates of the form
%                 A_{t} <- rho A_{t-1} + alpha_t alpha_t^T
%           param.rho (optional) tuning parameter (see paper arXiv:0908.0050)
%           param.t0 (optional) tuning parameter (see paper arXiv:0908.0050)
%           param.clean (optional, true by default. prunes
%              automatically the dictionary from unused elements).
%           param.verbose (optional, true by default, increase verbosity)
%           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).
%
% Output:
%         param.D: double m x p matrix   (dictionary)
%
% Note: this function admits a few experimental usages, which have not
%     been extensively tested:
%         - single precision setting
%
% Author: Julien Mairal, 2009


%% DS - CDMA (SNR-Performance)
clear all;close all;clc;
nu=input('Number of Users = ');
u=[];s=[];
ml=input('Number of bits for each user = ');
hl=2^nextpow2(nu);
%
for k = 1:nu

u_binary(k,:)=randi([0 1],1,ml);

end
for k = 1:nu

u_BPSK(k,:)=u_binary(k,:)*2-1;

end
for n=1:nu
    s(n,:)=cdmat(u_BPSK(n,:),hl,n);
end
cd1=sum(s);
%% Oversampling
cd =rectpulse(cd1,4);
loo=0;
for SNR=0:2:8

    loo=loo+1;

    t=awgn(cd,SNR,'measured');

    %% Integrate and dump (downsampling)
    or=intdump(t,4);

    sr=[];
    for p=1:nu
        sr(p,:)=cdmar(or,hl,p,ml);
    end

    binary_rx=(sr+1)/2;
[n(loo),r(loo)]=symerr(u_BPSK,sr);
end

figure;%plot combined signals
%Tx
subplot(211);stem(cd1(1:20),'filled');
title('Combined signals (only 20 symbols');
xlabel('Index of Combined symbols');
ylabel('Magnitude');
grid;
%Rx
subplot(212);stem(or(1:20),'filled');
title('Combined noisy signals (only 20 symbols');
xlabel('Index of Combined symbols');
ylabel('Magnitude');

grid;

SNR=0:2:8;
figure; % plot the BER vs. SNR
semilogy(SNR,r,'r-x'),grid;

figure;% plot data for a randomly selected user such as user no. 1 before the BPSK mapping Tx and Rx
% Tx
subplot(211);stem(u_binary(1,1:10),'filled');grid
xlabel('Bits index');
title('Transmitted Bits (showing only 10 bits)');
% Rx
subplot(212);stem((sr(1,1:10)+1)/2,'filled');grid
xlabel('Bits index');
title('Received Bits (showing only 10 bits)');

figure;% plot data for a randomly selected user such as user no. 1 after the BPSK mapping Tx and Rx
% Tx
subplot(211);stem(u_BPSK(1,1:10),'filled');grid
xlabel('Symbol index');
title('Transmitted BPSK Symbols (showing only 10 Symbol)');
% Rx
subplot(212);stem(sr(1,1:10),'filled');grid
xlabel('Symbol index');
title('Received BPSK Symbols (showing only 10 Symbol)');


% MAIN.m  --  Lesson 2 -- Simple Drawing
%
% This script performs a simulation of the cart as it passively moves from
% some initial state.
%
% In the lesson I've moved the state plotting commands to their own
% function, and introduced some basic drawing concepts using plot
%

clc; clear;

%%%% Initial State
z0 = [
    0.0;   %horizontal position
    (pi/180)*120;  %pendulum angle (wrt gravity)
    0.0;   %horizontal velocity
    0.0];  %pendulum angular rate

%%%% Physical Parameters
p.m1 = 1.0;  % (kg) Cart mass
p.m2 = 0.3;  % (kg) pole mass
p.g = 9.81;  % (m/s^2) gravity
p.l = 0.5;   % (m) pendulum (pole) length

%%%% Time vector
t = linspace(0,2,250);  %Simulation time stamps

%%%% Function Handle
dynFun = @(t,z)( cartPoleDynamics(z, p) );

%%%% Simulate the system!
options = odeset(...
    'RelTol',1e-8, ...
    'AbsTol',1e-8);
[~, z] = ode45(dynFun, t, z0, options);   %  <-- This is the key line!
z = z';

%%%% Plots:
figure(1); clf;
plotPendulumCart(t,z);  %Moved plotting to its own function

%%%% Drawing:

% Convert states to cartesian positions:
pos = cartPolePosition(z,p);

% Unpack the positions:
x1 = pos(1,:);
y1 = pos(2,:);
x2 = pos(3,:);
y2 = pos(4,:);

% Compute the extents of the drawing, keeping everything in view
padding = 0.2*p.l;  %Free space around edges
xLow = min(min(x1,x2)) - padding;
xUpp = max(max(x1,x2)) + padding;
yLow = min(min(y1,y2)) - padding;
yUpp = max(max(y1,y2)) + padding;
extents = [xLow,xUpp,yLow,yUpp];

% Select an index corresponding to the time step to draw:
idx = 6;  %Draw the initial state for now

% Create and clear a figure:
figure(2); clf;
hold on;  %   <-- Important!

title('Cart-Pole System')

% Draw the rail that the cart-pole travels on
plot([xLow, xUpp],[0,0],'k-','LineWidth',2);

% Draw the cart:
plot(x1(idx), y1(idx), 'bs','MarkerSize',30,'LineWidth',5);

% Draw the pole:
plot([x1(idx),x2(idx)], [y1(idx), y2(idx)], 'r-','LineWidth',2);

% Draw the bob of the pendulum:
plot(x2(idx), y2(idx), 'ro','MarkerSize',22,'LineWidth',4);

% Format the axis so things look right:
axis(extents); axis equal; axis off;


function pc = ckf_packed_pc(x,fmmparam)
% CKF_PACKED_PC - Pack P and C for the Cubature Kalman filter transform
%
% Syntax:
%   pc = CKF_PACKED_PC(x,fmmparam)
%
% In:
%   x - Evaluation point
%   fmmparam - Array of handles and parameters to form the functions.
%
% Out:
%   pc - Output values
%
% Description:
%   Packs the integrals that need to be evaluated in nice function form to
%   ease the evaluation. Evaluates P = (f-fm)(f-fm)' and C = (x-m)(f-fm)'.

% Copyright (c) 2010 Hartikainen, Särkkä, Solin
%
% This software is distributed under the GNU General Public
% Licence (version 2 or later); please refer to the file
% Licence.txt, included with the software, for details.
%%

  f  = fmmparam{1};
  m  = fmmparam{2};
  fm = fmmparam{3};
  if length(fmmparam) >= 4
      param = fmmparam{4};
  end

  if ischar(f) || strcmp(class(f),'function_handle')
      if ~exist('param','var')
         F = feval(f,x);
      else
         F = feval(f,x,param);
      end
  elseif isnumeric(f)
         F = f*x;
  else
      if ~exist('param','var')
         F = f(x);
      else
         F = f(x,param);
      end
  end
  d = size(x,1);
  s = size(F,1);

  % Compute P = (f-fm)(f-fm)' and C = (x-m)(f-fm)'
  % and form array of [vec(P):vec(C)]
  pc = zeros(s^2+d*s,size(F,2));
  P = zeros(s,s);
  C = zeros(d,s);
  for k=1:size(F,2)
    for j=1:s
      for i=1:s
          P(i,j) = (F(i,k)-fm(i)) * (F(j,k) - fm(j));
      end
      for i=1:d
          C(i,j) = (x(i,k)-m(i)) * (F(j,k) - fm(j));
      end
    end
    pc(:,k) = [reshape(P,s*s,1);reshape(C,s*d,1)];
  end


function invA = cholinv(A)

% SYNTAX:
%   invA = cholinv(A);
%
% INPUT:
%   A = positive definite matrix to be inverted
%
% OUTPUT:
%   invA = inverse of matrix A
%
% DESCRIPTION:
%   Inverse of a positive definite matrix by using Cholesky decomposition.

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:       Andrea Nardo
%  Contributors:     ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   This program is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

% compute cholesky decomposition
n = size(A,1);
U    = chol(A);
invU = U\speye(n);
%L    = inv(L);
invA = invU * invU';


function dG0_prime = Transform(pseudoisomers, pH, I, T)
% Calculate pseudoisomer group standard transformed Gibbs energy of
% formation at specified pH, ionic strength and temperature.
%
% USAGE:
%
%    dG0_prime = Transform(pseudoisomers, pH, I, T)
%
% INPUTS:
%    pseudoisomers:    `p x 3` matrix with a row for each of the p pseudoisomers
%                      in the group, and the following columns:
%
%                        1. Standard Gibbs energy of formation,
%                        2. Number of hydrogen atoms,
%                        3. Charge.
%    pH:               pH.
%    I:                Ionic strength in mol/L.
%    T:                Temperature in Kelvin.
%
% OUTPUT:
%    dG0_prime:        Pseudoisomer group standard transformed Gibbs energy of
%                      formation in kJ/mol.
%
% .. Authors:
%       - Elad Noor, Nov. 2012
%       - Hulda SH, Nov. 2012, Added temperature dependent alpha.

R = 8.3144621e-3; % Gas constant in kJ/(K*mol)
alpha = (9.20483*T)/10^3 - (1.284668*T^2)/10^5 + (4.95199*T^3)/10^8; % Approximation of the temperature dependency of ionic strength effects
DH = (alpha * sqrt(I)) / (1 + 1.6 * sqrt(I)); % Debye Huckel

% dG0' = dG0 + nH * (RTlog(10) * pH + DH) + charge^2 * DH;
dG0_prime_vector = pseudoisomers(:, 1) + ...
    pseudoisomers(:, 2) * (R*T*log(10)*pH + DH) - ...
    pseudoisomers(:, 3).^2 * DH;

try
    dG0_prime = -R * T * maxstar(dG0_prime_vector / (-R * T));
catch
    disp(dG0_prime_vector)
    return
end


%PLOT_HOMLINE Draw a line in homogeneous form
%
% PLOT_HOMLINE(L) draws a 2D line in the current plot defined in homogenous
% form ax + by + c = 0  where L (3x1) is L = [a b c].
% The current axis limits are used to determine the endpoints of
% the line.  If L (3xN) then N lines are drawn, one per column.
%
% PLOT_HOMLINE(L, LS) as above but the MATLAB line specification LS is given.
%
% H = PLOT_HOMLINE(...) as above but returns a vector of graphics handles for the lines.
%
% Notes::
% - The line(s) is added to the current plot.
% - The line(s) can be drawn in 3D axes but will always lie in the
%   xy-plane.
%
% Example::
%          L = homline([1 2]', [3 1]'); % homog line from (1,2) to (3,1)
%          plot_homline(L, 'k--'); % plot dashed black line
%
% See also PLOT_BOX, PLOT_POLY, HOMLINE.

% Copyright (C) 1993-2019 Peter I. Corke
%
% This file is part of The Spatial Math Toolbox for MATLAB (SMTB).
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
% of the Software, and to permit persons to whom the Software is furnished to do
% so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in all
% copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
% FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
% COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
% IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
%
% https://github.com/petercorke/spatial-math

function handles = plot_homline(lines, varargin)

	% get plot limits from current graph
	xlim = get(gca, 'XLim');
	ylim = get(gca, 'YLim');

    ish = ishold;
    hold on;

    if min(size(lines)) == 1
        lines = lines(:);
    end

    assert(numrows(lines) == 3, 'SMTB:plot_homline:badarg', 'Input must be a 3-vector or 3xN matrix');

	h = [];
	% for all input lines (columns
	for l=lines
        if abs(l(2)) > abs(l(1))
            y = (-l(3) - l(1)*xlim) / l(2);
            hh = plot(xlim, y, varargin{:});
        else
            x = (-l(3) - l(2)*ylim) / l(1);
            hh = plot(x, ylim, varargin{:});
        end
		h = [h; hh];
	end

    if ~ish
        hold off
    end

	if nargout > 0,
		handles = h;
	end


function errors = test_filter()
%TEST_FILTERS This function test all the filters

errors = 0;

errors = errors + test_mexican_hat1();
errors = errors + test_mexican_hat2();
errors = errors + test_meyer();
errors = errors + test_abspline();
errors = errors + test_simple_tf();
errors = errors + test_itersine();
errors = errors + test_uniform_half_cosine();
errors = errors + test_design_warped_translates();
errors = errors + test_held();
errors = errors + test_simoncelli();
errors = errors + test_papadakis();
errors = errors + test_regular();

errors = errors + test_filter_lanczos();
errors = errors + test_filter_lanczos_multiple();

errors = errors + test_filter_lanczos_syn();
errors = errors + test_filter_lanczos_syn_multiple();

errors = errors + test_cheb_coeff();
errors = errors + test_cheb_op();
errors = errors + test_filter_analysis();
errors = errors + test_filter_synthesis();
errors = errors + test_filter_inverse();
errors = errors + test_localization();

errors = errors + test_multiple_dimensions();

errors = errors + test_reshape();
errors = errors + test_matrix_op();

try  %#ok<TRYNC>
    close(100)
end

end

function errors = test_regular()

errors = 0;
try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   g = gsp_design_regular(G);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: regular kernel 1 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel regular 1 test')
end

try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   param.d = 5;
   g = gsp_design_regular(G,param);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: regular kernel 2 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel regular 2 test')
end

try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   param.d = 0;
   g = gsp_design_regular(G,param);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: regular kernel 3 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel regular 3 test')
end

end

function errors = test_papadakis()

errors = 0;
try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   g = gsp_design_papadakis(G);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: papadakis kernel 1 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel papadakis 1 test')
end

try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   param.a = 0.25;
   g = gsp_design_papadakis(G,param);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: papadakis kernel 2 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel papadakis 2 test')
end

end

function errors = test_simoncelli()

errors = 0;
try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   g = gsp_design_simoncelli(G);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: simoncelli kernel 1 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel simoncelli 1 test')
end

try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   param.a = 0.25;
   g = gsp_design_simoncelli(G,param);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: simoncelli kernel 2 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel simoncelli 2 test')
end

end

function errors = test_held()

errors = 0;
try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   g = gsp_design_held(G);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: held kernel 1 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel held 1 test')
end

try

   figure(100);
   G = gsp_sensor(100);
   G = gsp_estimate_lmax(G);
   param.a = 0.25;
   g = gsp_design_held(G,param);
   gsp_plot_filter(G,g);
   close(100);

   fprintf('FILTER: held kernel 2 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error kernel held 2 test')
end

end

function errors = test_design_warped_translates()

errors = 0;
try

    figure(100);
    Nf = 10;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    G = gsp_spectrum_cdf_approx(G);
    g = gsp_design_warped_translates(G, Nf);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: test_design_warped_translates 1 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in test_design_warped_translates 1 test')
end

try

    figure(100);
    Nf = 10;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    param.log =1 ;
    param.warping_type = 'spectrum_approximation';
    G = gsp_spectrum_cdf_approx(G);
    g = gsp_design_warped_translates(G, Nf,param);
    gsp_plot_filter(G,g);
     close(100);

   fprintf('FILTER: test_design_warped_translates 2 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in test_design_warped_translates 2 test')
end

try

    figure(100);
    Nf = 10;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    param.log =1 ;
    param.warping_type = 'custom';
    G = gsp_spectrum_cdf_approx(G);
    g = gsp_design_warped_translates(G, Nf,param);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: test_design_warped_translates 3 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in test_design_warped_translates 3 test')
end

try

    figure(100);
    Nf = 10;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    param.log =0 ;
    param.warping_type = 'custom';
    G = gsp_spectrum_cdf_approx(G);
    g = gsp_design_warped_translates(G, Nf,param);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: test_design_warped_translates 4 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in test_design_warped_translates 4 test')
end

try

    figure(100);
    Nf = 10;
    G = gsp_sensor(100);
    G = gsp_compute_fourier_basis(G);
    tol=1e-8;
    [unique_E,unique_E_inds]=unique(round(G.e*1/tol)*tol);
    param.approx_spectrum.x=unique_E;
    param.approx_spectrum.y=(unique_E_inds-1)/(G.N-1);
    param.interpolation_type='monocubic';
    param.log =0 ;
    param.warping_type = 'spectrum_interpolation';
    g = gsp_design_warped_translates(G, Nf,param);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: test_design_warped_translates 5 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in test_design_warped_translates 5 test')
end

try

    figure(100);
    Nf = 10;
    G = gsp_sensor(100);
    G = gsp_compute_fourier_basis(G);
    tol=1e-8;
    approx_spectrum_inds=1:11:100;
    N_bar=length(approx_spectrum_inds);
    [unique_subset_E, unique_subset_E_inds]=unique(round(G.e(approx_spectrum_inds)*1/tol)*tol);
    param.approx_spectrum.x=unique_subset_E;
    param.approx_spectrum.y=(unique_subset_E_inds-1)/(N_bar-1);
    param.interpolation_type='pwl';
    param.log =1 ;
    param.warping_type = 'spectrum_interpolation';
    G = gsp_spectrum_cdf_approx(G);
    g = gsp_design_warped_translates(G, Nf,param);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: test_design_warped_translates 6 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in test_design_warped_translates 6 test')
end

end

function errors = test_mexican_hat1()

errors = 0;
try

   G = gsp_sensor(100);
   gsp_design_mexican_hat(G, 5);

   fprintf('FILTER: mexican hat 1 ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in the mexican hat 1 test')
end

end

function errors = test_mexican_hat2()

errors = 0;
try

    figure(100);
    Nf = 4;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    g = gsp_design_mexican_hat(G, Nf);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: mexican hat 2 ok\n');
catch
    errors = 1;
    warning('FILTER: Error in the mexican hat 2 test')
end

end

function errors = test_uniform_half_cosine()

errors = 0;
try

    figure(100);
    Nf = 4;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    g = gsp_design_half_cosine(G, Nf);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: uniform half cosine ok\n');
catch
    errors = 1;
    warning('FILTER: Error in uniform half cosine test')
end

end

function errors = test_abspline()

errors = 0;
try

    figure(100);
    Nf = 4;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    g = gsp_design_abspline(G, Nf);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: abspline ok\n');
catch
    errors = 1;
    warning('FILTER: Error abspline test')
end

end

function errors = test_meyer()

errors = 0;
try

    figure(100);
    Nf = 4;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    g = gsp_design_meyer(G, Nf);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: meyer ok\n');
catch
    errors = 1;
    warning('FILTER: Error in meyer test')
end

end

function errors = test_simple_tf()

errors = 0;
try

    figure(100);
    Nf = 4;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    g = gsp_design_simple_tf(G, Nf);
    gsp_plot_filter(G,g);
    close(100);

   fprintf('FILTER: simple_tf ok\n');
catch
    errors = 1;
    warning('FILTER: Error in simple_tf test')
end

end

function errors = test_itersine()

errors = 0;
try

        Nf = 20;
        G = gsp_sensor(100);
        G = gsp_estimate_lmax(G);
        g = gsp_design_itersine(G, Nf);
        gsp_plot_filter(G,g);
        [A,B] = gsp_filterbank_bounds(G,g);

   fprintf('FILTER: itersine ok\n');
catch
    errors = errors + 1;
    warning('FILTER: Error in itersine test')
end

if norm(A-B)<eps(1000)
    fprintf('FILTER: itersine 2 ok\n');
else
    errors = errors + 1;
    warning('FILTER: Error in itersine 2 test')
end

end

function errors = test_cheb_coeff()

 errors = 0;
 try

   Nf = 4;
    G = gsp_sensor(100);
    G = gsp_estimate_lmax(G);
    g = gsp_design_meyer(G, Nf);
    c = gsp_cheby_coeff(G, g);

  fprintf('FILTER: cheb coeff ok\n');

 catch
	 errors = 1;
	 warning('FILTER: Error in cheb coeff test')
end

end

function errors = test_cheb_op()

errors = 0;
try

        Nf = 4;
        G = gsp_sensor(100);
        G = gsp_estimate_lmax(G);
        g = gsp_design_meyer(G, Nf);
        c = gsp_cheby_coeff(G, g);
        f = rand(G.N,1);
        r = gsp_cheby_op(G, c, f);

   fprintf('FILTER: cheb op ok\n');
catch
    errors = 1;
    warning('FILTER: Error in cheb op test')
end

end

function errors = test_filter_analysis()

    Nf = 4;
    G = gsp_sensor(10);
    G = gsp_estimate_lmax(G);
    G = gsp_compute_fourier_basis(G);
    g = gsp_design_meyer(G, Nf);
    f = rand(G.N,1);

    param.method = 'exact';
    param.order = 100;
    f1 = gsp_filter_analysis(G,g,f,param);
    param.method = 'cheby';
    f2 = gsp_filter_analysis(G,g,f,param);

    if norm(f1(:)-f2(:))/norm(f1) < 1e-4
        errors = 0;
       fprintf('FILTER: analysis ok\n');
    else
        errors = 1;
        warning('FILTER: Error in analysis test')
    end

end

function errors = test_filter_synthesis()

    Nf = 4;
    G = gsp_sensor(10);
    G = gsp_estimate_lmax(G);
    G = gsp_compute_fourier_basis(G);
    g = gsp_design_simple_tf(G, Nf);
    f = rand(G.N,1);
    f = f/norm(f);

    param.method = 'cheby';
    param.order = 1000;
    f1 = gsp_filter_analysis(G,g,f,param);
    f2 = gsp_filter_synthesis(G,g,f1,param);
    param.method = 'exact';
    f3 = gsp_filter_synthesis(G,g,f1,param);
    f4 = f2/norm(f2);

    if norm(f-f4) < 1e-5
        errors = 0;
       fprintf('FILTER: synthesis ok\n');
    else
        errors = 1;
        norm(f-f4)
        warning('FILTER: Error in synthesis test')
    end

    if norm(f3-f2)/norm(f2) < 1e-5
       fprintf('FILTER: synthesis 2 ok\n');
    else
        errors = errors+1;
        warning('FILTER: Error in synthesis 2 test')
    end
end

function errors = test_filter_inverse()

    Nf = 4;
     G = gsp_sensor(10);
%     G = gsp_estimate_lmax(G);
    G = gsp_compute_fourier_basis(G);

    g = gsp_design_mexican_hat(G, Nf);
    f = rand(G.N,1);

    param.method = 'exact';
    f1 = gsp_filter_analysis(G,g,f,param);
    f2 = gsp_filter_inverse(G,g,f1,param);

    if norm(f-f2) < 1e-10
        errors = 0;
       fprintf('FILTER: inverse ok\n');
    else
        errors = 1;
        warning('FILTER: Error in inverse test')
    end

end

function errors = test_localization()

   % Number of nodes
    N = 100;

    % Kernel
    tau = 0.1;

    g = @(x) exp(-tau*x);

    G1 = gsp_sensor(N);

    G1 = gsp_estimate_lmax(G1);
    s1 = sqrt(G1.N)*gsp_filter_analysis(G1,g,eye(N));

    % Do the test
    G1 = gsp_compute_fourier_basis(G1);
    shat = g(G1.e);
    s = gsp_igft(G1,shat);

    s2 = zeros(G1.N);
    for ii = 1:G1.N
        s2(:,ii) = gsp_translate_old(G1, s, ii);
    end

    if norm(s1-s2) < 1e-10
        errors = 0;
       fprintf('FILTER: localisation ok\n');
    else
        errors = 1;
        warning('FILTER: Error in localisation test')
    end

end

function errors = test_multiple_dimensions()

   % Number of nodes
    N = 100;

    G1 = gsp_sensor(N);

    Nf = 4;
    k = 6;

    G1 = gsp_estimate_lmax(G1);
    g = gsp_design_meyer(G1, Nf);

    G1 = gsp_estimate_lmax(G1);

    f = rand(N,k);

    s1 = gsp_filter_analysis(G1,g,f);

    s2 = zeros(G1.N*Nf,k);
    for ii = 1:k
        s2(:,ii) =  gsp_filter_analysis(G1,g,f(:,ii));
    end

    if norm(s1(:)-s2(:)) < 1e-10
        errors = 0;
       fprintf('FILTER: multiple_dimensions ok\n');
    else
        errors = 1;
        warning('FILTER: Error in multiple_dimensions test')
    end

    f1 = gsp_filter_synthesis(G1,g,s1);

    f2 = zeros(G1.N,k);
    for ii = 1:k
        f2(:,ii) =  gsp_filter_synthesis(G1,g,s1(:,ii));
    end

     if norm(f1(:)-f2(:)) < 1e-10
       fprintf('FILTER: multiple_dimensions 2 ok\n');
    else
        errors = errors + 1;
        warning('FILTER: Error in multiple_dimensions 2 test')
     end

        f1 = gsp_filter_inverse(G1,g,s1);

    f2 = zeros(G1.N,k);
    for ii = 1:k
        f2(:,ii) =  gsp_filter_inverse(G1,g,s1(:,ii));
    end

    if norm(f1(:)-f2(:)) < 1e-10
        fprintf('FILTER: multiple_dimensions 3 ok\n');
    else
        errors = errors + 1;
        warning('FILTER: Error in multiple_dimensions 3 test')
    end

%     if norm(f1(:)-f(:))/norm(f(:)) < 1e-6
%         fprintf('FILTER: multiple_dimensions 4 ok\n');
%     else
%         errors = errors + 1;
%         norm(f1(:)-f(:))/norm(f(:))
%         warning('FILTER: Error in multiple_dimensions 4 test')
%     end

end

function errors = test_reshape()

   % Number of nodes
    N = 10;
    M = 4;

    f = rand(M*N,N);

    ft = gsp_vec2mat(f,M);
    [f1, M2] = gsp_mat2vec(ft);

    errors = 0;

    if norm(f1(:)-f(:))/norm(f(:)) < 1e-12
        fprintf('FILTER: reshape ok\n');
    else
        errors = errors + 1;
        warning('FILTER: erros reshape test')
    end

    if norm(M2-M) < 1e-12
        fprintf('FILTER: reshape 2 ok\n');
    else
        errors = errors + 1;
        warning('FILTER: erros reshape test 2')
    end
end

function errors = test_matrix_op()

    errors = 0;
    % Number of nodes
    N = 100;

    G1 = gsp_sensor(N);

    Nf = 4;

    G1 = gsp_estimate_lmax(G1);
    g = gsp_design_meyer(G1, Nf);

    G1 = gsp_estimate_lmax(G1);

    x = rand(N,1);

    f = gsp_filter_analysis(G1,g,x);
    F = gsp_filterbank_matrix(G1,g);
    f1 = F'*x;

    if norm(f1(:)-f(:))/norm(f(:)) < 1e-12
        fprintf('FILTER: operator matrix ok\n');
    else
        errors = errors + 1;
        warning('FILTER: error in operator matrix test')
    end

end

function errors = test_filter_lanczos()

    Nf = 4;
    G = gsp_sensor(10);
    G = gsp_estimate_lmax(G);
    G = gsp_compute_fourier_basis(G);
    g = gsp_design_meyer(G, Nf);
    f = rand(G.N,1);

    param.method = 'exact';
    param.order = 100;
    f1 = gsp_filter_analysis(G,g,f,param);
    param.method = 'lanczos';
    f2 = gsp_filter_analysis(G,g,f,param);

    if norm(f1(:)-f2(:))/norm(f1(:)) < 1e-10
        errors = 0;
       fprintf('FILTER: lanczos ok\n');
    else
        errors = 1;
        norm(f1(:)-f2(:))/norm(f1(:))
        warning('FILTER: Error in lanczos test')
    end

end

function errors = test_filter_lanczos_multiple()

    Nf = 4;
    G = gsp_sensor(10);
    G = gsp_estimate_lmax(G);
    G = gsp_compute_fourier_basis(G);
    g = gsp_design_meyer(G, Nf);
    f = rand(G.N,5);

    param.method = 'exact';
    param.order = 100;
    f1 = gsp_filter_analysis(G,g,f,param);
    param.method = 'lanczos';
    f2 = gsp_filter_analysis(G,g,f,param);

    if norm(f1(:)-f2(:))/norm(f1(:)) < 1e-10
        errors = 0;
       fprintf('FILTER: lanczos multiple ok\n');
    else
        errors = 1;
        norm(f1(:)-f2(:))/norm(f1(:))
        warning('FILTER: Error in lanczos multiple test')
    end

end

function errors = test_filter_lanczos_syn()

    Nf = 4;
    G = gsp_sensor(10);
    G = gsp_estimate_lmax(G);
    G = gsp_compute_fourier_basis(G);
    g = gsp_design_meyer(G, Nf);
    f = rand(G.N*Nf,1);

    param.method = 'exact';
    param.order = 100;
    f1 = gsp_filter_synthesis(G,g,f,param);
    param.method = 'lanczos';
    f2 = gsp_filter_synthesis(G,g,f,param);

    if norm(f1(:)-f2(:))/norm(f1(:)) < 1e-10
        errors = 0;
       fprintf('FILTER: lanczos synthesis ok\n');
    else
        errors = 1;
        norm(f1(:)-f2(:))/norm(f1(:))
        warning('FILTER: Error in lanczos synthesis test')
    end

end

function errors = test_filter_lanczos_syn_multiple()

    Nf = 4;
    G = gsp_sensor(10);
    G = gsp_estimate_lmax(G);
    G = gsp_compute_fourier_basis(G);
    g = gsp_design_meyer(G, Nf);
    f = rand(G.N*Nf,5);

    param.method = 'exact';
    param.order = 100;
    f1 = gsp_filter_synthesis(G,g,f,param);
    param.method = 'lanczos';
    f2 = gsp_filter_synthesis(G,g,f,param);

    if norm(f1(:)-f2(:))/norm(f1(:)) < 1e-10
        errors = 0;
       fprintf('FILTER: lanczos synthesis multiple test ok\n');
    else
        errors = 1;
        norm(f1(:)-f2(:))/norm(f1(:))
        warning('FILTER: Error in lanczos synthesis multiple test')
    end

end


%fsqfindpn(lambda,mu,c,m,n)
%   This function finds the probability there are n machines down
%   (in the system) for a machine repair problem (finite source queue).

function out = fsqfindpn(lambda,mu,c,m,n)

p0 = fsqfindp0(lambda,mu,c,m);

if n == 0
    pn = p0;
end

if n >= 1
    if n < c
        pn = nchoosek(m,n)*(lambda/mu)^n*p0;
    end
end

if n >= c
    if n <= m
        pn = nchoosek(m,n)*(lambda/mu)^n*p0*factorial(n)/(factorial(c)*c^(n-c));
    end
end

if n > m
    pn = 0;
end

out = pn;


%% Figure 1 of RSDS paper
% ``Rotation, Scaling and Deformation Invariant Scattering
% for Texture Discrimination"
% Laurent Sifre, Stephane Mallat.
% Proc. IEEE CVPR 2013 Portland, Oregon
%
%%

clear; close all;

%% build a filter bank of oriented and dilated morlet wavelets
size_in = [512, 512];
options.min_margin = [0, 0];
filters = morlet_filter_bank_2d(size_in, options);

%% build two grids of dirac
dirac_step = 64;
dirac_grid_1 = zeros(size_in);
dirac_grid_1(1:dirac_step:end, 1:dirac_step:end) = 1;
dirac_grid_2 = zeros(size_in);
dirac_grid_2(dirac_step/2+1:dirac_step:end, ...
    dirac_step/2+1:dirac_step:end) = 1;

%% convolves the grid with morlet filters
dirac_grid_1_f = fft2(dirac_grid_1);
dirac_grid_2_f = fft2(dirac_grid_2);

psi_1 = filters.psi.filter{17};
psi_2 = filters.psi.filter{17+4};

texture_1 = conv_sub_2d(dirac_grid_1_f, psi_1, 0);
texture_1 = texture_1 + conv_sub_2d(dirac_grid_1_f, psi_2, 0);

texture_2 = conv_sub_2d(dirac_grid_1_f, psi_1, 0);
texture_2 = texture_2 + conv_sub_2d(dirac_grid_2_f, psi_2, 0);

%% take real part
texture_1 = real(texture_1);
texture_2 = real(texture_2);

%% display the two textures
subplot(121);
imagesc(texture_1);
subplot(122);
imagesc(texture_2);
colormap gray;


 function [xs, Ps] = qpwls_qn(x, G, W, yy, C, P, niter)
%function [xs, Ps] = qpwls_qn(x, G, W, yy, C, P, niter)
%
% quadratic penalized weighted least squares (QPWLS) via
% (preconditioned) quasi-Newton (QN) algorithm
% cost(x) = (y-Gx)'W(y-Gx) / 2  + x'C'Cx / 2
% in
%	x	[np,1]		initial estimate
%	G	[nn,np]		system matrix
%	W	[nn,nn]		data weighting matrix
%	yy	[nn,1]		noisy data
%	C	[nc,np]		penalty 'derivatives' (R = \Half C'*C)
%	P	[np,np]		preconditioner (matrix or object)
%	niter			# total iterations
% out
%	xs	[np,niter]	estimates each iteration
%	ws	[np,niter]	P rank-one update terms each iteration
%
% Copyright July 2000, Jeff Fessler, The University of Michigan

if nargin < 3 || nargin > 7, ir_usage, end
np = ncol(G);

if ~isvar('C')		| isempty(C),		C = 0;			end
if ~isvar('P')		| isempty(P),		P = speye(np);		end
if ~isvar('niter')	| isempty(niter),	niter = 2;		end
if ~isvar('x')		| isempty(x),		x = zeros(np,1);	end

yy = yy(:);
xs = zeros(np, niter);
xs(:,1) = x;

ws = zeros(np, niter);
bs = zeros(1, niter);

%
% initialize projections
%
Gx = G * x;
Cx = C * x;

grad_next = G' * (W * (yy - Gx)) - C' * Cx;

%
% iterate
%
for iter = 2:niter

	grad = grad_next;

	%
	% compute ddir = P * grad, which is -s
	%
	ddir = Pmul(grad, P, bs(1:(iter-2)), ws(:,1:(iter-2)));
	x = x + ddir;

	% check if descent direction
	if ddir' * grad < 0
		warning('wrong direction')
%		keyboard
	end

	%
	% next (negative) gradient
	%
	Gx = G * x;
	Cx = C * x;
	grad_next = G' * (W * (yy - Gx)) - C' * Cx;

	q = grad_next - grad;
	w = ddir + Pmul(q, P, bs(1:(iter-2)), ws(:,1:(iter-2)));

	tmp = w' * q;
	if tmp == 0, error zero, end
	bs(iter-1) = 1 / tmp;
	ws(:,iter-1) = w;

	%
	% step size in search direction
	%
	if 0
		Gdir = G * ddir;
		Cdir = C * ddir;

		step = (ddir' * grad) / (Gdir'*(W*Gdir) + Cdir'*Cdir);
		steps(iter,1) = step;
		if step < 0
			warning('downhill?')
			keyboard
		end

		%
		% update
		%
		x	= x + step * ddir;
		Gx	= Gx  + step * Gdir;
		Cx	= Cx  + step * Cdir;
	end

	xs(:,iter) = x;
end

%
% multiply v = P_n * u where P_n = P_0 + \sum_i b_i w_i w_i'
%
function v = Pmul(u, P, bs, ws)
v = P * u;
bs = bs .* (u' * ws);
v = v - ws * bs';


% y-position of nose
function [data,units] = compute_ynose_mm(trx,n)

flies = trx.exp2flies{n};
nflies = numel(flies);
data = cell(1,nflies);
for i = 1:nflies,
  fly = flies(i);
  data{i} = trx(fly).y_mm + 2*trx(fly).a_mm.*sin(trx(fly).theta_mm);
end
units = parseunits('mm');


% book : Signals and Systems Laboratory with MATLAB
% authors : Alex Palamides & Anastasia Veloni
%
%
% problem 11 - Computes the linear convolution of two sequences

% b)
x1=1:4;
x2=7:-1:1;
y=linconv(x1,x2)

% c)
y=conv(x1,x2)


classdef MOEADDE_F7 < PROBLEM
% <multi> <real> <large/none>
% Benchmark MOP for testing MOEA/D-DE

%------------------------------- Reference --------------------------------
% H. Li and Q. Zhang, Multiobjective optimization problems with complicated
% Pareto sets, MOEA/D and NSGA-II, IEEE Transactions on Evolutionary
% Computation, 2009, 13(2): 284-302.
%------------------------------- 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
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 2;
            if isempty(obj.D); obj.D = 10; end
            obj.lower    = zeros(1,obj.D);
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,X)
            J1 = 3 : 2 : obj.D;
            J2 = 2 : 2 : obj.D;
            Y  = X - repmat(X(:,1),1,obj.D).^repmat((1+3*((1:obj.D)-2)/(obj.D-2))/2,size(X,1),1);
            PopObj(:,1) = X(:,1)         + 2*mean(4*Y(:,J1).^2-cos(8*Y(:,J1)*pi)+1,2);
            PopObj(:,2) = 1-sqrt(X(:,1)) + 2*mean(4*Y(:,J2).^2-cos(8*Y(:,J2)*pi)+1,2);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R(:,1) = linspace(0,1,N)';
            R(:,2) = 1 - R(:,1).^0.5;
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            R = obj.GetOptimum(100);
        end
    end
end