В сложных вычислительных задачах (или просто при нежелании программировать на Lua, Cpp и т.д., а пользоваться более высокоуровневыми инструментами разработки), незаменимым оказывается API интерфейс Матлаба реализованный в качестве Active-X COM Automation Server. Для его реализации на языке Си существует специальная библиотека
libe
ng.lib, позволяющая языкам Си, С++, Фортран обмениваться данными и пользоваться всеми ресурсами Матлаба (обычно это обработка видео, автопилоты, ИИ, нейронные сети и т.п.).
Поэтому, в качестве изучения возможностей, попробуем реализовать простейший проект обмена данными и вызова функций Матлаб со стороны Си++ при использовании CodeBlocks и MinGW64.
Чтобы адресовать все внешние процессы к единому процессу Матлаб, а не запускать Engine для каждого процесса в отдельности,
запустим «двигатель» матлаба внутренней командой :
server=actxserver('matlab.application.single'); server.Execute(' enableservice (''AutomationServer'', true)');
В этом случае используемые в Cи++ функции engOpen() будут получать указатель на уже существующий интерфейс, а не открывать новый.
- Подключение необходимых библиотек и получение указателя интерфейса
Необходимый минимум :
1. Библиотека libeng.lib, отвечающая за управление интерфейсом Matlab (
matlabroot)/extern/lib/win64/microsoft
2. Библиотека libmx.lib, отвечающая за конвертацию данных Matlab — Cpp (
matlabroot)/extern/lib/win64/microsoft
3. Файл заголовок engine.h, описывающий доступные пользователю функции. (
matlabroot)/extern/include/win64/microsoft
Указатель интерфейса получается вызовом функции ep=engOpen(NULL), с единственно допустимым параметром для Win OS — NULL.
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include "engine.h"
int PASCAL WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
// ПОДКЛЮЧЕНИЕ К СЕРВЕРУ МАТЛАБ(!)
printf("%s","Connect to exist Matlab Engine ...");
Engine *ep; // Start the MATLAB engine
if (!(ep = engOpen(NULL))){
MessageBox ((HWND)NULL, (LPSTR)"Can't start MATLAB engine",
(LPSTR) "Engwindemo.c", MB_OK);
exit(-1);
}
printf("%s"," Ok. \n");
printf("%s","\n");
- Передача в Матлаб массива типа Double float,2p
// ЗАПИСЬ ДВУМЕРНОГО МАССИВА типа DOUBLE
int row=2,col=3;
double DARR[row][col]={0.1,0.2,0.3,0.4,0.5,0.6}; // Массив СИ++
mxArray *OutArr=mxCreateDoubleMatrix(2,3,mxREAL); // Создаем массив OUT
memcpy((char *) mxGetPr(OutArr), (char *) DARR, row*col*sizeof(double)); // Копируем массив DARR в OUT
engPutVariable(ep, "DoubleArrayFromCpp", OutArr); // Отправляем массив в матлаб
printf("%s","Double Array Send to Matlab Engine \n");
printf("%s","\n");
printf("%s","\n");
mxDestroyArray(OutArr); //очищаем массив
getch();
Для того чтобы передать заданный массив размером 2х3 в Матлаб нам необходимо сначала создать некоторый матлаб-совместимый объект mxArray, указатель на который возвращает функция:
*mxCreateDoubleMatrix( число строк, число столбцов, флаг комплексного числа)
После чего, созданный объект заполняется при помощи функции:
memcpy( память назначения (первый элемент mxArray), память источник (массив Cи++), объем копирования памяти в байтах)
Полученный таким образом массив передается в Матлаб по стандартной процедуре:
engPutVariable( указатель процесса Матлаб, имя переменной в процессе Матлаб, передаваемая переменная из Си++)
- Чтение ранее переданного Double float,2p массива из Матлаб
// Чтение ДВУМЕРНОГО МАССИВА типа DOUBLE
mxArray *InDArr=engGetVariable(ep, "DoubleArrayFromCpp"); // Получаем указатель на считанный массив
int rowi= mxGetM(InDArr); // Считаем число строк
int coli=mxGetN(InDArr); // Считаем число столбцов
double InArr[rowi][coli]; //Создаём клон массива в Си++
memcpy(InArr, mxGetPr(InDArr) ,rowi*coli*sizeof(double) ); // Заполняем клон-массив
printf(" Double Array Loaded from Matlab, num rows %d", rowi);
printf("\n Double Array Loaded from Matlab, num columns %d", coli);
printf("%s","\n");
printf("\n Double Array Loaded from Matlab, first element %f", InArr[0][0]);
printf("\n Double Array Loaded from Matlab, last element %f", InArr[rowi-1][coli-1]);
printf("%s","\n");
printf("%s","\n");
mxDestroyArray(InDArr); //очищаем массив
getch();
Чтение происходит аналогично, но в обратной последовательности.
- Исполнение заданной Си++ функции в среде Матлаб
// ВЫЗОВ ФУНКЦИИ в MATЛАБ ( и, одновременно, создание 2x2 Cell массива)
char func[100] = "CellArray={'Smart-Lab','Kot-Begemot';'Blog','Cpp-MatlabEngine'}";
engEvalString(ep,func);
Функция для исполнения Матлаб задается строкой (массив char) и в данном случае представляет собой создание и заполнение 2х2 массива ячеек (Cell Array) строковыми переменными.
После того, как функция задана строкой, она исполняется командой:
engEvalString(указатель процесса Матлаб, команда матлаб заданная строкой)
- Чтение массива ячеек из матлаб в цикле
// Чтения массива строк (Cell Array)
mxArray *InCArr=engGetVariable(ep, "CellArray"); // Получаем указатель на считанный массив
int rowc= mxGetM(InCArr); // Считаем число строк
int colc=mxGetN(InCArr); // Считаем число столбцов
printf("\n Cell Array Loaded from Matlab, num rows %d", rowc);
printf("\n Cell Array Loaded from Matlab, num columns %d", colc);
printf("%s","\n");
char *CArr[rowc][colc];
int i,j;
for (i=0;i<rowc;i++)
{
for (j=0;j<colc;j++)
{
CArr[i][j]=mxArrayToString(mxGetCell(InCArr,i*colc+j));
printf("\n Cell Array Loaded from Matlab element %d %s\n", i*colc+j, CArr[i][j] );
}
}
mxDestroyArray(InCArr); //очищаем массив
getch();
Чтение массива ячеек аналогично чтению массива double за исключением того, что читать нам его приходится поэлементно в цикле, получая строки из ячеек при помощи функции :
строка из ячейки = mxArrayToString( указатель ячейки)
и
указатель ячейки = mxGetCell( указатель массива, указатель порядкового номера ячейки от 0 до последнего элемента массива)
* В ячейке Cell Array может содержаться не только строка, но и многомерный массив Double, и даже другой Cell Array, в ячейках которого содержаться иные массивы. В данном случае, предполагается использование только простых массивов строк.
int engOutputBuffer(Engine *ep, char *buffer, int buflen); — захват выходного буфера процесса Матлаб
int engSetVisible(Engine *ep, bool newVal); — изменение видимости окна процесса Матлаб
int engClose(Engine *ep); — закрытие указанного процесса Матлаб
Результаты работы программы:
Предложения и критика приветствуются.
Торгуйте алгоритмами.
С уважением, Кот-Бегемот.
Но мне для внешнего управления больше нужно, чем для скорости.
можешь как-то более подробно описать свою задачу, где ты увидел решение в виде вызова функций matlab? или этот пост никак не связан с твоей задачей?
Матлаб, я так понимаю, уже на фиг никому не нужен.
Сейчас готовлю материал по обмену Lua c Python. Хотя я о такой простой возможности обмена Луа со всем и вся уже писал, народ не внемлет.) Попробую еще раз.)
имеется ввиду dll на Cpp?
Обычный обмен файлами CSV или JSON. Эт по желанию. Простенько, со вкусом и простейшими средствами. Сам тоже иногда применял.
Хочу показать, что скорости вполне и для всего хватает. Но людям ведь нужен реактивный самолет, им каждая мс дорога.))
Но CSV, конечно, хватит даже далеко не среднему юзеру.
Скорость там минимум ~1МБ/с и больше. Куда больше то? Кто чего не успеет?
Подождите неск дней. На днях тест программу сделаю, чтобы конкретные цифры были.
А у меня, можно считать, прямой доступ. Это удобно, красиво, надёжно, без доп нагрузки на ХДД и еще +100500 плюсов.
С JSON работайте, и все преобразования на автомате будут. Ну, почти.)
Ладно, напишу, сами увидите. Но главное — простота реализации и скорость достаточная для всего.
Безусловно, программистам это не интересно.) Они и сами все умеют.
Матлаб, Борланд?(С++) что то еще. Слышал можно тупа купить виртуальную машину, где всё уже будет установлено. Так то схема понятна, есть данные(в чем то) фундаментальные, технические, цены. С ними как то работаем(исследуем) с помощью АPI функций Матлаба, на базе С++(программы).
Список программ?
Я такую же штуку делал на С диез.
А тем кто спрашивает зачем все это?
Можно ответить, что в результате мы получаем:
Полнофункциональный язык программирования + мощный MathProcessor
с большим кол-вом toolbox-ов, например:
CurveFitting,
Econometric,
FilterDesign,
Financial,
Fuzzy,
ImageProccess,
Neural,
Statistics
etc
+ Прекрасная документация
Разве этого мало?
А Вы сами какую архитектуру в своих разработках для торговли используете? И на каких языках написаны функциональные модули в Вашей системе?
Вот автор использует С++ и Matlab. Я считаю это неплохой вариант. Не идеальный, конечно, но вполне рабочий.
А что используете Вы? Поделитесь, пожалуйста.
Спасибо за Ваш ответ. Интересно.
Теперь понятен Ваш подход. Похож на классический и правильный, но несколько несовременный на мой взгляд.
В настоящее время в результате эволюции софтверных архитектур фокусировка на конкретных языках исчезает.
В настоящее время Приложения среднего уровня и, тем более приложения уровня Enterprise, проектируются в виде множества микро-сервисов с «шиной данными» между ними.
В результате для реализации конкретного микро-сервиса разработчик выбирает наиболее подходящий для этого язык программирования и реализуют его наиболее оптимальным образом.
Взаимодействие между сервисами происходит по «шине данных».
Конкретный сервис инициализируется и подписывается на получение необходимых данных через Контроллер шины данных. То есть, сказал в коде new, а потом subscribe. И все. Данные прилетают сами. Используются Push-технологии. И никто уже не думает, что из чего вызывать и не циклится на этом.
Причем такая архитектура одинаково хорошо работает и для Intranet-сетей и для Internet, ну а для Desktop тем более.
Даже Moex, к моему большому удивлению, начала иcпользовать Push-технологии.
А дискуссии что из чего вызывать уже не актуальны.