Ищем прок от применения матриц - страница 5

 
Vladimir #:

Не надо просить разработчиков, если нужна матрица отличий - вычитаем матрицы друг их друга, поскольку https://www.mql5.com/ru/docs/matrix/matrix_operations (*):

"Математические операции — сложение, вычитание, умножение и деление — можно производить над матрицами и векторами почленно. "

Если нужны более хитрые сравнения, то https://www.mql5.com/ru/docs/matrix/matrix_manipulations :

Compare

Сравнивает элементы двух матриц/векторов с указанной точностью

CompareByDigits

Сравнивает элементы двух матриц/векторов на совпадение с точностью до значащих цифр

По поводу умножения на 100 см. пример на той же странице (*)  с вычитанием скаляра из вектора:

double avr=r.Mean();       // среднее значение массива
vector d=r-avr;            // вычислим массив отклонений от среднего значения

Дело в том, что получив разницу между чисел или булево значение о равенстве мы вынуждены для дальнейшей работы всё равно проводить сравнение полученных результатов. А если мы по результатам применения неравенств к матрицам получим ответ булевый, то сможем применить switch для ветвления дальнейших действий, что ускорит процесс вычисления.

Конечно я смотрю всё, что сейчас публикуется разработчиками.

 

Добавил генератор исходных данных - теперь можно пробовать подумать об ускорении вычислений.

2022.09.27 03:14:00.344 Terminal        Windows 7 Service Pack 1 build 7601, Intel Atom  N570 @ 1.66GHz, 0 / 1 Gb memory, 16 / 280 Gb disk, IE 11, UAC, GMT+3
2022.09.29 08:59:12.379 Scripts script Primer (FORTS-USDRUB,M15) removed
2022.09.29 08:59:40.042 Scripts script Primer (FORTS-USDRUB,M15) loaded successfully

Компьютер потратил 28 секунд на таблицу из 1000000 элементов. Конечно, компьютер слабенький - но всё же это не мало времени.

//+------------------------------------------------------------------+
//|                                                       Primer.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "-Aleks-"
#property link      "https://www.mql5.com/ru/users/-aleks-"
#property version   "1.00"
#property script_show_inputs
#property strict

sinput bool Random_Data=false;//Генерировать таблицу с данными?
input group "Параметры генерируемой таблицы"
sinput      int Strok_Total_Data_Random=1000;//Всего строк
sinput      int Stolb_Total_Data_Random=1000;//Всего столбцов
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
float arr_Data[];//Массив для первичных данных - выборка
float arr_Quant[];//Массив с таблицами неравенств (сплитов)
char arr_Target[];//Массив с целевыми
float arr_MiniData[]=//Массив для проверки логики с малым числом примеров - первичные данные
{
   7,0,1,
   8,1,2,
   9,0,3,
   10,1,1,
   11,0,2,
   12,1,3,
   13,0,1,
   14,1,2,
   15,0,3,
   16,1,1
};
float arr_MiniQuant[]=//Массив для проверки логики с малым числом примеров - таблицы неравенств (сплитов)
{
   0,10.5,
   0,14.5,
   0,15.5,
   1,0.5,
   2,0.5,
   2,1.5
};
char arr_MiniTarget[]=//Массив с целевыми
{
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1
};

int Strok_Total_Data=10;//Количество строк в таблице Data
int Stolb_Total_Data=3;//Количество столбцов в таблице Data

int Strok_Total_Quant=6;//Количество строк в таблице Quant
int Stolb_Total_Quant=2;//Количество столбцов в таблице Quant
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
{
   if(Random_Data==true)//Сгенерируем данные для оценки времени работы алгоритма
   {
      MathSrand(GetTickCount());
      float N_Random=0.0;//Переменная для сохранения случайного числа
      int Strok_Total_Quant_Random=0;

      int Size_Arr_RandomData=Strok_Total_Data_Random*Stolb_Total_Data_Random;
      float arr_RandomData[];
      float arr_RandomQuant[];
      int arr_RandomTarget[];

      ArrayResize(arr_RandomData,Size_Arr_RandomData);
      ArrayResize(arr_RandomTarget,Strok_Total_Data_Random);


      for(int i=0; i<Size_Arr_RandomData; i++) //Выберем комбинации
      {
         N_Random=RandomFloat(20);//Определяем число случайным образом
         arr_RandomData[i]=N_Random;
      }

      for(int i=0; i<Strok_Total_Data_Random; i++) //Выберем комбинации
      {
         N_Random=RandomFloat(2);//Определяем число случайным образом
         arr_RandomTarget[i]=(int)N_Random;
      }

      for(int i=0; i<Stolb_Total_Data_Random; i++) //Выберем комбинации
      {
         N_Random=RandomFloat(20);//Определяем число сплитов
         if(N_Random<1)N_Random=1;
         int Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         ArrayResize(arr_RandomQuant,Size_arr_RandomQuant+(int)N_Random*2);
         Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         float arr_N_Random[];
         ArrayResize(arr_N_Random,(int)N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
         {
            arr_N_Random[n]=RandomFloat(20);//Определяем значение сплитов
         }
         ArraySort(arr_N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
         {
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n]=(float)i;//Номер столбца
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n+1]=arr_N_Random[n];//Значение сплита
         }
      }

      ArrayCopy(arr_Data,arr_RandomData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_RandomQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_RandomTarget,0,0,WHOLE_ARRAY);

      Strok_Total_Data=Strok_Total_Data_Random;
      Stolb_Total_Data=Stolb_Total_Data_Random;
      Strok_Total_Quant_Random=ArraySize(arr_RandomQuant)/2;
      Strok_Total_Quant=Strok_Total_Quant_Random;
   }
   else
   {
      ArrayCopy(arr_Data,arr_MiniData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_MiniQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_MiniTarget,0,0,WHOLE_ARRAY);
   }


   int arr_N_Quant[];//Массив в котором будем хранить число сплитов квантовой таблицы для каждого предиктора
   ArrayResize(arr_N_Quant,Stolb_Total_Data);
   ArrayInitialize(arr_N_Quant,-1);

   int New_Size=0;//Для установки размера массива
   int N_Calc=1;//Счетчик
   int N_Pred=0;//Счетчик столбцов (//Номер предиктора)

   for(int i=1; i<Strok_Total_Quant; i++)//Найдем число сплитов для каждого предиктора
   {
      //Print("2*i=",2*i," 2*(i-1)=",2*(i-1));
      if(arr_Quant[2*i]>arr_Quant[2*(i-1)])
      {
         arr_N_Quant[N_Pred++]=N_Calc;
         if(New_Size<N_Calc)
         {
            New_Size=N_Calc;
         }
      N_Calc=1;
      }
      else N_Calc++;
      if(i+1==Strok_Total_Quant)arr_N_Quant[N_Pred++]=N_Calc;//Если последний индекс столбца, то сохраним его
   }

   int arr_Max_Calc[];//Массив в котором будем искать максимум после сортировки
   ArrayCopy(arr_Max_Calc,arr_N_Quant);//Скопируем массив
   ArraySort(arr_Max_Calc);//Отсортируем массив
   int Max_Ind=ArrayMaximum(arr_Max_Calc,0,WHOLE_ARRAY);//Присвоем индекс максимального значения массива
   int Max_N=arr_Max_Calc[Max_Ind];//Присвоем максимальное значение массива
   float arr_Quant_Trans[];//Массив, куда запишем преобразованную таблицу с неравенствами
   int Size_arr_Quant_Trans=(Max_N+1)*Stolb_Total_Data;//Размер массива транспонированной квантовой таблицы

   ArrayResize(arr_Quant_Trans,Size_arr_Quant_Trans);
   ArrayInitialize(arr_Quant_Trans,0);

   int Calc_Split=0;//Счетчик для подсчета числа сплитов
   int Index=0;
   New_Size=0;
   N_Calc=1;//Счетчик числа сплитов предиктора
   N_Pred=0;
   double Split=0.0;//Значение сплита
   for(int i=1; i<Strok_Total_Quant; i++)//Транспонируем квантовую таблицу и записывем число сплитов
   {
      arr_Quant_Trans[Stolb_Total_Data*(N_Calc)+N_Pred]=arr_Quant[2*i-1];//Значение сплита

      if(arr_Quant[2*i]>arr_Quant[2*(i-1)])//Новый сплит
      {
         Index=(int)arr_Quant[2*(i-1)];
         arr_Quant_Trans[Index]=(float)N_Calc;//Число сплитов в предикторе / столбца
         arr_N_Quant[N_Pred++]=N_Calc;
         if(New_Size<N_Calc)
         {
            New_Size=N_Calc;
         }
         N_Calc=1;
      }
      else N_Calc++;
      if(i+1==Strok_Total_Quant)//Если последний индекс столбца, то сохраним число сплитов в предикторе / столбца
      {
         arr_N_Quant[N_Pred++]=N_Calc;//Если последний индекс столбца, то сохраним его
         Index=(int)arr_Quant[2*i];
         arr_Quant_Trans[Index]=(float)N_Calc;//Число сплитов в предикторе / столбце
         arr_Quant_Trans[Stolb_Total_Data*(N_Calc)+N_Pred-1]=arr_Quant[2*i+1];//Значение сплита -1 так как это последнее значение, а счетчик N_Pred ранее по коду учел новое
      }
   }

   ushort arr_Data_Q[];//Таблица №3 с результатами классификации(квантования) выборки.
   ArrayResize(arr_Data_Q,Strok_Total_Data*Stolb_Total_Data);
   ArrayInitialize(arr_Data_Q,0);

   int Index_Data=0;//Индекс массива arr_Data и arr_Data_Q
   int Index_Quant_A=0;//Индекс массива arr_Quant_Trans для границы А
   int Index_Quant_B=0;//Индекс массива arr_Quant_Trans для границы Б

   float arr_Proc_Target[];//Процент принадлежности классов к целевой
   float arr_Proc_Otklik[];//Процент откликов классов ко всей таблице (выборке).
   ArrayResize(arr_Proc_Target,((Max_N+1)*Stolb_Total_Data)*2);//Делаем по размеру квантовой таблицы, умноженной на число разных значений (типов) целевых
   ArrayResize(arr_Proc_Otklik,((Max_N+1)*Stolb_Total_Data));//Делаем по размеру квантовой таблицы
   ArrayInitialize(arr_Proc_Target,0);
   ArrayInitialize(arr_Proc_Otklik,0);

   for(int p=0; p<Stolb_Total_Data; p++)
   {
      ushort arr_N_Class_Target[];//Считаем число целевых по их типам для каждого условного класса после квантования
      ushort arr_N_Class_Otklik[];//Считаем число откликов для каждого условного класса после квантования в выборке
      ArrayResize(arr_N_Class_Target,((int)arr_Quant_Trans[p]+1)*2);//Умножаем на количество разных целевых ("0" и "1")
      ArrayResize(arr_N_Class_Otklik,((int)arr_Quant_Trans[p]+1));//
      ArrayInitialize(arr_N_Class_Target,0);
      ArrayInitialize(arr_N_Class_Otklik,0);

      for(int i=0; i<Strok_Total_Data; i++)
      {
         Index_Data=Stolb_Total_Data*i+p;
         for(ushort q=0; q<arr_Quant_Trans[p]+1; q++)
         {
            if(arr_Quant_Trans[p]<1)
            {
               arr_Data_Q[Index_Data]=0;//Обнуляем значение предиктора, так как нет информации о сплитах
               break;
            }
            else
            {
               if(q==0)//Первый сплит
               {
                  Index_Quant_A=Stolb_Total_Data*(q+1)+p;//Рассчитаем индекс первой границы
                  if(arr_Data[Index_Data]<=arr_Quant_Trans[Index_Quant_A])
                  {
                     arr_Data_Q[Index_Data]=q+1;
                     break;
                  }
               }
               else
               {
                  Index_Quant_A=Stolb_Total_Data*(q+1-1)+p;//Рассчитаем индекс первой границы
                  Index_Quant_B=Stolb_Total_Data*(q+1)+p;//Рассчитаем индекс последней границы
                  if(q==arr_Quant_Trans[p])//Последний сплит "q" будет равно arr_Quant_Trans[p] при выходе за пределы массива)
                  {
                     if(arr_Data[Index_Data]>arr_Quant_Trans[Index_Quant_A])
                     {
                        arr_Data_Q[Index_Data]=q+1;
                        break;

                     }
                  }
                  else//Средние сплиты
                  {
                     if(arr_Data[Index_Data]>arr_Quant_Trans[Index_Quant_A] && arr_Data[Index_Data]<=arr_Quant_Trans[Index_Quant_B])
                     {
                        arr_Data_Q[Index_Data]=q+1;
                        break;
                     }

                  }
               }
            }
         }
         int Calc_Index=0;
         switch(arr_Target[i])
         {
         case 0:
            Calc_Index=((int)arr_Data_Q[Index_Data]-1)*2;
            break;
         case 1:
            Calc_Index=((int)arr_Data_Q[Index_Data]-1)*2+1;
            break;
         }
         arr_N_Class_Target[Calc_Index]++;//Прибавим 1 для подсчета целевой
         Calc_Index=((int)arr_Data_Q[Index_Data]-1);//Индекс для массива arr_N_Class_Otklik
         arr_N_Class_Otklik[Calc_Index]++;//Прибавим 1 для подсчета откликов
      }

      for(ushort q=0; q<arr_Quant_Trans[p]+1; q++)//Посчитаем проценты
      {
         int Summ=arr_N_Class_Target[2*q]+arr_N_Class_Target[2*q+1];
         //Print("Summ=",Summ);
         if (Summ>0)
         {
            arr_Proc_Target[Stolb_Total_Data*2*q+p*2]=float((double)arr_N_Class_Target[2*q]/(double)Summ*100.0);//Целевая "0"
            arr_Proc_Target[Stolb_Total_Data*2*q+p*2+1]=float((double)arr_N_Class_Target[2*q+1]/(double)Summ*100.0);//Целевая "1"
         }
         arr_Proc_Otklik[Stolb_Total_Data*q+p]=float((double)arr_N_Class_Otklik[q]/(double)Strok_Total_Data*100.0);

      }
   }
   Print("Задача №1 Таблица №3 с результатами классификации выборки.");
   ArrayPrint(arr_Data_Q);
   Print("Таблица №5 с результатами вычислений процента принадлежности классов к целевой.");
   ArrayPrint(arr_Proc_Target);
   Print("Таблица №6 с  результатами вычислений процента откликов классов ко всей таблице (выборке).");
   ArrayPrint(arr_Proc_Otklik);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|Определяем комбинацию случайным образом
//+------------------------------------------------------------------+
float RandomFloat(float max_vl)
{
   return (float)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);  //случайное Int от 0 до  1073741824
}
//+------------------------------------------------------------------+
 

Ниже код с использованием матриц. Генерацию случайными числами я оставил на базе массивов - думаю источник должен быть сопоставим.

Не заменил на вектора или матрицы массивы:

arr_N_Class_Target[];
arr_N_Class_Otklik[];

Прошлый код (Primer_00 - 22 секунды) и новый  (Primer_01 - 14 секунд) - выборка 10000 строк и 10000 столбцов, процессор FX-8350.

2022.10.10 17:12:30.416 Scripts script Primer_00 (EURUSD,H1) loaded successfully
2022.10.10 17:12:52.585 Scripts script Primer_00 (EURUSD,H1) removed

2022.10.10 17:13:12.679 Scripts script Primer_01 (EURUSD,H1) loaded successfully
2022.10.10 17:13:26.645 Scripts script Primer_01 (EURUSD,H1) removed

Прирост получается 8 секунд, не плохо.

Сам код, если есть идеи как ускорить или перевести на OpencCL - пишите.

//+------------------------------------------------------------------+
//|                                                       Primer.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "-Aleks-"
#property link      "https://www.mql5.com/ru/users/-aleks-"
#property version   "1.00"
#property script_show_inputs
#property strict

sinput bool Random_Data=false;//Генерировать таблицу с данными?
input group "Параметры генерируемой таблицы"
sinput      int Strok_Total_Data_Random=1000;//Всего строк
sinput      int Stolb_Total_Data_Random=1000;//Всего столбцов
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
float arr_Data[];//Массив для первичных данных - выборка
float arr_Quant[];//Массив с таблицами неравенств (сплитов)
char arr_Target[];//Массив с целевыми
float arr_MiniData[]=//Массив для проверки логики с малым числом примеров - первичные данные
  {
   7,0,1,
   8,1,2,
   9,0,3,
   10,1,1,
   11,0,2,
   12,1,3,
   13,0,1,
   14,1,2,
   15,0,3,
   16,1,1
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
float arr_MiniQuant[]=//Массив для проверки логики с малым числом примеров - таблицы неравенств (сплитов)
  {
   0,10.5,
   0,14.5,
   0,15.5,
   1,0.5,
   2,0.5,
   2,1.5
  };
char arr_MiniTarget[]=//Массив с целевыми
  {
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1
  };

int Strok_Total_Data=10;//Количество строк в таблице Data
int Stolb_Total_Data=3;//Количество столбцов в таблице Data

int Strok_Total_Quant=6;//Количество строк в таблице Quant
int Stolb_Total_Quant=2;//Количество столбцов в таблице Quant


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   if(Random_Data==true)//Сгенерируем данные для оценки времени работы алгоритма
     {
      MathSrand(GetTickCount());
      float N_Random=0.0;//Переменная для сохранения случайного числа
      int Strok_Total_Quant_Random=0;

      int Size_Arr_RandomData=Strok_Total_Data_Random*Stolb_Total_Data_Random;
      float arr_RandomData[];
      float arr_RandomQuant[];
      int arr_RandomTarget[];

      ArrayResize(arr_RandomData,Size_Arr_RandomData);
      ArrayResize(arr_RandomTarget,Strok_Total_Data_Random);


      for(int i=0; i<Size_Arr_RandomData; i++) //Выберем комбинации
        {
         N_Random=RandomFloat(20);//Определяем число случайным образом
         arr_RandomData[i]=N_Random;
        }

      for(int i=0; i<Strok_Total_Data_Random; i++) //Выберем комбинации
        {
         N_Random=RandomFloat(2);//Определяем число случайным образом
         arr_RandomTarget[i]=(int)N_Random;
        }

      for(int i=0; i<Stolb_Total_Data_Random; i++) //Выберем комбинации для квантовой таблицы
        {
         N_Random=RandomFloat(20);//Определяем число сплитов
         if(N_Random<1)
            N_Random=1;
         int Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         ArrayResize(arr_RandomQuant,Size_arr_RandomQuant+(int)N_Random*2);
         Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         float arr_N_Random[];
         ArrayResize(arr_N_Random,(int)N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
           {
            arr_N_Random[n]=RandomFloat(20);//Определяем значение сплитов
           }
         ArraySort(arr_N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
           {
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n]=(float)i;//Номер столбца
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n+1]=arr_N_Random[n];//Значение сплита
           }
        }

      ArrayCopy(arr_Data,arr_RandomData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_RandomQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_RandomTarget,0,0,WHOLE_ARRAY);

      Strok_Total_Data=Strok_Total_Data_Random;
      Stolb_Total_Data=Stolb_Total_Data_Random;
      Strok_Total_Quant_Random=ArraySize(arr_RandomQuant)/2;
      Strok_Total_Quant=Strok_Total_Quant_Random;
     }
   else
     {
      ArrayCopy(arr_Data,arr_MiniData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_MiniQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_MiniTarget,0,0,WHOLE_ARRAY);
     }

   matrixf m_Data;//Матрица с основной таблицей
   m_Data.Init(Strok_Total_Data*Stolb_Total_Data, 1);//Инициализировали матрицу
   vectorf V_Data;//Вектор для передачи массива в матрицу
   V_Data.Assign(arr_Data);//Скопировали массив в вектор
//Print("data after Assign", V_Data);
   m_Data.Col(V_Data,0);//Скопировали вектор в матрицу
   m_Data.Reshape(Strok_Total_Data, Stolb_Total_Data);//Имзенили размер матрицы вместе с данными
//Print("data after Reshape", m_Data);

   matrixf m_Quant;//Матрица с квантовой таблицей
   m_Quant.Init(Strok_Total_Quant*2, 1);//Инициализировали матрицу
   vectorf V_Quant;//Вектор для передачи массива в матрицу
   V_Quant.Assign(arr_Quant);//Скопировали массив в вектор
//Print("data after Assign", m_Quant);
   m_Quant.Col(V_Quant,0);//Скопировали вектор в матрицу
   m_Quant.Reshape(Strok_Total_Quant, 2);//Имзенили пропорцию матрицы вместе с данными
//Print("data after Reshape", m_Quant);

   vectorf V_Target;//Вектор для передачи массива в матрицу
   V_Target.Assign(arr_Target);//Скопировали массив в вектор
//Print("data after Assign", V_Target);

   int New_Size=0;//Для установки размера массива
   int N_Calc=1;//Счетчик
   int N_Pred=0;//Счетчик столбцов (//Номер предиктора)

   for(int i=1; i<Strok_Total_Quant; i++)//Транспонируем квантовую таблицу и записывем число сплитов
     {
      if(m_Quant[i][0]>m_Quant[i-1][0])//Новый предиктор
        {
         if(New_Size<N_Calc)
           {
            New_Size=N_Calc;
           }
         N_Pred++;
         N_Calc=0;
        }
      ++N_Calc;
      if(i+1==Strok_Total_Quant)//Если последний индекс столбца, то сохраним число сплитов в предикторе / столбца
         if(New_Size<N_Calc)
           {
            New_Size=N_Calc;
           }
     }

   int Max_N=New_Size;//Присвоем максимальное значение массива

//Print("Max_N=",Max_N);

   matrixf m_Quant_Trans;//Матрица с преобразованной квантовой таблицей
   m_Quant_Trans.Init(Max_N+1, Stolb_Total_Data);//Инициализировали матрицу
   m_Quant_Trans.Fill(0);//Заполняем матрицу нулями

   New_Size=0;
   N_Calc=1;//Счетчик числа сплитов предиктора
   N_Pred=0;

   for(int i=1; i<Strok_Total_Quant; i++)//Транспонируем квантовую таблицу и записывем число сплитов
     {
      if(m_Quant[i][0]>m_Quant[i-1][0])//Новый предиктор
        {
         m_Quant_Trans[0][N_Pred]=(float)N_Calc;//Сохраним число сплитов
         if(N_Pred==0)
           {
            m_Quant_Trans[1][0]=m_Quant[0][1];
           }
         N_Pred++;
         N_Calc=0;
        }

      m_Quant_Trans[++N_Calc][N_Pred]=m_Quant[i][1];

      if(i+1==Strok_Total_Quant)//Если последний индекс столбца, то сохраним число сплитов в предикторе / столбца
        {
         m_Quant_Trans[0][N_Pred]=(float)N_Calc;//Сохраним число сплитов
        }
     }

   Print("data after m_Quant_Trans", m_Quant_Trans);

   matrixf m_Data_Q;//Матрица с преобразованной квантовой таблицей
   m_Data_Q.Init(Strok_Total_Data, Stolb_Total_Data);//Инициализировали матрицу
   m_Data_Q.Fill(0);//Заполняем матрицу нулями
   matrixf m_Proc_Target;
   m_Proc_Target.Init(Max_N+1, Stolb_Total_Data*2);//Инициализировали матрицу
   m_Proc_Target.Fill(0);//Заполняем матрицу нулями
   matrixf m_Proc_Otklik;
   m_Proc_Otklik.Init(Max_N+1, Stolb_Total_Data);//Инициализировали матрицу
   m_Proc_Otklik.Fill(0);//Заполняем матрицу нулями

   for(int p=0; p<Stolb_Total_Data; p++)//Столбцы
     {
      ushort arr_N_Class_Target[];//Считаем число целевых по их типам для каждого условного класса после квантования
      ushort arr_N_Class_Otklik[];//Считаем число откликов для каждого условного класса после квантования в выборке
      ArrayResize(arr_N_Class_Target,((int)m_Quant_Trans[0][p]+1)*2);//Умножаем на количество разных целевых ("0" и "1")
      ArrayResize(arr_N_Class_Otklik,((int)m_Quant_Trans[0][p]+1));//
      ArrayInitialize(arr_N_Class_Target,0);
      ArrayInitialize(arr_N_Class_Otklik,0);

      for(int i=0; i<Strok_Total_Data; i++)//Строки
        {
         for(ushort q=0; q<m_Quant_Trans[0][p]+1; q++)//Сплиты
           {
            if(m_Quant_Trans[0][p]<1)
              {
               m_Data_Q[i][p]=0;//Обнуляем значение предиктора, так как нет информации о сплитах
               break;
              }
            else
              {
               if(q==0)//Первый сплит
                 {
                  if(m_Data[i][p]<=m_Quant_Trans[q+1][p])
                    {
                     m_Data_Q[i][p]=(float)q+1;
                     break;
                    }
                 }
               else
                 {
                  if(q==m_Quant_Trans[0][p])//Последний сплит "q" будет равно arr_Quant_Trans[p] при выходе за пределы массива)
                    {
                     if(m_Data[i][p]>m_Quant_Trans[q][p])
                       {
                        m_Data_Q[i][p]=(float)q+1;
                        break;
                       }
                    }
                  else//Средние сплиты
                    {
                     if(m_Data[i][p]>m_Quant_Trans[q][p] && m_Data[i][p]<=m_Quant_Trans[q+1][p])
                       {
                        m_Data_Q[i][p]=(float)q+1;
                        break;
                       }
                    }
                 }
              }
           }

         int Calc_Index=0;
         switch(arr_Target[i])
           {
            case 0:
               Calc_Index=((int)m_Data_Q[i][p]-1)*2;
               break;
            case 1:
               Calc_Index=((int)m_Data_Q[i][p]-1)*2+1;
               break;
           }
         arr_N_Class_Target[Calc_Index]++;//Прибавим 1 для подсчета целевой
         Calc_Index=((int)m_Data_Q[i][p]-1);//Индекс для массива arr_N_Class_Otklik
         arr_N_Class_Otklik[Calc_Index]++;//Прибавим 1 для подсчета откликов
        }

      for(ushort q=0; q<m_Quant_Trans[0][p]+1; q++)//Посчитаем проценты
        {
         int Summ=arr_N_Class_Target[2*q]+arr_N_Class_Target[2*q+1];
         //Print("Summ=",Summ);
         if(Summ>0)
           {
            m_Proc_Target[q][p*2]=float((double)arr_N_Class_Target[2*q]/(double)Summ*100.0);//Целевая "0"
            m_Proc_Target[q][p*2+1]=float((double)arr_N_Class_Target[2*q+1]/(double)Summ*100.0);//Целевая "1"
           }
         m_Proc_Otklik[q][p]=float((double)arr_N_Class_Otklik[q]/(double)Strok_Total_Data*100.0);
        }
     }
   Print("Задача №1 Таблица №3 с результатами классификации выборки.");
   Print(m_Data_Q);
   Print("Таблица №5 с результатами вычислений процента принадлежности классов к целевой.");
   Print(m_Proc_Target);
   Print("Таблица №6 с  результатами вычислений процента откликов классов ко всей таблице (выборке).");
   Print(m_Proc_Otklik);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|Определяем комбинацию случайным образом
//+------------------------------------------------------------------+
float RandomFloat(float max_vl)
  {
   return (float)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);  //случайное Int от 0 до  1073741824
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
 
А вот памяти в пике терминал потреблял 687 мегабайт -  Primer_00 (на массивах) и 1257 мегабайт (на матрицах) -  Primer_01, что конечно не очень хорошо. Да, можно было бы очистить массив с датой, но в реальной задаче мне она нужна, поэтому не вижу смысла.
 
Aleksey Vyazmikin #:
А вот памяти в пики терминал потреблял 687 мегабайт -  Primer_00 (на массивах) и 1257 мегабайт (на матрицах) -  Primer_01, что конечно не очень хорошо. Да, можно было бы очистить массив с датой, но в реальной задаче мне она нужна, поэтому не вижу смысла.

Видимо я описался, провел ещё раз замер матрица 10000 на 10000, терминал с 1 чартом, на массивах 661, на матрице 1636, на новом коде с матрицей пишу сразу результаты в m_Data, минуя m_Data_Q, таким образом экономим на памяти - расчет занял 1244 мегабайт.

Немного ускорил код, упростив и сократив вычисления индекса массивов.

//+------------------------------------------------------------------+
//|                                                       Primer.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "-Aleks-"
#property link      "https://www.mql5.com/ru/users/-aleks-"
#property version   "1.00"
#property script_show_inputs
#property strict

sinput bool Random_Data=false;//Генерировать таблицу с данными?
input group "Параметры генерируемой таблицы"
sinput      int Strok_Total_Data_Random=1000;//Всего строк
sinput      int Stolb_Total_Data_Random=1000;//Всего столбцов
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
float arr_Data[];//Массив для первичных данных - выборка
float arr_Quant[];//Массив с таблицами неравенств (сплитов)
char arr_Target[];//Массив с целевыми
float arr_MiniData[]=//Массив для проверки логики с малым числом примеров - первичные данные
  {
   7,0,1,
   8,1,2,
   9,0,3,
   10,1,1,
   11,0,2,
   12,1,3,
   13,0,1,
   14,1,2,
   15,0,3,
   16,1,1
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
float arr_MiniQuant[]=//Массив для проверки логики с малым числом примеров - таблицы неравенств (сплитов)
  {
   0,10.5,
   0,14.5,
   0,15.5,
   1,0.5,
   2,0.5,
   2,1.5
  };
char arr_MiniTarget[]=//Массив с целевыми
  {
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1
  };

int Strok_Total_Data=10;//Количество строк в таблице Data
int Stolb_Total_Data=3;//Количество столбцов в таблице Data

int Strok_Total_Quant=6;//Количество строк в таблице Quant
int Stolb_Total_Quant=2;//Количество столбцов в таблице Quant


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   if(Random_Data==true)//Сгенерируем данные для оценки времени работы алгоритма
     {
      MathSrand(GetTickCount());
      float N_Random=0.0;//Переменная для сохранения случайного числа
      int Strok_Total_Quant_Random=0;

      int Size_Arr_RandomData=Strok_Total_Data_Random*Stolb_Total_Data_Random;
      float arr_RandomData[];
      float arr_RandomQuant[];
      int arr_RandomTarget[];

      ArrayResize(arr_RandomData,Size_Arr_RandomData);
      ArrayResize(arr_RandomTarget,Strok_Total_Data_Random);


      for(int i=0; i<Size_Arr_RandomData; i++) //Выберем комбинации
        {
         N_Random=RandomFloat(20);//Определяем число случайным образом
         arr_RandomData[i]=N_Random;
        }

      for(int i=0; i<Strok_Total_Data_Random; i++) //Выберем комбинации
        {
         N_Random=RandomFloat(2);//Определяем число случайным образом
         arr_RandomTarget[i]=(int)N_Random;
        }

      for(int i=0; i<Stolb_Total_Data_Random; i++) //Выберем комбинации для квантовой таблицы
        {
         N_Random=RandomFloat(20);//Определяем число сплитов
         if(N_Random<1)
            N_Random=1;
         int Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         ArrayResize(arr_RandomQuant,Size_arr_RandomQuant+(int)N_Random*2);
         Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         float arr_N_Random[];
         ArrayResize(arr_N_Random,(int)N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
           {
            arr_N_Random[n]=RandomFloat(20);//Определяем значение сплитов
           }
         ArraySort(arr_N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
           {
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n]=(float)i;//Номер столбца
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n+1]=arr_N_Random[n];//Значение сплита
           }
        }

      ArrayCopy(arr_Data,arr_RandomData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_RandomQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_RandomTarget,0,0,WHOLE_ARRAY);

      Strok_Total_Data=Strok_Total_Data_Random;
      Stolb_Total_Data=Stolb_Total_Data_Random;
      Strok_Total_Quant_Random=ArraySize(arr_RandomQuant)/2;
      Strok_Total_Quant=Strok_Total_Quant_Random;
     }
   else
     {
      ArrayCopy(arr_Data,arr_MiniData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_MiniQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_MiniTarget,0,0,WHOLE_ARRAY);
     }

   matrixf m_Data;//Матрица с основной таблицей
   m_Data.Init(Strok_Total_Data*Stolb_Total_Data, 1);//Инициализировали матрицу
   vectorf V_Data;//Вектор для передачи массива в матрицу
   V_Data.Assign(arr_Data);//Скопировали массив в вектор
//Print("data after Assign", V_Data);
   m_Data.Col(V_Data,0);//Скопировали вектор в матрицу
   m_Data.Reshape(Strok_Total_Data, Stolb_Total_Data);//Имзенили размер матрицы вместе с данными
//Print("data after Reshape", m_Data);

   matrixf m_Quant;//Матрица с квантовой таблицей
   m_Quant.Init(Strok_Total_Quant*2, 1);//Инициализировали матрицу
   vectorf V_Quant;//Вектор для передачи массива в матрицу
   V_Quant.Assign(arr_Quant);//Скопировали массив в вектор
//Print("data after Assign", m_Quant);
   m_Quant.Col(V_Quant,0);//Скопировали вектор в матрицу
   m_Quant.Reshape(Strok_Total_Quant, 2);//Имзенили пропорцию матрицы вместе с данными
//Print("data after Reshape", m_Quant);

   vectorf V_Target;//Вектор для передачи массива в матрицу
   V_Target.Assign(arr_Target);//Скопировали массив в вектор
//Print("data after Assign", V_Target);

   int New_Size=0;//Для установки размера массива
   int N_Calc=1;//Счетчик
   int N_Pred=0;//Счетчик столбцов (//Номер предиктора)

   for(int i=1; i<Strok_Total_Quant; i++)//Транспонируем квантовую таблицу и записывем число сплитов
     {
      if(m_Quant[i][0]>m_Quant[i-1][0])//Новый предиктор
        {
         if(New_Size<N_Calc)
           {
            New_Size=N_Calc;
           }
         N_Pred++;
         N_Calc=0;
        }
      ++N_Calc;
      if(i+1==Strok_Total_Quant)//Если последний индекс столбца, то сохраним число сплитов в предикторе / столбца
         if(New_Size<N_Calc)
           {
            New_Size=N_Calc;
           }
     }

   int Max_N=New_Size;//Присвоем максимальное значение массива

//Print("Max_N=",Max_N);

   matrixf m_Quant_Trans;//Матрица с преобразованной квантовой таблицей
   m_Quant_Trans.Init(Max_N+1, Stolb_Total_Data);//Инициализировали матрицу
   m_Quant_Trans.Fill(0);//Заполняем матрицу нулями

   New_Size=0;
   N_Calc=1;//Счетчик числа сплитов предиктора
   N_Pred=0;

   for(int i=1; i<Strok_Total_Quant; i++)//Транспонируем квантовую таблицу и записывем число сплитов
     {
      if(m_Quant[i][0]>m_Quant[i-1][0])//Новый предиктор
        {
         m_Quant_Trans[0][N_Pred]=(float)N_Calc;//Сохраним число сплитов
         if(N_Pred==0)
           {
            m_Quant_Trans[1][0]=m_Quant[0][1];
           }
         N_Pred++;
         N_Calc=0;
        }

      m_Quant_Trans[++N_Calc][N_Pred]=m_Quant[i][1];

      if(i+1==Strok_Total_Quant)//Если последний индекс столбца, то сохраним число сплитов в предикторе / столбца
        {
         m_Quant_Trans[0][N_Pred]=(float)N_Calc;//Сохраним число сплитов
        }
     }

   Print("data after m_Quant_Trans", m_Quant_Trans);
   /*
   matrixf m_Data_Q;//Матрица с преобразованной квантовой таблицей
   m_Data_Q.Init(Strok_Total_Data, Stolb_Total_Data);//Инициализировали матрицу
   m_Data_Q.Fill(0);//Заполняем матрицу нулями
   */
   matrixf m_Proc_Target;
   m_Proc_Target.Init(Max_N+1, Stolb_Total_Data*2);//Инициализировали матрицу
   m_Proc_Target.Fill(0);//Заполняем матрицу нулями
   matrixf m_Proc_Otklik;
   m_Proc_Otklik.Init(Max_N+1, Stolb_Total_Data);//Инициализировали матрицу
   m_Proc_Otklik.Fill(0);//Заполняем матрицу нулями

   ushort arr_N_Class_Target[];//Считаем число целевых по их типам для каждого условного класса после квантования
   ushort arr_N_Class_Otklik[];//Считаем число откликов для каждого условного класса после квантования в выборке

   int Index=0;

   for(int p=0; p<Stolb_Total_Data; p++)//Столбцы
     {
      ArrayResize(arr_N_Class_Target,((int)m_Quant_Trans[0][p]+1)*2);//Умножаем на количество разных целевых ("0" и "1")
      ArrayResize(arr_N_Class_Otklik,((int)m_Quant_Trans[0][p]+1));//
      ArrayInitialize(arr_N_Class_Target,0);
      ArrayInitialize(arr_N_Class_Otklik,0);

      for(int i=0; i<Strok_Total_Data; i++)//Строки
        {
         for(ushort q=0; q<m_Quant_Trans[0][p]+1; q++)//Сплиты
           {
            Index=q;
            if(m_Quant_Trans[0][p]<1)
              {
               m_Data[i][p]=0;//Обнуляем значение предиктора, так как нет информации о сплитах
               break;
              }
            else
              {
               if(q==0)//Первый сплит
                 {
                  if(m_Data[i][p]<=m_Quant_Trans[q+1][p])
                    {
                     m_Data[i][p]=(float)q+1;
                     break;
                    }
                 }
               else
                 {
                  if(q==m_Quant_Trans[0][p])//Последний сплит "q" будет равно arr_Quant_Trans[p] при выходе за пределы массива)
                    {
                     if(m_Data[i][p]>m_Quant_Trans[q][p])
                       {
                        m_Data[i][p]=(float)q+1;
                        break;
                       }
                    }
                  else//Средние сплиты
                    {
                     if(m_Data[i][p]>m_Quant_Trans[q][p] && m_Data[i][p]<=m_Quant_Trans[q+1][p])
                       {
                        m_Data[i][p]=(float)q+1;
                        break;
                       }
                    }
                 }
              }
           }

         int Calc_Index=0;
         switch(arr_Target[i])
           {
            case 0:
               Calc_Index=Index*2;
               break;
            case 1:
               Calc_Index=Index*2+1;
               break;
           }
         arr_N_Class_Target[Calc_Index]++;//Прибавим 1 для подсчета целевой
         Calc_Index=Index;//Индекс для массива arr_N_Class_Otklik
         arr_N_Class_Otklik[Calc_Index]++;//Прибавим 1 для подсчета откликов
        }
      int Pn2=p*2;
      int Qn2=0;
      for(ushort q=0; q<m_Quant_Trans[0][p]+1; q++)//Посчитаем проценты
        {
         Qn2=q*2;
         int Summ=arr_N_Class_Target[Qn2]+arr_N_Class_Target[Qn2+1];
         //Print("Summ=",Summ);
         if(Summ>0)
           {
            m_Proc_Target[q][Pn2]=float((double)arr_N_Class_Target[Qn2]/(double)Summ*100.0);//Целевая "0"
            m_Proc_Target[q][Pn2+1]=float((double)arr_N_Class_Target[Qn2+1]/(double)Summ*100.0);//Целевая "1"
           }
         m_Proc_Otklik[q][p]=float((double)arr_N_Class_Otklik[q]/(double)Strok_Total_Data*100.0);
        }
     }
   Print("Задача №1 Таблица №3 с результатами классификации выборки.");
   Print(m_Data);
   Print("Таблица №5 с результатами вычислений процента принадлежности классов к целевой.");
   Print(m_Proc_Target);
   Print("Таблица №6 с  результатами вычислений процента откликов классов ко всей таблице (выборке).");
   Print(m_Proc_Otklik);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|Определяем комбинацию случайным образом
//+------------------------------------------------------------------+
float RandomFloat(float max_vl)
  {
   return (float)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);  //случайное Int от 0 до  1073741824
  }
//+------------------------------------------------------------------+
 

Сделал версию на OpenCL, если сравнивать с последним скриптом, то получается, что таблица 10000 на 10000 рассчиталась за 4,3 секунды, при этом время вычисления основного цикла для прошлого и текущего варианта было следующее

Для варианта с использованием матриц:
2022.11.01 22:10:47.672 Primer_02 (EURUSD,M1)   Время вычислений основного цикла=5864.159
Для варианта на OpenCL
2022.11.01 22:11:17.904 Primer_03 (EURUSD,M1)   Время вычислений основного цикла=1520.418

Т.е. увеличение скорости примерно в 3 раза, на мой взгляд прирост недостаточный, даже я бы сказал маленький, что бы идти и покупать видеокарту.

2022.11.01 21:56:15.646	OpenCL	device #0: GPU 'NVIDIA GeForce GTX 1660 SUPER' with OpenCL 3.0 (22 units, 1785 MHz, 6144 Mb, version 473.81, rating 5714)

2022.11.01 21:56:10.173	Terminal	Windows 7 Service Pack 1 build 7601, 8 x AMD FX-8350 Eight-Core, AVX, 25 / 31 Gb memory, 41 / 476 Gb disk, admin, GMT+3

Но, будем объективны, возможно мой код можно оптимизировать, что значительно повысит производительность - пишите, если знаете, как это сделать!

Код скрипта:

//+------------------------------------------------------------------+
//|                                                       Primer.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "-Aleks-"
#property link      "https://www.mql5.com/ru/users/-aleks-"
#property version   "1.00"
#property script_show_inputs
#property strict
//--- COpenCL class
#include <OpenCL/OpenCL.mqh>
COpenCL           m_OpenCL;
//--- исходные коды кернелов
#resource "tester.cl" as string cl_tester


sinput bool Random_Data=false;//Генерировать таблицу с данными?
input group "Параметры генерируемой таблицы"
sinput      int Strok_Total_Data_Random=1000;//Всего строк
sinput      int Stolb_Total_Data_Random=1000;//Всего столбцов
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
float arr_Data[];//Массив для первичных данных - выборка
float arr_Quant[];//Массив с таблицами неравенств (сплитов)
char arr_Target[];//Массив с целевыми
float arr_MiniData[]=//Массив для проверки логики с малым числом примеров - первичные данные
{
   7,0,1,
   8,1,2,
   9,0,3,
   10,1,1,
   11,0,2,
   12,1,3,
   13,0,1,
   14,1,2,
   15,0,3,
   16,1,1
};

float arr_MiniQuant[]=//Массив для проверки логики с малым числом примеров - таблицы неравенств (сплитов)
{
   0,10.5,
   0,14.5,
   0,15.5,
   1,0.5,
   2,0.5,
   2,1.5
};
char arr_MiniTarget[]=//Массив с целевыми
{
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1,
   0,
   1
};

int Strok_Total_Data=10;//Количество строк в таблице Data
int Stolb_Total_Data=3;//Количество столбцов в таблице Data

int Strok_Total_Quant=6;//Количество строк в таблице Quant
int Stolb_Total_Quant=2;//Количество столбцов в таблице Quant


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
{
   if(Random_Data==true)//Сгенерируем данные для оценки времени работы алгоритма
   {
      MathSrand(GetTickCount());
      float N_Random=0.0;//Переменная для сохранения случайного числа
      int Strok_Total_Quant_Random=0;

      int Size_Arr_RandomData=Strok_Total_Data_Random*Stolb_Total_Data_Random;
      float arr_RandomData[];
      float arr_RandomQuant[];
      int arr_RandomTarget[];

      ArrayResize(arr_RandomData,Size_Arr_RandomData);
      ArrayResize(arr_RandomTarget,Strok_Total_Data_Random);


      for(int i=0; i<Size_Arr_RandomData; i++) //Выберем комбинации
      {
         N_Random=RandomFloat(20);//Определяем число случайным образом
         arr_RandomData[i]=N_Random;
      }

      for(int i=0; i<Strok_Total_Data_Random; i++) //Выберем комбинации
      {
         N_Random=RandomFloat(2);//Определяем число случайным образом
         arr_RandomTarget[i]=(int)N_Random;
      }

      for(int i=0; i<Stolb_Total_Data_Random; i++) //Выберем комбинации для квантовой таблицы
      {
         N_Random=RandomFloat(20);//Определяем число сплитов
         if(N_Random<1)
            N_Random=1;
         int Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         ArrayResize(arr_RandomQuant,Size_arr_RandomQuant+(int)N_Random*2);
         Size_arr_RandomQuant=ArraySize(arr_RandomQuant);
         float arr_N_Random[];
         ArrayResize(arr_N_Random,(int)N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
         {
            arr_N_Random[n]=RandomFloat(20);//Определяем значение сплитов
         }
         ArraySort(arr_N_Random);
         for(int n=0; n<(int)N_Random; n++) //Выберем комбинации
         {
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n]=(float)i;//Номер столбца
            arr_RandomQuant[Size_arr_RandomQuant-(int)N_Random*2+2*n+1]=arr_N_Random[n];//Значение сплита
         }
      }

      ArrayCopy(arr_Data,arr_RandomData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_RandomQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_RandomTarget,0,0,WHOLE_ARRAY);

      Strok_Total_Data=Strok_Total_Data_Random;
      Stolb_Total_Data=Stolb_Total_Data_Random;
      Strok_Total_Quant_Random=ArraySize(arr_RandomQuant)/2;
      Strok_Total_Quant=Strok_Total_Quant_Random;
   }
   else
   {
      ArrayCopy(arr_Data,arr_MiniData,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Quant,arr_MiniQuant,0,0,WHOLE_ARRAY);
      ArrayCopy(arr_Target,arr_MiniTarget,0,0,WHOLE_ARRAY);
   }

   int arr_N_Quant[];//Массив в котором будем хранить число сплитов квантовой таблицы для каждого предиктора
   ArrayResize(arr_N_Quant,Stolb_Total_Data);
   ArrayInitialize(arr_N_Quant,-1);

   int New_Size=0;//Для установки размера массива
   int N_Calc=1;//Счетчик
   int N_Pred=0;//Счетчик столбцов (//Номер предиктора)

   for(int i=1; i<Strok_Total_Quant; i++)//Найдем число сплитов для каждого предиктора
   {
      if(arr_Quant[2*i]>arr_Quant[2*(i-1)])
      {
         arr_N_Quant[N_Pred++]=N_Calc;
         if(New_Size<N_Calc)
         {
            New_Size=N_Calc;
         }
         N_Calc=1;
      }
      else
         N_Calc++;
      if(i+1==Strok_Total_Quant)
         arr_N_Quant[N_Pred++]=N_Calc;//Если последний индекс столбца, то сохраним его
   }

   int arr_Max_Calc[];//Массив в котором будем искать максимум после сортировки
   ArrayCopy(arr_Max_Calc,arr_N_Quant);//Скопируем массив
   ArraySort(arr_Max_Calc);//Отсортируем массив
   int Max_Ind=ArrayMaximum(arr_Max_Calc,0,WHOLE_ARRAY);//Присвоем индекс максимального значения массива
   int Max_N=arr_Max_Calc[Max_Ind];//Присвоем максимальное значение массива
   int Size_arr_Quant_Trans=(Max_N+1)*Stolb_Total_Data;//Размер массива транспонированной квантовой таблицы

   float arr_Quant_Trans[];//Массив, куда запишем преобразованную таблицу с неравенствами
   ArrayResize(arr_Quant_Trans,Size_arr_Quant_Trans);
   ArrayInitialize(arr_Quant_Trans,0);
   Print("New_Size=",New_Size," Max_N=",Max_N);
   int Index=0;
   New_Size=0;
   N_Calc=1;//Счетчик числа сплитов предиктора
   N_Pred=0;
   double Split=0.0;//Значение сплита
   for(int i=1; i<Strok_Total_Quant; i++)//Транспонируем квантовую таблицу и записывем число сплитов
   {
      Index=(int)arr_Quant[2*(i-1)];
      arr_Quant_Trans[Stolb_Total_Data*(N_Calc)+Index]=arr_Quant[2*i-1];//Значение сплита

      if(arr_Quant[2*i]>arr_Quant[2*(i-1)])//Новый сплит
      {
         arr_Quant_Trans[Index]=(float)N_Calc;//Число сплитов в предикторе / столбца
         if(New_Size<N_Calc)
         {
            New_Size=N_Calc;
         }
         N_Calc=1;
      }
      else
         N_Calc++;
      if(i+1==Strok_Total_Quant)//Если последний индекс столбца, то сохраним число сплитов в предикторе / столбца
      {
         Index=(int)arr_Quant[2*i];
         arr_Quant_Trans[Index]=(float)N_Calc;//Число сплитов в предикторе / столбце
         arr_Quant_Trans[Stolb_Total_Data*(N_Calc)+Index]=arr_Quant[2*i+1];//Значение сплита -1 так как это последнее значение, а счетчик N_Calc ранее по коду учел новое
      }
   }


   ushort arr_Data_Q[];//Таблица №3 с результатами классификации(квантования) выборки.
   ArrayResize(arr_Data_Q,Strok_Total_Data*Stolb_Total_Data);
   ArrayInitialize(arr_Data_Q,0);

   float arr_Proc_Target[];//Процент принадлежности классов к целевой
   float arr_Proc_Otklik[];//Процент откликов классов ко всей таблице (выборке).
   ArrayResize(arr_Proc_Target,((Max_N+1)*Stolb_Total_Data)*2);//Делаем по размеру квантовой таблицы, умноженной на число разных значений (типов) целевых
   ArrayResize(arr_Proc_Otklik,((Max_N+1)*Stolb_Total_Data));//Делаем по размеру квантовой таблицы
   ArrayInitialize(arr_Proc_Target,0);
   ArrayInitialize(arr_Proc_Otklik,0);

   int arr_N_Class_Target[];//Считаем число целевых по их типам для каждого условного класса после квантования
   int arr_N_Class_Otklik[];//Считаем число откликов для каждого условного класса после квантования в выборке

   ArrayResize(arr_N_Class_Target,(Max_N+1)*2);//Умножаем на количество разных целевых ("0" и "1")
   ArrayResize(arr_N_Class_Otklik,(Max_N+1)*2);

   ArrayInitialize(arr_N_Class_Target,0);
   ArrayInitialize(arr_N_Class_Otklik,0);

   int index_kernel=0;
   int index_kernel_array_fill=1;
   int Handle_Context=0;
//---Инициализация файла с кернелами
   Print("Initialize=",m_OpenCL.Initialize(cl_tester,true));
   //CLProgramCreate(Handle_Context,cl_tester);
//--- установка количества кернелов
   Print("SetKernelsCount=",m_OpenCL.SetKernelsCount(2));
//--- создание кернелов
   Print("KernelCreate=",m_OpenCL.KernelCreate(index_kernel,"CalcPred"));
   Print("KernelCreate=",m_OpenCL.KernelCreate(index_kernel_array_fill,"array_fill"));
//--- создание буферов - указать количество буферов
   Print("SetBuffersCount=",m_OpenCL.SetBuffersCount(6));
//--- копирование буфера на видеокарту
   Print("BufferFromArray=",m_OpenCL.BufferFromArray(0,arr_Data,0,Stolb_Total_Data*Strok_Total_Data,CL_MEM_READ_ONLY));
   Print("BufferFromArray=",m_OpenCL.BufferFromArray(1,arr_Quant_Trans,0,Size_arr_Quant_Trans,CL_MEM_READ_ONLY));
   Print("BufferFromArray=",m_OpenCL.BufferFromArray(2,arr_Target,0,Strok_Total_Data,CL_MEM_READ_ONLY));
   Print("BufferFromArray=",m_OpenCL.BufferFromArray(3,arr_Data_Q,0,Stolb_Total_Data*Strok_Total_Data,CL_MEM_READ_WRITE));
   Print("BufferFromArray=",m_OpenCL.BufferFromArray(4,arr_N_Class_Target,0,(Max_N+1)*2,CL_MEM_READ_WRITE));
   Print("BufferFromArray=",m_OpenCL.BufferFromArray(5,arr_N_Class_Otklik,0,Max_N+1,CL_MEM_READ_WRITE));
//---привязка буфера к аргументу кернела CalcPred
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel,0,0));
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel,1,1));
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel,2,2));
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel,3,3));
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel,4,4));
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel,5,5));
//---привязка параметра фукнкции к кернелу CalcPred
   int p=0;
   Print("SetArgument=",m_OpenCL.SetArgument(index_kernel,6,p));
   Print("SetArgument=",m_OpenCL.SetArgument(index_kernel,7,Stolb_Total_Data));

//---привязка буфера к аргументу кернела index_kernel_array_fill
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel_array_fill,0,4));
   Print("SetArgumentBuffer=",m_OpenCL.SetArgumentBuffer(index_kernel_array_fill,1,5));
//---привязка параметра фукнкции к кернелу index_kernel_array_fill
   int ZeroInint=0;
   Print("SetArgument=",m_OpenCL.SetArgument(index_kernel_array_fill,2,ZeroInint));

//--- пространство задач для кернела index_kernel - одномерное CalcPred
   uint global_work_size[1];
//--- 1-е измерение
   global_work_size[0]=Strok_Total_Data;

//--- пространство задач для кернела index_kernel_array_fill
//--- 1-е измерение
   uint global_work_size_02[1];
   global_work_size_02[0]=(Max_N+1)*2;

//--- начальное смещение в пространстве задач для обоих измерений равно нулю
   uint global_work_offset[1]= {0};
   ulong mcs=GetMicrosecondCount();
   for(/*int*/ p=0; p<Stolb_Total_Data; p++)
   {
         m_OpenCL.SetArgument(index_kernel,6,p);//Передаем значение переменной "p" на видеокарту
         m_OpenCL.Execute(index_kernel,1,global_work_offset,global_work_size);//Запускаем в работу основной воркер
         m_OpenCL.BufferRead(4,arr_N_Class_Target,0,0,(Max_N+1)*2);//Читаем буфер/массив с видеокарты arr_N_Class_Target
         m_OpenCL.BufferRead(5,arr_N_Class_Otklik,0,0,Max_N+1);//Читаем буфер/массив с видеокарты arr_N_Class_Otklik

      for(ushort q=0; q<arr_Quant_Trans[p]+1; q++)//Посчитаем проценты
      {
         int Summ=arr_N_Class_Target[2*q]+arr_N_Class_Target[2*q+1];
         if (Summ>0)
         {
            arr_Proc_Target[Stolb_Total_Data*2*q+p*2]=float((double)arr_N_Class_Target[2*q]/(double)Summ*100.0);//Целевая "0"
            arr_Proc_Target[Stolb_Total_Data*2*q+p*2+1]=float((double)arr_N_Class_Target[2*q+1]/(double)Summ*100.0);//Целевая "1"
         }
         arr_Proc_Otklik[Stolb_Total_Data*q+p]=float((double)arr_N_Class_Otklik[q]/(double)Strok_Total_Data*100.0);
      }
      m_OpenCL.Execute(index_kernel_array_fill,1,global_work_offset,global_work_size_02);//Обнулим буферы/массивы arr_N_Class_Otklik и arr_N_Class_Target
   }
   Print("Время вычислений основного цикла=",(GetMicrosecondCount()-mcs)/1000.0);
   Print("BufferRead=",m_OpenCL.BufferRead(3,arr_Data_Q,0,0,Stolb_Total_Data*Strok_Total_Data));
   Print("Задача №1 Таблица №3 с результатами классификации выборки.");
   ArrayPrint(arr_Data_Q);
   Print("Таблица №5 с результатами вычислений процента принадлежности классов к целевой.");
   ArrayPrint(arr_Proc_Target);
   Print("Таблица №6 с  результатами вычислений процента откликов классов ко всей таблице (выборке).");
   ArrayPrint(arr_Proc_Otklik);

   m_OpenCL.Shutdown();
}
//+------------------------------------------------------------------+
//|Определяем комбинацию случайным образом
//+------------------------------------------------------------------+
float RandomFloat(float max_vl)
{
   return (float)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);  //случайное Int от 0 до  1073741824
}

Сами кернелы

//+------------------------------------------------------------------+
//|                                                        tester.cl |
//|                                  Copyright 2018, Serhii Shevchuk |
//|                           https://www.mql5.com/ru/users/decanium |
//+------------------------------------------------------------------+
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable
#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable

//+------------------------------------------------------------------+
//| Расчет
//+------------------------------------------------------------------+

__kernel void CalcPred(
   __global float *arr_Data,
   __global float *arr_Quant_Trans,
   __global char *arr_Target,
   __global ushort *arr_Data_Q,
//   __global ushort *arr_N_Class_Target,
//   __global ushort *arr_N_Class_Otklik,
   __global int *arr_N_Class_Target,
   __global int *arr_N_Class_Otklik,

    int p,
    int Stolb_Total_Data
 )
  {
   int Index_Data=0;//Индекс массива arr_Data и arr_Data_Q
   int Index_Quant_A=0;//Индекс массива arr_Quant_Trans для границы А
   int Index_Quant_B=0;//Индекс массива arr_Quant_Trans для границы Б
   int Index=0;
   int Calc_Index=0;   
//--- работает в одном измерении    
   size_t i=get_global_id(0);

         Index_Data=Stolb_Total_Data*i+p;
         for(ushort q=0; q<arr_Quant_Trans[p]+1; q++)
         {
            Index=q;
            if(arr_Quant_Trans[p]<1)
            {
               arr_Data_Q[Index_Data]=0;//Обнуляем значение предиктора, так как нет информации о сплитах
               break;
            }
            else
            {
               if(q==0)//Первый сплит
               {
                  Index_Quant_A=Stolb_Total_Data*(q+1)+p;//Рассчитаем индекс первой границы
                  if(arr_Data[Index_Data]<=arr_Quant_Trans[Index_Quant_A])
                  {
                     arr_Data_Q[Index_Data]=q+1;
                     break;
                  }
               }
               else
               {
                  Index_Quant_A=Stolb_Total_Data*(q+1-1)+p;//Рассчитаем индекс первой границы
                  Index_Quant_B=Stolb_Total_Data*(q+1)+p;//Рассчитаем индекс последней границы
                  if(q==arr_Quant_Trans[p])//Последний сплит "q" будет равно arr_Quant_Trans[p] при выходе за пределы массива)
                  {
                     if(arr_Data[Index_Data]>arr_Quant_Trans[Index_Quant_A])
                     {
                        arr_Data_Q[Index_Data]=q+1;
                        break;

                     }
                  }
                  else//Средние сплиты
                  {
                     if(arr_Data[Index_Data]>arr_Quant_Trans[Index_Quant_A] && arr_Data[Index_Data]<=arr_Quant_Trans[Index_Quant_B])
                     {
                        arr_Data_Q[Index_Data]=q+1;
                        break;
                     }
                  }
               }
            }
         }            
         switch(arr_Target[i])
         {
         case 0:
            Calc_Index=Index*2;
            break;
         case 1:
            Calc_Index=Index*2+1;
            break;
         }
         atomic_inc(&arr_N_Class_Target[Calc_Index]);//Прибавим 1 для подсчета целевой
         Calc_Index=Index;//Индекс для массива arr_N_Class_Otklik
         atomic_inc(&arr_N_Class_Otklik[Calc_Index]);//Прибавим 1 для подсчета откликов
  }
//+------------------------------------------------------------------+
//| Заполнение буфера указанным значением                            |
//+------------------------------------------------------------------+
__kernel void array_fill(__global int *Buf_A,__global int *Buf_B,const int value)
  {
//--- работает в одном измерении    
   size_t x=get_global_id(0);
   Buf_A[x]=value;
   Buf_B[x]=value;
  }
 

По идее, матрицы появились как метод решения систем линейных уравнений с многими переменными. 

Соответственно, на мой взгляд, главное направление использования матриц - это задачи, предусматривающие такие расчёты. 

Классический пример - Метод Наименьших Квадратов. 

Вот, я когда-то делал индикатор:


 
Georgiy Merts #:

По идее, матрицы появились как метод решения систем линейных уравнений с многими переменными. 

Соответственно, на мой взгляд, главное направление использования матриц - это задачи, предусматривающие такие расчёты. 

Классический пример - Метод Наименьших Квадратов. 

Вот, я когда-то делал индикатор:



Хорошо бы обсуждать код, какие то примеры...

Сейчас к матрицам надо относится как к динамичному двухмерному массиву - и тут применение уже шире, чем математический прок от матриц.

 
Aleksey Vyazmikin #:

Хорошо бы обсуждать код, какие то примеры...

Сейчас к матрицам надо относится как к динамичному двухмерному массиву - и тут применение уже шире, чем математический прок от матриц.

Ну, у меня этот код был сделан с применением самописного класса матрицы. Тебе это разве интересно? 

Вот, например, включаемый файл класса ядра метода МНК (mqh  и mq5 файлы приложу ниже, они используют мою общую библиотеку, и для применения их надо будет подкорректировать, но основную мысль из них можно увидеть и так) - решается вопрос аппроксимации от нулевой до третьей степени. Перегружаем виртуальные функции, дающие пары (x;y) и число таких пар, и получаем готовый класс для аппроксимации. Именно с помощью этого класса были нарисованы границы параболического и кубического каналов в картинке выше:

/*
CLSMCore - класс, осуществляющий метод наименьших квадратов. Ядро.
Для использования - необходимо пронаследовать свой класс от ядра и перегрузить чисто виртуальные функции.
*/

#include <MyLib\DebugOrRelease\DebugSupport.mqh>
#include <MyLib\Common\TrendEnums.mqh>

struct SLSMPowers
{
   double   m_dThirdPower;
   double   m_dSecondPower;
   double   m_dFirstPower;
   double   m_dNullPower;
};

enum EQntExtremums
{
   QE_NO_EXTREMUMS = 0,
   QE_MAXIMUM = 1,
   QE_MINIMUM = 2,
   QE_BOTH = 3
};

struct SLSMExtremums
{
   EQntExtremums  m_qeExtremums;
   double         m_dMinX;
   double         m_dMinY; 
   double         m_dMaxX;
   double         m_dMaxY; 
};


class CLSMCore
{
public:
// Степени многочленов
static const uint    LSM_FLAT_POWER;
static const uint    LSM_TREND_POWER;
static const uint    LSM_PARABOLIC_POWER;
static const uint    LSM_CUBIC_POWER;

static const double  LSM_DEFAULT_POINT_WEIGHT;  // Вес точки по умолчанию

protected:

   
   // Функции, которые обязательно следует перегрузить
   // Именно эти функции возвращают число точек и их координаты.
   virtual uint   _N() = 0;      // Число точек
   virtual double _X(uint uiIdx) = 0;  // Значение X точки с индексом uiIdx
   virtual double _Y(uint uiIdx) =0;  // Значение Y точки с индексом uiIdx
   
   // Функци, которые можно не перегружать, если необходимо значение по умолчанию.
   // Это функции для указания веса и полярной точки.
   virtual double _W(uint uiIdx) { return(LSM_DEFAULT_POINT_WEIGHT); };  // Значение веса точки с индексом uiIdx
   virtual int    _PolarIdx()    { return(WRONG_VALUE); }            // Индекс точки, через которую должна проходить прямая, при отрицательном значении - такой точки нет.     

   // Функция, проверяющаяя, что МНК указанного типа возможен
   // (Количество точек ненулевого веса должно быть на один больше, чем степень многочлена)
   virtual bool _LSMIsAvailible(ELSMType ltType);

   // Расчетные функции.
   // Во всех случаях учитываются веса точек Wi и отнимается полярная точка (Xpol,Ypol), если ее индекс валиден,
   // обозначается "с" - корректированное
   virtual double _SummXc();     // Summ((Xi-Xpol)*Wi)
   virtual double _SummXc2();    // Summ((Xi-Xpol)^2*Wi)
   virtual double _SummXc3();    // Summ((Xi-Xpol)^3*Wi)
   virtual double _SummXc4();    // Summ((Xi-Xpol)^4*Wi)
   virtual double _SummXc5();    // Summ((Xi-Xpol)^5*Wi)
   virtual double _SummXc6();    // Summ((Xi-Xpol)^6*Wi)
   virtual double _SummX2c2();   // Summ((Xi^2-Xpol^2)^2*Wi)  
   virtual double _SummX3c2();   // Summ((Xi^3-Xpol^3)^2*Wi)
   virtual double _SummXcYc();   // Summ((Xi-Xpol)*(Yi-Ypol)*Wi)
   virtual double _SummX2cXc();  // Summ((Xi^2-Xpol^2)*(Xi-Xpol)*Wi)  - 
   virtual double _SummX2cYc();  // Summ((Xi^2-Xpol^2)*(Yi-Ypol)*Wi)
//   virtual double _SummXcX2c();  // Summ((Xi-Xpol)*(Xi^2-Xpol^2)*Wi)  - оказывается, это одна и та же функция
   virtual double _SummX3cX2c(); // Summ((Xi^3-Xpol^3)*(Xi^2-Xpol^2)*Wi)   
   virtual double _SummX3cXc();  // Summ((Xi^3-Xpol^3)*(Xi-Xpol)*Wi)   
   virtual double _SummX3cYc();  // Summ((Xi^3-Xpol^3)*(Yi-Ypol)*Wi)   
   virtual double _SummYc();     // Summ((Yi-Ypol)*Wi)
   virtual double _SummW();      // Summ(Wi)


   // Функциии расчета для аппроксимированных значений.
   // Функции возвращают коэффициенты определенных кривых. 
   // Последняя функция возвращает сразу все коэффициенты в структуре, ее чаще всего и имеет смысл использовать.
   // Функции вынесены в protected-секцию, чтобы можно было организовать различные способы доступа к данным
   // Для расчетов используются перегруженные функции: _N(); _X(); _Y(); _W(); _PolarIdx().


   // Функция расчета горизонтальной прямой (по сути среднего арифметического)
   double _CountFlatLevel();         

   // Функция расчета тренда для случая, когда есть точка-полюс, через которую должна лежать прямая
   // Предполагается, что _PolarIdx() != WRONG_VALUE (проверка по ASSERT)
   double _CountPolarTrend(double & rdPolarLevel);    
   
   // Функция расчета обычной прямой c трендом
   // Предполагается, что _PolarIdx() == WRONG_VALUE (проверка по ASSERT)
   double _CountTrend(double & rdLevel);   
   
   // Функция расчета параболы для случая, когда есть точка полюс, через которую парабола должна проходить.
   // Заполняет соответствующие коэффициенты
   // Предполагается, что _PolarIdx() != WRONG_VALUE (проверка по ASSERT)
   void _CountPolarParabola(double & rdSecondPower,double & rdFirstPower,double & rdNullPower);    

   // Функция расчета параболы.
   // Заполняет соответствующие коэффициенты
   // Предполагается, что _PolarIdx() == WRONG_VALUE (проверка по ASSERT)
   void _CountParabola(double & rdSecondPower,double & rdFirstPower,double & rdNullPower);    


   // Функция расчета кубической параболы для случая, когда есть точка полюс, через которую парабола должна проходить.
   // Заполняет соответствующие коэффициенты
   // Предполагается, что _PolarIdx() != WRONG_VALUE (проверка по ASSERT)
   void _CountPolarCubic(double & rdThirdPower,double & rdSecondPower,double & rdFirstPower,double & rdNullPower);

   // Функция расчета кубической параболы.
   // Заполняет соответствующие коэффициенты
   // Предполагается, что _PolarIdx() == WRONG_VALUE (проверка по ASSERT)
   void _CountCubic(double & rdThirdPower,double & rdSecondPower,double & rdFirstPower,double & rdNullPower);

   // Функция расчета указанной кривой.
   // Заполняет соответствующие коэффициенты (несуществующие коэффициента заполняются нулями
   // В зависимости от величины, возвращаемой _PolarIdx(), вызываются полярные или обычные функции
   SLSMPowers _CountLSM(ELSMType ltType);

   // Функция возвращает параболическую кривую, построенную по трем первым точкам массивов с координатами.
   static SLSMPowers _GetParabolicCurvePyPoints(double & dArrX[],double & dArrY[]);

   // Функция возвращает кубическую кривую, построенную по четырем первым точкам массивов с координатами.
   static SLSMPowers _GetCubicCurvePyPoints(double & dArrX[],double & dArrY[]);

   static void _TraceDouble(string strName,double dValue,int iDoubleDigits); 
      
public:
   CLSMCore() {};
   ~CLSMCore() {};

   // Заполнение данной структуры одинаковыми значениями степеней.
   static void SetPowers(SLSMPowers & lpPowers,double dPower) { lpPowers.m_dNullPower = dPower; lpPowers.m_dFirstPower = dPower; lpPowers.m_dSecondPower = dPower; lpPowers.m_dThirdPower = dPower; };
   
   // Расчет многочлена с данными степенями и аргументом.   
   static double CountLSMPolynom(double dX,SLSMPowers & lpPowers) { return(dX*(dX*(dX*lpPowers.m_dThirdPower + lpPowers.m_dSecondPower)+lpPowers.m_dFirstPower)+lpPowers.m_dNullPower); };
   
   // Расчет производной порядка uiDerivativeStep для аргумента dX и коэффициентов lpPowers
   static double CountDerivative(double dX,SLSMPowers & lpPowers,uint uiDerivativeStep = 1);
   
   // Расчет числа экстремумов для указанных степеней и, если они есть - заполняет их значения.
   // Возвращает структуру количеством экстремумов и их данными.
   // В структуре данных заполняется:
   // Для флета - в обоих экстремумах устанавливается Y, абсцисса у обоих устанавливается на EMPTY_VALUE
   // Для тренда - все значения устанавливаются на EMPTY_VALUE
   // Для параболы - существующий экстремум устанавливается на реальный экстремум, несуществующий на EMPTY_VALUE
   // Для кубики - устанавливаются оба экстремума (если они есть), либо все устанавливается на EMPTY_VALUE (если экстремумов нет).
   static SLSMExtremums GetExtremums(SLSMPowers & lpPowers);   
   
   // Функция возвращает степени уравнения, проходящие через минимальное число точек (в зависимости от ltEqPower):
   // Количество точек должно быть достаточным, исследуются только первые необходимые. 
   static SLSMPowers GetCurvePyPoints(double & dArrX[],double & dArrY[], ELSMType ltEqPower);
   
   // Функция предназначена для трассировки указанного полинома от dX1 до dX2 числом промежуточных шагов uiMidSteps 
   // Значения коэффициентов полинома преобразуются функцией DoubleToString() c параметром 16
   // Для значений точек полинома используются параметры iXDoubleDitits и iYDoubleDigits
   static void TracePolynom(SLSMPowers & lpPowers,double dX1,double dX2,uint uiMidSteps,int iXDoubleDitits,int iYDoubleDigits);
   
   // Функция предначена для нахождения блока uiBlockSize точек в массиве adArray, ближайших к значению dValue.
   // Возвращает индекс минимального индекса в блоке. 
   // Предназначена для аппроксимации.
   // Если у нас есть массив adArray[], и нужно найти несколько точек, ближайших к данной, 
   // чтобы провести через них аппроксимирующую кривую, то вызываем эту функцию, и она находит первый (минимальный) индекс такого блока. 
   // Предполагается, что uiBlockSize не больше размера массива. Если это так - возвращается UINT_MAX (внутри ASSERT) 
   static uint GetBestIdx4Approx(double dValue,double & adArray[],uint uiBlockSize);
   
   // Статические функции для матричных вычислений

   // Функция вычисляет детерминант матрицы размера 3х3.
   // Значения передаются по строкам.
   static double Determinant_3(double dX11,double dX12,double dX13,double dX21,double dX22,double dX23,double dX31,double dX32,double dX33) { return(dX11*dX22*dX33 - dX11*dX23*dX32 - dX12*dX21*dX33 + dX12*dX23*dX31 + dX13*dX21*dX32 - dX13*dX22*dX31);};
       
   // Функция вычисляет детерминант матрицы размера 4х4.
   // Значения передаются по строкам.
   static double Determinant_4(double dX11,double dX12,double dX13,double dX14,double dX21,double dX22,double dX23,double dX24,double dX31,double dX32,double dX33,double dX34,double dX41,double dX42,double dX43,double dX44);

   

   // Функция использует предыдущую, выбирая размер блока для соответствующего типа аппроксимации.
   static uint GetBestIdx4Approx(double dValue,double & adArray[],ELSMType ltType);
};

Файлы:
LSMCore.mqh  20 kb
LSMCore.mq5  54 kb
 
Georgiy Merts #:

Ну, у меня этот код был сделан с применением самописного класса матрицы. Тебе это разве интересно? 

Интересно увидеть код с матрицами нового формата в сравнении со старым. Оценить прирост производительности. Да и код должен тогда значительно лучше восприниматься по идеи.

Причина обращения: