Я хотел бы знать, как обмениваться данными между Mathematica и C / C ++ с каналами. В учебнике Mathematica говорится, что «когда вы открываете файл или канал, Mathematica создает« объект потока », который указывает открытый поток, связанный с файлом или каналом».
Я знаю, как создавать файлы в C и Mathematica , и я могу заставить каждую программу читать и записывать их. То, что я до сих пор не знаю, как это сделать, это как отправить вывод из C через канал в другую программу, а тем более как это сделать из Mathematica.
Вот функция, в которой Mathematica записывает матрицу в двоичный файл, а также читает файл, записанный в этом формате.
writeDoubleMatrix[obj_, fileName_] := Module[{file},
file = OpenWrite[fileName, BinaryFormat -> True];
BinaryWrite[file, Length@obj, "Integer32"];
BinaryWrite[file, Length@obj[[1]], "Integer32"];
BinaryWrite[file, Flatten[obj], "Real64"];
Close[file]
]
readDoubleMatrix[fileName_] := Module[{file, obj, m, n},
file = OpenRead[fileName, BinaryFormat -> True];
m = BinaryRead[file, "Integer32"];
n = BinaryRead[file, "Integer32"];
obj = BinaryReadList[file, "Real64", m*n];
Close[file];
Partition[obj, n]
]
Первая функция запишет в файл 2 целых числа (размер матрицы) и данные матрицы. Я не делаю никакой проверки ошибок здесь, и поэтому я предполагаю, что данные
быть написано конкретно в виде {{r11, r12, ..., r1n}, ...., {rm1, rm2, ..., rmn}}
. Вторая функция сможет читать двоичный файл и возвращать матрицу.
Далее идет моя программа на Си. Эта программа будет считывать данные, хранящиеся в файле MathematicaData.bin, умножать эту матрицу на 2 и записывать данные в другой файл.
// genData.c
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv){
int m, n, i;
double* matrix;
FILE* fin;
FILE* fout;
// Reading input file
fin = fopen(argv[1], "rb");
fread(&m, sizeof(int), 1, fin);
fread(&n, sizeof(int), 1, fin);
matrix = (double*)malloc(m*n*sizeof(double));
fread(matrix, sizeof(double), m*n, fin);
fclose(fin);
//Modifying data
for (i = 0; i < m*n; ++i) matrix[i] = 2*matrix[i];
// Writing output file
fout = fopen(argv[2], "wb");
fwrite(&m, sizeof(int), 1, fout);
fwrite(&n, sizeof(int), 1, fout);
fwrite(matrix, sizeof(double), m*n, fout);
fclose(fout);
// De-allocate memory used for matrix.
free(matrix);
return 0;
}
Эта программа не имеет проверки ошибок. Вы должны быть осторожны, как вы используете его, иначе программа может не обнаружить файлы или даже выделить объем памяти, который вы хотите. В любом случае мы можем скомпилировать программу с вашим компилятором по вашему выбору.
gcc -o genData genData.c
И теперь мы можем попытаться использовать эти функции для связи между двумя языками из Mathematica.
matrix = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
writeDoubleMatrix[matrix, "MathematicaData.bin"];
Run["./genData MathematicaData.bin CData.bin"];
readDoubleMatrix["CData.bin"]
Если все прошло хорошо, вы должны получить
{{2., 4., 6., 8.}, {10., 12., 14., 16.}, {18., 20., 22., 24.}}
Да, это очень трудоемкий способ умножения матрицы на 2, но это всего лишь простой пример, показывающий, как обмениваться данными из Mathematica в C и из C в Mathematica.
Что мне не нравится, так это то, что все сначала сохраняется в файле, а затем читается в другой программе. Может кто-нибудь показать мне, как обмениваться данными без записи файлов. У меня есть ощущение, что мне нужны каналы, но я не знаю, как их читать или писать на любом языке. Было бы полезно, если бы вы могли изменить эту программу, чтобы адаптировать ее к каналам.
UPDATE:
Я узнал, как сделать программу на C "pipeable".
//genDataPipe.c
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv){
int m, n, i;
double* matrix;
// Reading input file
fread(&m, sizeof(int), 1, stdin);
fread(&n, sizeof(int), 1, stdin);
matrix = (double*)malloc(m*n*sizeof(double));
fread(matrix, sizeof(double), m*n, stdin);
//Modifying data
for (i = 0; i < m*n; ++i) matrix[i] = 2*matrix[i];
// Writing output file
fwrite(&m, sizeof(int), 1, stdout);
fwrite(&n, sizeof(int), 1, stdout);
fwrite(matrix, sizeof(double), m*n, stdout);
// Deallocate memory used for matrix.
free(matrix);
return 0;
}
Это означает, что мы должны использовать программу следующим образом:
./genDataPipe < fileIn.bin > fileOut.bin
Я искал в документации на стороне Mathematica , но все, что я понял, - это открыть файл с помощью внешней команды. Возьмите OpenWrite
, например:
В компьютерных системах, которые поддерживают каналы, OpenWrite ["! Command"] запускает внешнюю программу, указанную командой, и открывает канал, чтобы отправить в него входные данные.
Это означает, что я могу передать свой двоичный вход непосредственно в программу c. Проблема в том, что я не могу найти способ перенаправить вывод программы. Я пришел к выводу: записать данные в файл и создать оболочку для запуска внешней команды и чтения содержимого выходных данных внешней команды. Здесь мы предполагаем существование writeDoubleMatrix
от ранее.
getDataPipe[fileName_] := Module[{file, obj, m, n},
file = OpenRead["!./genDataPipe < " <> fileName,
BinaryFormat -> True];
m = BinaryRead[file, "Integer32"];
n = BinaryRead[file, "Integer32"];
obj = BinaryReadList[file, "Real64", m*n];
Close[file];
Partition[obj, n]
]
matrix = {{1, 2, 3}, {4, 5, 6}};
writeDoubleMatrix[matrix, "MData.bin"];
output = getDataPipe["MData.bin"]
В результате получается следующее содержимое {{2., 4., 6.}, {8., 10., 12.}}
.
Единственная цель, которая остается сейчас, - выяснить, как устранить необходимость writeDoubleMatrix
и передать данные напрямую, без необходимости записи файла.