function [new_patterns, targets] = kernel_PCA(patterns, targets, params)

% Reshape the data points using kernel principal component analysis
% 
% Inputs:
%	train_patterns	- Input patterns
%	train_targets	- Input targets
%	params	        - [output dimension, kernel, kernel parameter]
%                     Kernel can be one of: Gauss, RBF (Same as Gauss), Poly, Sigmoid, or Linear
%                     The kernel parameters are:
%                       RBF kernel  - Gaussian width (One parameter)
%                       Poly kernel - Polynomial degree
%                       Sigmoid     - The slope and constant of the sigmoid (in the format [1 2], with no separating commas)
%					    Linear		- None needed
%
% Outputs
%	patterns		- New patterns
%	targets			- New targets

[Dim, Nf]       = size(patterns);

%Get parameters
[dimension, kernel, ker_param] = process_params(params);

%Transform the input patterns
K	= zeros(Nf);
switch kernel,
case {'Gauss','RBF'},
   for i = 1:Nf,
      K(:,i)    = exp(-sum((patterns-patterns(:,i)*ones(1,Nf)).^2)'/(2*ker_param^2));
   end
case {'Poly', 'Linear'}
   if strcmp(kernel, 'Linear')
      ker_param = 1;
   end
   
   for i = 1:Nf,
      K(:,i) = (patterns'*patterns(:,i) + 1).^ker_param;
   end
case 'Sigmoid'
    ker_param = str2num(ker_param);
    
    if (length(ker_param) ~= 2)
        error('This kernel needs two parameters to operate!')
    end
    
   for i = 1:Nf,
      K(:,i) = tanh(patterns'*patterns(:,i)*ker_param(1)+ker_param(2));
   end
otherwise
   error('Unknown kernel. Can be Gauss, Linear, Poly, or Sigmoid.')
end

% Find eigenvalues of the kernel matrix
[v, e]          = eig(K);
new_patterns    = v(:, end-dimension+1:end)';

