function sc=ApEnSimCoeffOpt(x,len,st)
% Calculate similarity coefficient for a time serie:
%
%    Допоміжна функція; використовується в ApEn.
%    Функція оптимізована.
%
%    sc=ApEnSimCoeff(x,len,st)
%    Вхідні дані:
%       x      - вектор-стовпчик
%       len    - довжина паттерна
%       st     - значення критерія подібності
%    Вихідні дані:
%       sc     - значення коефіцієнтів подібності
%
%    Джерела:
%       Moody G. Approximate Entropy (ApEn) // http://www.physionet.org/
%
% (c) Сердюк О., 20.02.2007

[m,n]=size(x);                          % визначаємо розміри вхідного вектора
%len=len+1;                              % збільшуємо довжину досліджуваних векторів на 1

mCmp=zeros(m,len);                      % матриця для запису результатів порівняння векторів
cMatchesV=zeros(len,1);                 % кількість подібних векторів
cAllV=zeros(len,1);                     % загальна кількість векторів

% позначатимемо v(i,j): i-й вектор - (i,i+1,i+2,...) , j-а координата
% порівнюємо v(1:len,1) з v(1:len,i) та записуємо результати порівняння
for i=1:len
    % порівнюємо i-у координату 1-го вектора з такими ж для інших векторів
    rCmp=abs(x(i)-x(i:m))>st;
    nVec=m-i+1;                         % кількість векторів для порівняння
    j2=nVec;                            % кінцевий індекс для запису результатів
    icMatchesV=i;
    % додаємо результати порівняння до матриці
    for j=1:i
        mCmp(j:j2,j)=mCmp(j:j2,j) | rCmp(1:nVec);
        cMatchesV(icMatchesV)=cMatchesV(icMatchesV)+sum(mCmp(j:j2,j));
        cAllV(icMatchesV)=cAllV(icMatchesV)+nVec;
        j2=j2+1;
        icMatchesV=icMatchesV-1;
    end
end

% створюємо масив індексів для вибору векторів потрібної розмірності
index=1:len;

% проходимо по векторам, що залишились, та обробляємо їх
for i=len+1:m
    % циклічно повертаємо елементи масиву та обнуляємо потрібний стовпчик
    % матриці mCmp;
    index=[index(2:len) index(1)];
    mCmp(:,index(len))=0;
    
    % порівнюємо i-у координату i-го вектора з такими ж для інших векторів
    rCmp=abs(x(i)-x(i:m))>st;
    nVec=m-i+1;                         % кількість векторів для порівняння
    j1=i-(len-1); j2=j1+nVec-1;         % початковий та кінцевий індекс
                                        % для запису результатів
    icMatchesV=len;
    % додаємо результати порівняння до матриці
    for j=1:len
        jC=index(j);
        mCmp(j1:j2,jC)=mCmp(j1:j2,jC) | rCmp(1:nVec);
        cMatchesV(icMatchesV)=cMatchesV(icMatchesV)+sum(mCmp(j1:j2,jC));
        cAllV(icMatchesV)=cAllV(icMatchesV)+nVec;
        j1=j1+1; j2=j2+1;
        icMatchesV=icMatchesV-1;
    end
end

% визначаємо масив самоповторень
selfMatches=[m:-1:m-len+1];
selfMatches=selfMatches';
cMatchesV=cMatchesV.*2;
cAllV=cAllV.*2-selfMatches;
% розраховуємо кількість подібних векторів
cMatchesV=cAllV-cMatchesV;
% обраховуємо значення коефіцієнтів подібності
sc=cMatchesV./cAllV;

clear m n mCmp cMatchesV cAllV i rCmp nVec j2 icMatchesV index j1 jC;