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 )
%
%                                 ********************
%                                 ********************


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


% 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 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)');


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


 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';


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


function linpack_c_test12 ( )

%*****************************************************************************80
%
%% TEST12 tests CHIFA and CHISL.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 June 2009
%
%  Author:
%
%    John Burkardt
%
  n = 3;
  lda = n;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST12\n' );
  fprintf ( 1, '  For a single precision complex (C)\n' );
  fprintf ( 1, '  Hermitian matrix (HI):\n' );
  fprintf ( 1, '  CHIFA factors the matrix.\n' );
  fprintf ( 1, '  CHISL solves a linear system.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The matrix order is N = %d\n', n );
%
%  Set the values of the matrix A.
%
  seed = 123456789;

  for i = 1 : n
    [ a(i,i), seed ] = r4_uniform_01 ( seed );
    for j = i+1 : n
      [ a(i,j), seed ] = c4_uniform_01 ( seed );
      a(j,i) = conj ( a(i,j) );
    end
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '  The matrix A:\n' );
  fprintf ( 1, '\n' );

  for i = 1 : n
    for j = 1 : n
      fprintf ( 1, '  (%8f  %8f)', real ( a(i,j) ), imag ( a(i,j) ) );
    end
    fprintf ( 1, '\n' );
  end
%
%  Set the values of the right hand side vector B.
%
  [ x, seed ] = c4vec_uniform_01 ( n, seed );

  b(1:n) = a(1:n,1:n) * transpose ( x(1:n) );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  The right hand side B:\n' );
  fprintf ( 1, '\n' );
  for i = 1 : n
    fprintf ( 1, '  (%8f  %8f)\n', real ( b(i) ), imag ( b(i) ) );
  end
%
%  Factor the matrix A.
%
  [ a, ipvt, info ] = chifa ( a, lda, n );

  if ( info ~= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, '  CHIFA returned an error flag INFO = %d', info );
    return
  end
%
%  Solve the system.
%
  b = chisl ( a, lda, n, ipvt, b );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Computed                     Exact\n' );
  fprintf ( 1, '  Solution                     Solution\n' );
  fprintf ( 1, '\n' );

  for i = 1 : n
    fprintf ( 1, '  (%12f  %12f)  (%12f  %12f)\n', ...
      real ( b(i) ), imag ( b(i) ), real ( x(i) ), imag ( x(i) ) );
  end

  return
end


%% FUNCTION solve_trace_norm_RMTL
%   trace norm projection
%
%% LICENSE
%   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/>.
%
%   Copyright (C) 2011 - 2012 Jiayu Zhou, Jianhui and Jieping Ye
%
%   You are suggested to first read the Manual.
%   For any problem, please contact with Jiayu Zhou via jiayu.zhou@asu.edu
%
%   Last modified on June 3, 2012.
%

function L_hat = solve_trace_norm_RMTL(L, alpha)

[d1 d2] = size(L);

if (d1 > d2)

    [U S V] = svd(L, 0);

    thresholded_value = diag(S) - alpha / 2;

    diag_S = thresholded_value .* ( thresholded_value > 0 );

    L_hat = U * diag(diag_S) * V';

else

    new_L = L';

    [U S V] = svd(new_L, 0);

    thresholded_value = diag(S) - alpha / 2;

    diag_S = thresholded_value .* ( thresholded_value > 0 );

    L_hat = U * diag(diag_S) * V';

    L_hat = L_hat';

end


function l = luma(img)
%
%       l = luma(img)
%
%       This function calculates the luma
%
%
%       input:
%           img: an RGB image
%
%       output:
%           l: luminance as XYZ color
%
%     Copyright (C) 2016  Francesco Banterle
%
%     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/>.
%

col = size(img, 3);

switch col
    case 1
        l = img;

    case 3
        l = 0.299 * img(:,:,1) + 0.587 * img(:,:,2) + 0.114 * img(:,:,3);

    otherwise
        l = mean(img, 3);
        disp('Mean of channels was computed; the input image is not an RGB or luminance image!');
end

end


%This computes the hand-eye calibration using the method described in
%"Hand-Eye Calibration, Horaud, Radu and Dornaika, Fadi"
%
%Input:
%Hmarker2world      a 4x4xNumber_of_Views Matrix of the form
%                   Hmarker2world(:,:,i) = [Ri_3x3 ti_3x1;[ 0 0 0 1]]
%                   with
%                   i = number of the view,
%                   Ri_3x3 the rotation matrix
%                   ti_3x1 the translation vector.
%                   Defining the transformation of the robot hand / marker
%                   to the robot base / external tracking device
%Hgrid2cam          a 4x4xNumber_of_Views Matrix (like above)
%                   Defining the transformation of the grid to the camera
%
%Output:
%Hcam2marker_       The transformation from the camera to the marker /
%                   robot arm
%err                The residuals from the least square processes
%
%Christian Wengert
%Computer Vision Laboratory
%ETH Zurich
%Sternwartstrasse 7
%CH-8092 Zurich
%www.vision.ee.ethz.ch/cwengert
%wengert@vision.ee.ethz.ch
function [Hcam2marker_, err] =inria_calibration(Hmarker2world, Hgrid2cam)

n=size(Hmarker2world,3);
A=[];
B=[];
C=[];

for i=1:n-1
    Dm(:,:,i)=Hgrid2cam(:,:,i+1)*inv(Hgrid2cam(:,:,i));
    Tm(:,:,i)=Dm(1:3,4,i);  % used later to build Matrix B and C

    % equation from the paper:
    % Doff * Dmi->i+1 = inv(Deri+1) * Deri * Doff

    HH(:,:,i)=inv(Hmarker2world(:,:,i+1))*Hmarker2world(:,:,i);   % multiplication HH = Deri+1 * Deri --> quaternion(HH) = z
    z=dcm2q(HH(1:3,1:3,i));
    y=dcm2q(Dm(1:3,1:3,i));  %quaternion of Dm1->i+1

    % quaternion(Doff) * y = z * quaternion(Doff) -> A*quaternion(Doff)=0

    row1=[ z(4)-y(4) -z(3)-y(3)  z(2)+y(2) z(1)-y(1)];
    row2=[ z(3)+y(3)  z(4)-y(4) -z(1)-y(1) z(2)-y(2)];
    row3=[-z(2)-y(2)  z(1)+y(1)  z(4)-y(4) z(3)-y(3)];
    row4=[-z(1)+y(1) -z(2)+y(2) -z(3)+y(3) z(4)-y(4)];

    A=[A; row1; row2; row3; row4];  % build Matrix A

end

[U,S,V]=svd(A);
qoff=V(:,4);
Roff=q2dcm(qoff);
Roff=Roff';                     %  transpone Roff, maybe one of the matrices have wrong direction

% Building B and C matrix
for i=1:n-1
    B=[B; Hmarker2world(1:3,1:3,i+1)-Hmarker2world(1:3,1:3,i)];
    C=[C; Hmarker2world(1:3,4,i)-Hmarker2world(1:3,4,i+1)-Hmarker2world(1:3,1:3,i+1)*Roff*Tm(:,:,i)];
end

Toff=inv(B'*B)*B'*C;

Hcam2marker_=[Roff Toff; 0 0 0 1];

if(nargout==2)
    err = 0;
end


function [W,H]=nmfprob(X,K,maxiter,speak)
%
% Probabilistic NFM interpretating X as samples from a multinomial
%
% INPUT:
% X (N,M) : N (dimensionallity) x M (samples) non negative input matrix
% K       : Number of components
% maxiter : Maximum number of iterations to run
% speak   : prints iteration count and changes in connectivity matrix
%           elements unless speak is 0
%
% OUTPUT:
% W       : N x K matrix
% H       : K x M matrix
%
% Lars Kai Hansen, IMM-DTU (c) November 2005
%
print_iter=50;

powers=1.5+(2.5-1.5)*((1:maxiter)-1)/(maxiter-1);
% INITIALIZE
[D,N]=size(X);
X_factor = (sum(sum(X)));
X_org = X;
X=X/X_factor;

W=rand(D,K);
W=W./repmat(sum(W,1),D,1);
H=rand(K,N);
H=H./repmat(sum(H,2),1,N);
P=ones(K,1);
P=P/sum(P);
W1=W;H1=H;

% use W*H to test for convergence
Xr_old = W*H;

for n=1:maxiter,
    %E-step
    Qnorm=(W*diag(P))*H;

    for k=1:K,
        %E-step
        Q=(W(:,k)*H(k,:)*P(k))./(Qnorm+eps);
        XQ=X.*Q;
        %M-step W
        dummy=sum(XQ,2);
        W1(:,k)=dummy/(sum(dummy));
        dummy=sum(XQ,1);
        H1(k,:)=dummy/(sum(dummy));
    end

    W=W1;
    H=H1;

    %%%%%%%%%%%%%%%%%%%%%%%
    % print to screen
    %%%%%%%%%%%%%%%%%%%%%%%
    if (rem(n,print_iter)==0) & speak,
        Xr = W*H;
        diff = sum(sum(abs(Xr_old-Xr)));
        Xr_old = Xr;
        eucl_dist = nmf_euclidean_dist(X_org,W*diag(sqrt(P))*X_factor*diag(sqrt(P))*H);
        errorx = mean(mean(abs(X-W*H)))/mean(mean(X));
        disp(['Iter = ',int2str(n),...
            ', relative error = ',num2str(errorx),...
            ', diff = ', num2str(diff),...
            ', eucl dist ' num2str(eucl_dist)])
        if errorx < 10^(-5), break, end
    end
end,

W=W*diag(sqrt(P))*X_factor;
H=diag(sqrt(P))*H;


%%********************************************************************
%% igmres: compute ideal GMRES polynomial of deg m
%%         of a matrix B.
%%
%%    min || p(B) ||_2
%%    where p is a polynomial of degree <= m and p(0) = 1.
%%
%%    B = a general square matrix.
%%-----------------------------------------------------------
%%
%% [blk,Avec,C,b,X0,y0,Z0,objval,p] = igmres(B,m,feas,solve);
%%
%% B = a square matrix.
%% m = degree of polynomial.
%% feas  = 1 if want feasible starting point
%%       = 0 if otherwise.
%% solve = 0 just to initialize
%%       = 1 if want to solve the problem.
%%
%% p = ideal GMRES polynomial in Matlab format.
%%*****************************************************************
%% SDPT3: version 4.0
%% Copyright (c) 1997 by
%% Kim-Chuan Toh, Michael J. Todd, Reha H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************

 function [blk,Avec,C,b,X0,y0,Z0,objval,p] = igmres(B,m,feas,solve)

   if (nargin <= 3); solve = 0; end;
   if (nargin <= 2); feas  = 0; end;

   N = length(B);
   if (m >= N); error('degree >= size of B'); end;

   A = cell(1,m+1);
   [V,H,R] = orthbasis(B,m-1);
   A{1} = eye(N);
   for k = [1:m];  A{k+1} = B*V{k};  end;
   [blk,Avec,C,b,X0,y0,Z0,objval,xx] = norm_min(A,feas,solve);
   if (solve)
      y = xx;
      x1 = R(1:m,1:m)*y(1:m);
      p = [x1(m:-1:1); 1];
   else
      objval = []; p = [];
   end
%%********************************************************************


function out = ALM_SADAL_smoothed(D, opts)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Test ALM in the paper ''Fast Alternating Linearization Methods for
%       Minimizing the Sum of Two Convex Functions'', Donald Goldfarb,
%       Shiqian Ma and Katya Scheinberg, Tech. Report, Columbia University,
%       2009 - 2010.
%
% Author: Shiqian Ma
% Date  : Apr. 20, 2010
% IEOR, Columbia University, Copyright (2010)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[m,n] = size(D);
mu = opts.mu; sigma = opts.sigma; rho = opts.rho;
Y = zeros(m,n); gradgY = zeros(m,n);
X = D - Y; Dnorm = norm(D,'fro');
Lambda = zeros(m,n); sv = opts.sv;

for itr = 1: opts.maxitr
    if choosvd(n, sv) == 1
        [U, gamma, V] = lansvd(mu*Lambda-Y+D,sv,'L');
    else
        [U, gamma, V] = svd(mu*Lambda-Y+D, 'econ');
    end
    gamma = diag(gamma);
    gamma_new = gamma-mu*gamma./max(gamma,mu+sigma);
    svp = length(find(gamma > mu));
    if svp < sv
        sv = min(svp + 1, n);
    else
        sv = min(svp + round(0.05*n), n);
    end

    Xp = X;
    X = U*diag(gamma_new)*V';
    Lambda = Lambda - (X+Y-D)/mu;
    muY = mu;
    B = Lambda - (X-D)/muY;
    Yp = Y;

    Y = muY*B - muY*min(rho, max(-rho,muY*B/(sigma+muY)));
    Lambda = Lambda - (X+Y-D)/muY;

    StopCrit = norm(D-X-Y,'fro')/Dnorm;
    relX = norm(X-opts.Xs,'fro')/norm(opts.Xs,'fro');
    relY = norm(Y-opts.Ys,'fro')/norm(opts.Ys,'fro');
%     fprintf('iter: %d, mu: %3.2e, rank(X):%d, relX: %3.2e, relY: %3.2e,crit:%3.2e\n', ...
%         itr, mu, length(find(gamma_new>1e-3)), relX, relY, norm(D-X-Y,'fro')/norm(D,'fro'));
    %fprintf('iter: %d, mu: %3.2e, crit:%3.2e\n', itr, mu, norm(D-X-Y,'fro')/norm(D,'fro'));

    mu = max(opts.muf, mu*opts.eta_mu);
    sigma = max(opts.sigmaf, sigma*opts.eta_sigma);

    if StopCrit < opts.epsilon
        out.X = X; out.Y = Y; out.iter = itr; out.relX = relX; out.relY = relY; out.StopCrit = StopCrit;
        return;
    end
end

out.X = X;
out.Y = Y;
out.iter = itr;
out.relX = relX;
out.relY = relY;
out.StopCrit = StopCrit;


function img = discreteCylinder(varargin)
%DISCRETECYLINDER Discretize a 3D cylinder
%
%   IMG = discreteCylinder(LX, LY, LZ, P1, P2, RADIUS)
%   LX, LY and LZ are row vectors specifying position of vertex centers
%   along each coordinate.
%   P1 is the starting point of the cylinder, given as a 1-by-3 row vector
%   P2 is the ending point of the cylinder, given as a 1-by-3 row vector
%   RADIUS is the cylinder radius.
%
%   IMG = discreteCylinder(LX, LY, LZ, CYLINDER)
%   send parameters in a row vector, where CYLINDER is a 1-by-7 row vector
%   containing coordinates of start point, of end point, and radius:
%   CYLINDER = [X1 Y1 Z1 X2 Y2 Z2 R];
%
%   Example
%     % Compute the union of three mutually orthogonal cylinders
%     p0 = [30 30 30];
%     p1 = [90 30 30];
%     p2 = [30 90 30];
%     p3 = [30 30 90];
%     cyl1 = discreteCylinder(1:100, 1:100, 1:100, [p0 p1 25]);
%     cyl2 = discreteCylinder(1:100, 1:100, 1:100, [p0 p2 25]);
%     cyl3 = discreteCylinder(1:100, 1:100, 1:100, [p0 p3 25]);
%     cylUnion = cyl1 | cyl2 | cyl3;
%     [f v] = isosurface(cylUnion, .5);
%     figure;
%     drawMesh(v, f, 'linestyle', 'none', 'facecolor', 'r');
%     l = light; view([120 20]);
%
%   See also
%   imShapes, discreteBall, discreteCapsule3d
%

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2010-10-21
% Copyright 2006 INRA - CEPIA Nantes - MIAJ (Jouy-en-Josas).

%   HISTORY
%   2010-10-21 create from discreteCube

%% Process input arguments

% compute coordinate of image voxels
[lx, ly, lz, varargin] = parseGridArgs3d(varargin{:});
[x, y, z] = meshgrid(lx, ly, lz);

% process input parameters
if length(varargin) == 1
    % input is a 1-by-7 row vector
    var = varargin{1};
    if length(var) ~= 7
        error('Should specify a row vector with 7 inputs');
    end

    % extract first and last point coordinates
    p1 = var(1:3);
    p2 = var(4:6);
    radius = var(7);

elseif length(varargin) == 3
    % inputs are P1, P2 and R
    p1 = varargin{1};
    p2 = varargin{2};
    radius = varargin{3};

else
    error('wrong number of arguments: should be 1 or 3');
end

%% Transform voxel coordinates

% compute cylinder direction angle
dirVect = p2-p1;

[theta, phi, height] = cart2sph2(dirVect);

% compute coordinate of image voxels in cylinder reference system
% (cylinder pointing upwards)
trans = composeTransforms3d(...
    createTranslation3d(-p1),...
    createRotationOz(-phi),...
    createRotationOy(-theta),...
    createScaling3d(1./[radius radius height]));
[x, y, z] = transformPoint3d(x, y, z, trans);

%% Compute final image

% create image: simple threshold over 3 dimensions, and test z axis
img = ((x.*x + y.*y) < 1) & (z>0) & (z<1);


function [nyquist_number,Bezugsfrequenz,Signal_amp] = Fast_Harmonics(x,fs,duration)
xx = 0;
if xx == 1
    % Sampling
    fs = 1000;     % Sampling rate [Hz]
    Ts = 1/fs;     % Sampling period [s]
    fNy = fs / 2;  % Nyquist frequency [Hz]
    duration = 10; % Duration [s]
    t = 0 : Ts : duration-Ts; % Time vector
    noSamples = length(t);    % Number of samples
    % Original signal
    x = 220.*sin(2 .* pi .* 50 .* t);
    % Harmonics
    x1 = 100.*sin(2 .* pi .* 100 .* t);
    x2 = 100.*sin(2 .* pi .* 200 .* t);
    x3 = 100.*sin(2 .* pi .* 300 .* t);
    % Contaminated signal
    xn = x + x1 + x2 + x3;
    % Frequency analysis
    f = 0 : fs/noSamples : fs - fs/noSamples; % Frequency vector
    % FFT
    x_fft = abs(fft(x));
    xn_fft = abs(fft(xn));
    % Plot
    figure(1);
    subplot(2,2,1);
    plot(t, x);
    subplot(2,2,2);
    plot(t, xn);
    subplot(2,2,3);
    plot(f,x_fft);
    xlim([0 fNy]);
    subplot(2,2,4);
    plot(f,xn_fft);
    xlim([0 fNy]);
else
%     x is the sampled data
%     m = length(x) is the window length (number of samples)
%     fs is the samples/unit time
%     dt = 1/fs is Time increment per sample
%     t = (0:m-1)/fs Time range for data
%     y = fft(x,n) is the Discrete Fourier Transform (DFT)
%     abs(y) is the Amplitude of the DFT
%     (abs(y).^2)/n is power of the DFT
%     fs/n Frequency increment
%     f = (0:n-1)*(fs/n) is frequency range
%     fs/2 is Nyquist frequency
%     n = pow2(nextpowe2(m)) is the transfrom length
    Ts = 1/fs;     % Sampling period [s]
    fNy = fs / 2;  % Nyquist frequency [Hz]
    t = 0 : Ts : duration-Ts; % Time vector
    noSamples = length(t);    % Number of samples
    % Original signal
    % Frequency analysis
    f = 0 : fs/noSamples : fs - fs/noSamples; % Frequency vector
    % FFT
    x_fft = abs(fft(x));
    xx = x';
    X = fft(xx(2:end));
    if rem(length(X),2)==0
        nyquist_number = length(X)/2;
    else
        nyquist_number = (length(X)+1)/2;
    end
    Bezugsfrequenz = 1/(t(end)-t(1));
    Signal_amp        = zeros(1,nyquist_number+1);
    Signal_phi        = zeros(1,nyquist_number+1);
    Signal_amp(1)     = X(1)/length(X);									                % Gleichanteil des Signals [unit]
    Signal_amp(2:end-1) = 2*abs(X(2:nyquist_number))/length(X);
    Signal_amp(end) = abs(X(nyquist_number+1))/length(X);
    %Signal_amp(2:end) = [2*abs(X(2:nyquist_number)) abs(X(nyquist_number+1))]/length(X);   % Amplituden der Harmonischen des Signals [unit]
    Signal_phi(1)     = 0;
    Signal_phi(2:end) = angle(X(2:nyquist_number+1));		                                % Phasenwinkel der Harmonischen des Signals [rad]

    %xn_fft = abs(fft(xn));
    % Plot
end


function H=calcSpherConvHessian(zSpher,systemType,useHalfRange,lTx,lRx,M)
%%CALCSPHERCONVHESSIAN Calculate the Hessian (a matrix of second partial
%            derivatives) for a monostatic or bistatic range and a
%            spherical direction measurement in 3D, ignoring atmospheric
%            effects, with respect to Cartesian position. This type of
%            Jacobian is useful when performing tracking using Cartesian-
%            converted measurements where the clutter density is specified
%            in the measurement coordinate system, not the converted
%            measurement coordinate system.
%
%INPUTS: zSpher A 3X1 point in range and azimuth and angle in the format
%           [range;azimuth;angle], where the angles are given in radians.
% systemType An optional parameter specifying the axes from which the
%           angles are measured in radians. Possible values are
%           0 (The default if omitted) Azimuth is measured
%             counterclockwise from the x-axis in the x-y plane. Elevation
%             is measured up from the x-y plane (towards the z-axis). This
%             is consistent with common spherical coordinate systems for
%             specifying longitude (azimuth) and geocentric latitude
%             (elevation).
%           1 Azimuth is measured counterclockwise from the z-axis in the
%             z-x plane. Elevation is measured up from the z-x plane
%             (towards the y-axis). This is consistent with some spherical
%             coordinate systems that use the z axis as the boresight
%             direction of the radar.
%           2 This is the same as 0 except instead of being given
%             elevation, one desires the angle away from the z-axis, which
%             is (pi/2-elevation).
%           3 This is the same as 0 except azimuth is measured clockwise
%             from the y-axis in the x-y plane instead of counterclockwise
%             from the x-axis. This coordinate system often arises when
%             given "bearings" in a local East-North-Up coordinate system,
%             where the bearing directions are measured East of North.
% useHalfRange An optional boolean value specifying whether the bistatic
%           (round-trip) range value has been divided by two. This normally
%           comes up when operating in monostatic mode (the most common
%           type of spherical coordinate system), so that the range
%           reported is a one-way range (or just half a bistatic range).
%           The default if this parameter is not provided is false if lTx
%           is provided and true if it is are omitted (monostatic). If no
%           range values are provided, an empty matrix can be passed.
%       lTx The 3X1 [x;y;z] location vector of the transmitter in global
%           Cartesian coordinates. If this parameter is omitted or an
%           empty matrix is passed, then the transmitter is assumed to be
%           at the origin.
%       lRx The 3X1 [x;y;z] location vector of the receiver in Cartesian
%           coordinates. If this parameter is omitted or an empty matrix
%           is passed, then the receiver is assumed to be at the origin.
%         M A 3X3 rotation matrix to go from the alignment of the global
%           coordinate system to that at the receiver. The z-axis of the
%           local coordinate system of the receiver is the pointing
%           direction of the receiver. If omitted or an empty matrix is
%           passed, then it is assumed that the local coordinate system is
%           aligned with the global and M=eye(3) --the identity matrix is
%           used.
%
%OUTPUTS: H The 3X3X3 Hessian matrix, where H(:,:,1) is the Hessian for the
%           range component, H(:,:,2) is the Hessian for the azimuth
%           component, and H(:,:,3) is the Hessian for the elevation
%           component. The ordering of the derivatives in each matrix is:
%                  [d^2/(dxdx), d^2/(dxdy), d^2/(dxdz);
%                   d^2/(dydx), d^2/(dydy), d^2/(dydz);
%                   d^2/(dzdx), d^2/(dzdy), d^2/(dzdz)];
%          note that each matrix is symmetric (i.e.
%                   d^2/(dydx)=d^2/(dxdy) ).
%
%This function just calls spher2Cart and then calcSpherHessian.
%
%June 2017 David F.Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<6||isempty(M))
	M=eye(3,3);
end

if(nargin<5)
   lRx=[];
end

if(nargin<4)
    lTx=[];
end

if(isempty(lTx)&&(nargin<3||isempty(useHalfRange)))
    useHalfRange=true;
elseif(~isempty(lTx)&&(nargin<3||isempty(useHalfRange)))
    useHalfRange=false;
end

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

x=spher2Cart(zSpher,systemType,useHalfRange,lTx,lRx,M);
H=calcSpherHessian(x,systemType,useHalfRange,lTx,lRx,M);

end

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


function phi = Segment2D_public( wb, wr, lambda, phi0, Nit )
% wb>0 edge detector
% wr region term
% lambda weight of region term over edge term
% phi0 initialization
% Nit number of iterations

verb = 1; fig_it = figure;
[Nx,Ny] = size(wb);
N = Nx*Ny;

% Parameters of augemented Lagrangian and minimizers
r1 = 1;
r2 = 1;
r3 = 0.1;
r4 = 0.1;
Njvarphi = 3; % increase it to get a better approximation to the minimizar with respect to varphi
Njphi = 2; % increase it to get better approximation to | grad phi | = 1
epsilon = 1; % controls smoothness of approximation to Heaviside and Dirac

% usufelu for FFT-based minimization
[Y,X] = meshgrid(0:Ny-1,0:Nx-1);
auxFFT = cos(2*pi/Nx*X)+cos(2*pi/Ny*Y)-2;

% initialize Lagrange multipliers and splitting variables
l1 = zeros(Nx,Ny);
l2x = zeros(Nx,Ny);
l2y = zeros(Nx,Ny);
l3 = zeros(Nx,Ny);
l4x = zeros(Nx,Ny);
l4y = zeros(Nx,Ny);
phi = phi0;
varphi = phi0;
u = H(phi0,epsilon);
dx = Fx(u);
dy = Fy(u);
px = Fx(phi);
py = Fy(phi);

wr = -lambda* wr;
% Start iterations: minimize w.r.t. each variable and update lagrange multipliers
for i=1:Nit

    % u^n+1 solved in Fourier domain
    b = r1*(H(varphi,epsilon)- l1/r1) - wr -r2* ( Bx(dx+l2x/r2)+By(dy+l2y/r2) );
    u = real(ifft2( fft2( b )./( -2*r2*auxFFT + r1 )));

    % d^n+1 solved by shrinkage
    Fxu = Fx(u);
    Fyu = Fy(u);
    [dx,dy] = shrink(Fxu - l2x/r2,Fyu - l2y/r2,wb/r2);

    % varphi^n+1 approx initialization and Newton method
    v = u + l1/r1;
    z = phi- l3/r3;
    E_0 = 0.5*r3*z.^2 + 0.5*r1*( 0.5 - v ).^2;
    E_z = 0.5*r1*( H(z,epsilon) - v ).^2;
        % initialize with solution to ideal Heaviside
    cond_m2 = ( z>=0 ).*( v>=0.5 ) + ( z<0 ).*( v<0.5 );
    varphi = z.*cond_m2 + (1-cond_m2).*( E_z < E_0 ).*z;
        % newton method to find zeros of derivative
    for j=1:Njvarphi
         df = r3*( varphi - z) + r1*( H(varphi,epsilon) - v ).*D(varphi,epsilon);
         hf = r3 + r1*D(varphi,epsilon).*D(varphi,epsilon) + r1*(H(varphi,epsilon) - v ).*dD(varphi,epsilon);
         varphi = varphi - df./( hf + (abs(hf)<1e-3) );
    end

    % lambda^n+1 update lagrangians
    l1 = l1 + r1* (u-H(varphi,epsilon));
    l2x = l2x + r2* (dx-Fxu);
    l2y = l2y + r2* (dy-Fyu);
    l3 = l3 + r3* (varphi- phi);

    %%%%%%%%%%%%%%%%%%%%%%%%%
    for jphi=1:Njphi

        % p^n+1 solved projecting in sphere
        ex = Fx(phi)-l4x/r4;
        ey = Fy(phi)-l4y/r4;
        norm_e = sqrt( ex.^2 + ey.^2 );
        px = ex./(norm_e + (norm_e==0));
        py = ey./(norm_e + (norm_e==0));

        % phi^n+1 solved in Fourier domain
        b = r3* (varphi+l3/r3) -r4.* ( Bx(px+l4x/r4)+By(py+l4y/r4) );
        phi = real(ifft2( fft2( b )./( -2*r4.*auxFFT + r3 )));

        % lambda^n+1 update lagrangians
        l4x = l4x + r4.*(px-Fx(phi));
        l4y = l4y + r4.*(py-Fy(phi));
    end

    %plotting
    if ((rem(i,5)==0)&&(verb==1))
        pause(0.01);
        figure(fig_it)
        clf; imagesc(phi); colormap(gray); colorbar;
        title([num2str(i), ' iterations']); hold on; contour(phi,[0 0],'m');
        for ct=-2:2; contour(phi,[ct ct],'k'); end; contour(phi,[0 0],'m');
    end
end

return;

% shrinkage function
function [xs,ys] = shrink(x,y,lambda)

s = sqrt(x.*conj(x)+y.*conj(y));
ss = s-lambda;
ss = ss.*(ss>0);

s = s+(s<lambda);
ss = ss./s;

xs = ss.*x;
ys = ss.*y;

return;

% smooth approximation of Heaviside function
function v = H(phi,epsilon)
v = 0.5*( 1 + 2/pi*atan(phi/epsilon) );
return;

% smooth approximation of Dirac distribution
function v = D(phi,epsilon)
v = 1/pi* epsilon./ (epsilon^2 + phi.^2);
return;

% smooth approximation of derivative of the Dirac distribution
function v = dD(phi,epsilon)
v = -2/pi* epsilon*phi./ (epsilon^2 + phi.^2).^2;

% Forward derivative operator on x with boundary condition u(:,1,:)=u(:,Nx,:)
function Fxu = Fx(u)
[Ny,Nx] = size(u);
Fxu = circshift(u,[0 -1])-u;
Fxu(:,Nx) = zeros(Ny,1);

% Forward derivative operator on y with boundary condition u(1,:,:)=u(Ny,:,:)
function Fyu = Fy(u)
[Ny,Nx] = size(u);
Fyu = circshift(u,[-1 0])-u;
Fyu(Ny,:) = zeros(1,Nx);

% Backward derivative operator on x with boundary condition Bxu(:,1)=u(:,1)
function Bxu = Bx(u)
[Ny,Nx] = size(u);
Bxu = u - circshift(u,[0 1]);
Bxu(:,1) = u(:,1);
Bxu(:,Nx) = -u(:,Nx-1);

% Backward derivative operator on x with boundary condition Bxu(1,:)=u(1,:)
function Byu = By(u)
[Ny,Nx] = size(u);
Byu = u - circshift(u,[1 0]);
Byu(1,:) = u(1,:);
Byu(Ny,:) = -u(Ny-1,:);


% This function is borrowed from rastamat

function d = deltas(x, w)
% D = deltas(X,W)  Calculate the deltas (derivatives) of a sequence
%    Use a W-point window (W odd, default 9) to calculate deltas using a
%    simple linear slope.  This mirrors the delta calculation performed
%    in feacalc etc.  Each row of X is filtered separately.
% 2003-06-30 dpwe@ee.columbia.edu

if nargin < 2
  w = 9;
end

[nr,nc] = size(x);

if nc == 0
  % empty vector passed in; return empty vector
  d = x;

else
  % actually calculate deltas

  % Define window shape
  hlen = floor(w/2);
  w = 2*hlen + 1;
  win = hlen:-1:-hlen;

  % pad data by repeating first and last columns
  xx = [repmat(x(:,1),1,hlen),x,repmat(x(:,end),1,hlen)];

  % Apply the delta filter
  d = filter(win, 1, xx, [], 2);  % filter along dim 2 (rows)

  % Trim edges
  d = d(:,2*hlen + [1:nc]);

end


function point_total_num = sparse_grid_mixed_size_total ( dim_num, level_max, rule )

%*****************************************************************************80
%
%% SPARSE_GRID_MIXED_SIZE sizes a sparse grid, counting duplicate points.
%
%  Discussion:
%
%    The sparse grid is the logical sum of product grids with total LEVEL
%    between LEVEL_MIN and LEVEL_MAX.
%
%    In some cases, the same point may occur in different product grids
%    used to form the sparse grid.
%
%    This routine counts the total number of points used to construct the sparse
%    grid; if the same point occurs several times, each occurrence is added
%    to the sum.
%
%    This computation is useful in order to be able to allocate enough
%    space for the full set of points, before they are compressed by removing
%    duplicates.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 March 2011
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Fabio Nobile, Raul Tempone, Clayton Webster,
%    A Sparse Grid Stochastic Collocation Method for Partial Differential
%    Equations with Random Input Data,
%    SIAM Journal on Numerical Analysis,
%    Volume 46, Number 5, 2008, pages 2309-2345.
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, integer LEVEL_MAX, the maximum value of LEVEL.
%
%    Input, integer RULE(DIM_NUM), the rule in each dimension.
%     1, "CC",  Clenshaw Curtis, Closed Fully Nested rule.
%     2, "F2",  Fejer Type 2, Open Fully Nested rule.
%     3, "GP",  Gauss Patterson, Open Fully Nested rule.
%     4, "GL",  Gauss Legendre, Open Weakly Nested rule.
%     5, "GH",  Gauss Hermite, Open Weakly Nested rule.
%     6, "GGH", Generalized Gauss Hermite, Open Weakly Nested rule.
%     7, "LG",  Gauss Laguerre, Open Non Nested rule.
%     8, "GLG", Generalized Gauss Laguerre, Open Non Nested rule.
%     9, "GJ",  Gauss Jacobi, Open Non Nested rule.
%    10, "GW",  Golub Welsch, (presumed) Open Non Nested rule.
%    11, "CC_SE", Clenshaw Curtis Slow Exponential, Closed Fully Nested rule.
%    12, "F2_SE", Fejer Type 2 Slow Exponential, Closed Fully Nested rule.
%    13, "GP_SE", Gauss Patterson Slow Exponential, Closed Fully Nested rule.
%    14, "CC_ME", Clenshaw Curtis Moderate Exponential, Closed Fully Nested rule.
%    15, "F2_ME", Fejer Type 2 Moderate Exponential, Closed Fully Nested rule.
%    16, "GP_ME", Gauss Patterson Moderate Exponential, Closed Fully Nested rule.
%    17, "CCN", Clenshaw Curtis Nested, Linear, Closed Fully Nested rule.
%
%    Output, integer POINT_TOTAL_NUM, the total number of points in the grid.
%

%
%  Special case.
%
  if ( level_max == 0 )
    point_total_num = 1;
    return
  end

  point_total_num = 0;
%
%  The outer loop generates values of LEVEL.
%
  level_min = max ( 0, level_max + 1 - dim_num );

  for level = level_min : level_max
%
%  The middle loop generates a GRID,
%  based on the next partition that adds up to LEVEL.
%
    level_1d = [];
    more_grids = 0;
    h = 0;
    t = 0;

    while ( 1 )

      [ level_1d, more_grids, h, t ] = comp_next ( level, dim_num, level_1d, ...
        more_grids, h, t );

      order_1d = level_to_order_default ( dim_num, level_1d, rule );

      point_total_num = point_total_num + prod ( order_1d(1:dim_num) );

      if ( ~more_grids )
        break
      end

    end

  end

  return
end


%% Random Search Algorithm (Pure Random Search Algorithm)

% This code finds the minimum of f(x) = x(1)^2 + x(2)^2
% in which -5 < x(i) < 5
% This function is a convex and the minimum is at (0,0)
% The RSA is the simplest algorithm to solve optimization problem
% it is not efficient and it sometimes cannot solve the problem

clc
close all
clear all
dim=2;
popsize=100;
ftarget=0.01;
numIter=100;
ObjFun=@(x) sum(x.^2);
for i=1:numIter
    candidate=10*rand(dim,popsize)-5;
    best=min(feval(ObjFun,candidate));
    if best <= ftarget
        break;
    end
end
disp(best);


function ring_render(ring_param,x_list,y_list)

%Extract ring parameters:
%------------------------
Ri=ring_param{2}; %inner radius
Ro=ring_param{3}; %outer modulation size
H=ring_param{4}; %height
Rfreq=ring_param{1}; %modulation frequency
face_color=ring_param{5}/255; %color

delta_theta=5; %angle spacing (smaller values will increase render time)
theta=0:delta_theta:360;

%Complete the list of cross-section nodes:
%-----------------------------------------
x=x_list;
y=y_list;
y_new=[x(1:length(x)-1) x(1)];
z_new=[y(1:length(y)-1) y(1)];
x_new=zeros(size(y));
x=x_new;
y=y_new+Ri;
z=z_new;
clear x_new y_new z_new

%Render ring:
%------------
for nt=1:length(theta)-1 %loop through each face angle

    th1=theta(nt);
    th2=theta(nt+1);

    for np=1:length(x)-1 %generate the edges of the face

        xtemp=x(np:np+1);
        ytemp=y(np:np+1);
        ztemp=z(np:np+1);

        %apply modulation to outer cross-section coordinates:
        r_temp1=(ytemp>Ri)*Ro*((sind(th1*Rfreq)+1)/2);
        r_temp2=(ytemp>Ri)*Ro*((sind(th2*Rfreq)+1)/2);

        %apply rotation transformation to cross-section coordinate:
        xtemp_rot1=xtemp*cosd(th1)+(ytemp+r_temp1)*sind(th1);
        xtemp_rot2=xtemp*cosd(th2)+(ytemp+r_temp2)*sind(th2);
        ytemp_rot1=xtemp*-sind(th1)+(ytemp+r_temp1)*cosd(th1);
        ytemp_rot2=xtemp*-sind(th2)+(ytemp+r_temp2)*cosd(th2);

        %edge lists:
        xtemp_face=[xtemp_rot1(1) xtemp_rot2(1) xtemp_rot2(2) xtemp_rot1(2) xtemp_rot1(1)];
        ytemp_face=[ytemp_rot1(1) ytemp_rot2(1) ytemp_rot2(2) ytemp_rot1(2) ytemp_rot1(1)];
        ztemp_face=[ztemp(1) ztemp(1) ztemp(2) ztemp(2) ztemp(1)];

        %render face:
        hf=fill3(xtemp_face,ytemp_face,ztemp_face,face_color);
        set(hf,'EdgeAlpha',0,'FaceLighting','phong','BackFaceLighting','lit','SpecularStrength',1,'FaceAlpha',.5)
        material shiny
        hold on
    end
end
axis equal
axis([-1 1 -1 1 -1 1]*(Ri+H))
axis off
set(gcf,'Color','k')
light('Position',[1 1 1]*25,'Style','local')
light('Position',[-1 1 -1]*25,'Style','local')
light('Position',[1 -1 -1]*25,'Style','local')
light('Position',[-1 -1 1]*25,'Style','local')


function xyz = cube2ball(XYZ)
%
% transforms cubochoric coordinates of quaternions into homochoric ones
% maps from cube (edge pi^(2/3) onto ball (radius (3*pi/4)^(1/3))
%
% Input
%  XYZ - cubochoric coordinates (X,Y,Z) of N points of the cube
%
% Output
%  xyz - homochoric coordinates (x,y,z) of N points of the ball

% the actual mapping is only defined on one pyramid Pz (z>=abs(x),z>=abs(y))
% map other points by:
%  1. transform coordinates, so that we get a point of Pz
%  2. map the point
%  3. apply the inverse transformation

% define permutaions (and inverse ones) for each region (pyramid)
p = regionId(XYZ);
permRegion  = [2 3 1;3 2 1;1 3 2;3 1 2;1 2 3;2 1 3];
ipermRegion = [3 1 2;3 2 1;1 3 2;2 3 1;1 2 3;2 1 3];

%  permXYZ contains for each point its permutation
% ipermXYZ contains for each point its inverse permutation

permXYZ  =  permRegion(p,:);
ipermXYZ = ipermRegion(p,:);

% apply the permutation on each grid point
XYZ = XYZ(sub2ind(size(XYZ), (1:size(XYZ,1)).' * [1 1 1] ,permXYZ));

% map each point
cosyx = sqrt(2) * cos(pi/12 * XYZ(:,2)./XYZ(:,1));
sinyx = sqrt(2) * sin(pi/12 * XYZ(:,2)./XYZ(:,1));

A = 2 * cosyx - 3;
B = 2 - cosyx;
C = (6/pi)^(1/3);
D = sqrt(A .* (XYZ(:,1).^2 - XYZ(:,3).^2) + XYZ(:,3).^2);
E = C * XYZ(:,1)./abs(XYZ(:,3)) .* D ./ B;

xyz = XYZ;
xyz(:,1) = E .* (cosyx - 1);
xyz(:,2) = E .* sinyx;
xyz(:,3) = C * (XYZ(:,3) + XYZ(:,1).^2 ./ XYZ(:,3) .* A ./ B);

% overwrite points with division by zero
O = (XYZ(:,1)==0);
xyz(O,:) = (6/pi)^(1/3) * XYZ(O,:);

xyz = xyz(sub2ind(size(xyz), (1:size(xyz,1)).' * [1 1 1] ,ipermXYZ));

end