function out1=crossentropyerror(varargin)
%TEMPLATE_PERFORMANCE Template performance function.
%
%  WARNING - Future versions of the toolbox may require you to update
%  custom functions.
%
%  Directions for Customizing
%
%    1. Make a copy of this function with a new name
%    2. Edit your new function according to the code comments marked ***
%    3. Type HELP NNPERFORMANCE to see a list of other performance functions.
%
%  Syntax
%
%    perf = template_performance(E,Y,X,FP)
%    dPerf_dy = template_performance('dy',E,Y,X,perf,FP);
%    dPerf_dx = template_performance('dx',E,Y,X,perf,FP);
%    info = template_performance(code)
%
%  Description
%
%    TEMPLATE_PERFORMANCE(E,Y,X,PP) takes E and optional function parameters,
%      E - Matrix or cell array of error vectors.
%      Y - Matrix or cell array of output vectors. (ignored).
%      X  - Vector of all weight and bias values (ignored).
%      FP - Function parameters (ignored).
%     and returns the mean squared error.
%
%    TEMPLATE_PERFORMANCE('dy',E,Y,X,PERF,FP) returns derivative of PERF with respect to Y.
%    TEMPLATE_PERFORMANCE('dx',E,Y,X,PERF,FP) returns derivative of PERF with respect to X.
%    TEMPLATE_PERFORMANCE('name') returns the name of this function.
%    TEMPLATE_PERFORMANCE('pnames') returns the name of this function.
%    TEMPLATE_PERFORMANCE('pdefaults') returns the default function parameters.
%
%  Network Use
%
%    To prepare a custom network to be trained with TEMPLATE_PERFORMANCE set
%    NET.performFcn to 'template_performance'.  This will automatically set
%    NET.performParam to the default functions parameters.

% Copyright 1992-2007 The MathWorks, Inc.

fn = mfilename;
boiler_perform

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Name
function n = name

% *** CUSTOMIZE HERE
% *** Define this functions human readable name
n = 'Cross entropy sum error';
% ***

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Parameter Defaults
function fp = param_defaults()
fp = struct;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Parameter Names
function names = param_names
names = {};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Parameter Check
function err = param_check(fp)
err = {};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Apply Performance Function
function perf = performance(e,y,x,fp)

dontcareindices = find(~isfinite(y));
numdontcares = length(dontcareindices);
y(dontcareindices) = 0;

numElements = prod(size(y)) - length(dontcareindices);
if (numElements == 0)
  perf = 0;
else
    % предполагаем, что порядок входных векторов сохранился, а значит
    % вектора упорядоченны по убыванию релевантности
  dims =size(y);
  tmp = 0;
  res = 0;  
  for i=1:dims(2)
      for j=i+1:dims(2)
        tmp = y(11,j) - y(11,i) + log(1+exp(y(11,i)-y(11,j))); 
        res = res + tmp;
      end 
  end
  perf = res;
end
% ***

%%compute total cross-entripy derivative per document
function derivative=crossEntropyTotalDerivative(y,i)
dims = size(y);
tmp=0;
for j=1:dims(2)
    if(j < i)% j-й документ более релевантен
        tmp=tmp+(1/(1+exp(y(11,j)-y(11,i))));
    end;
    if(j > i)%j-й докуент менее релевантен  
        tmp=tmp+((-1)/(1+exp(y(11,i)-y(11,j))));
    end;
end;
derivative=tmp;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Derivative of Perf w/respect to Y
function d = derivative_dperf_dy(e,y,x,perf,fp)

%инициализируем массив производиных первые
%первые 10 строк будут нулями
dontcareindices = find(~isfinite(y));
numdontcares = length(dontcareindices);
y(dontcareindices) = 0;

% *** CUSTOMIZE HERE
% *** Calculate derivative of performance with respect to outputs Y
% *** This should include contributions of both error and any direct effect
% *** of outputs.
numElements = size(y,2);%prod(size(y)) - length(numdontcares);
d = repmat(0,[11,numElements]); 
if numElements == 0
  d = zeros(size(y));
else
%  res = 0;
  for i=1:numElements
      %счатем производную для i-го документа
      %res(i)=crossEntropyTotalDerivative(y,i);  
      d(11,i)=crossEntropyTotalDerivative(y,i);  
  end;
%  d=res;
end;
% ***

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Derivative of Perf w/respect to X
function d = derivative_dperf_dx(t,y,x,perf,fp)

dontcareindices = find(~isfinite(y));
numdontcares = length(dontcareindices);
y(dontcareindices) = 0;
numElements = size(y,2);%количество документов

n = length(x);
%вектор х длины 2471 = 245*10 (нейроны от входов к первому уровню) +
%10(сдвиги на первом уровне) + 10 (нейроны от первого уровня ко второму) +
%1 (сдвиг на втором уровне)
d = repmat(0,[n,1]); 
% *** CUSTOMIZE HERE
% *** Calculate the Nx1 derivative of performance with respect to the networks
% *** weights and biases.


%считаем частные производные для весов между входным и первым уровными
for n=1:2450
    %зафиксировали нейрон (nodeIndex,inputIndex):
    inputIndex=floor(n/10)+1;
    if inputIndex == 246
        break;
    end
    
    nodeIndex = rem(n,10);
    if nodeIndex == 0
        nodeIndex=10;
    end
    
    %считаем производные для всех документов
    %k - индекс документа
    tmp=0;
    for k=1:numElements
        %производная выхода нейронной сети по весу(nodeIndex,inputIndex)
        %x(2460+nodeIndex) - nodeIndex вес между первым и вторым уровнями
        %fp(inputIndex,k) -  inputIndex элемент вектора к-го документа
        %y(nodeIndex, k) - значения функций активации на первом слое. первый
        %индекс - номер элемента с лое, второй индекс номер документа,
        %который проходит через сеть
        %y(11,k) - выходн нейронной сети для к-го документа
        %derivative = y(k,1)*(1-y(k,1))*x(2460+nodeIndex)*y(k,2)*(1-y(k,2))*fp(inputIndex,k);
        derivative = y(11,k)*(1-y(11,k))*x(2460+nodeIndex)*y(nodeIndex,k)*(1-y(nodeIndex,k))*fp(inputIndex,k);
        tmp=tmp+derivative*crossEntropyTotalDerivative(y,k);
    end
    d(n)=tmp;
end    
%считаем частные производные для сдвигов на первом уровне
for n=2450:2460
    nodeIndex = rem(n,10);
    if nodeIndex == 0
        nodeIndex=10;
    end
    
    tmp=0;
    for k=1:numElements
        derivative = y(11,k)*(1-y(11,k))*x(2460+nodeIndex)*y(nodeIndex,k)*(1-y(nodeIndex,k));
        tmp=tmp+derivative*crossEntropyTotalDerivative(y,k);
    end
    d(n)=tmp;
end
%считаем частнные производные для весов между первым и вторым уровнями    
for n=2460:2470
    nodeIndex = rem(n,10);
    if nodeIndex == 0
        nodeIndex=10;
    end
    
    tmp=0;
    for k=1:numElements
        derivative = y(11,k)*(1-y(11,k))*y(nodeIndex,k);
        tmp=tmp+derivative*crossEntropyTotalDerivative(y,k);
    end
    d(n)=tmp;
end
%считаем производную для сдвига на втором уровне
tmp=0;
for k=1:numElements
    derivative = y(11,k)*(1-y(11,k));
    tmp=tmp+derivative*crossEntropyTotalDerivative(y,k);    
end
d(2471)=tmp;
% ***

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