jml*_*pez 7 c wolfram-mathematica
我想知道如何使用管道在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]
]
Run Code Online (Sandbox Code Playgroud)
第一个函数将2个整数写入文件(矩阵的大小)和矩阵的数据.我没有在这里进行任何错误检查,因此我假设要写入的数据是特定的形式{{r11, r12, ..., r1n}, ...., {rm1, rm2, ..., rmn}}.第二个函数将能够读取二进制文件并返回矩阵.
接下来是我的C程序.该程序将读取存储在文件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;
}
Run Code Online (Sandbox Code Playgroud)
该程序没有任何错误检查.您需要小心如何使用它,否则程序可能无法检测文件,甚至无法分配您想要的内存量.无论如何,我们可以使用您选择的编译器编译程序.
gcc -o genData genData.c
Run Code Online (Sandbox Code Playgroud)
现在我们可以尝试使用这些函数在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"]
Run Code Online (Sandbox Code Playgroud)
如果一切顺利,你应该获得的输出是
{{2., 4., 6., 8.}, {10., 12., 14., 16.}, {18., 20., 22., 24.}}
Run Code Online (Sandbox Code Playgroud)
是的,这是一种将矩阵乘以2的非常耗时的方法,但这只是一个简单的例子,展示如何将数据从Mathematica交换到C,从C交换到Mathematica.我不喜欢的是事先将所有内容存储到文件中然后在其他程序中读取.有人可以告诉我如何在不写文件的情况下交换数据.我觉得管道是我需要的,但我不知道如何从两种语言中读取或写入它们.如果您可以修改此程序以使其适应管道,将会很有帮助.
我发现了如何使C程序"可管理".
//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;
}
Run Code Online (Sandbox Code Playgroud)
这意味着我们必须使用这样的程序:
./genDataPipe < fileIn.bin > fileOut.bin
Run Code Online (Sandbox Code Playgroud)
我一直在搜索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"]
Run Code Online (Sandbox Code Playgroud)
这导致输出具有以下内容{{2., 4., 6.}, {8., 10., 12.}}.
现在唯一的目标是找出如何消除需要writeDoubleMatrix并直接传递数据而无需编写文件.
第一步是创建一个命名管道(如上面Artefacto的评论所述).这被称为fifo,先入先出.管道将一个文件的输出转换为另一个文件的输入.我想请注意,这些方法仅在我开始之前就是Linux.
基本上,管道的工作方式如下:
mkfifo mypipe 或在C: system ("mkfifo mypipe");
下一步是将输出写入管道,因为Linux 中的所有内容都是文件,您可以使用标准的i/o操作,甚至将标准输入重定向到管道.你已经在Mathematica和C中都有了代码.因此,在将文件的输出写入管道之后,Mathematica版本可以从管道中读取输入,将其相乘,并在stdout或任何您需要的地方显示.你真的不应该对这个方法有任何问题,因为看到管道在读取后被清空,并且在你完成后可以很容易地删除.如果您想要之后删除管道,只需运行system ("rm myfifo");.
如果你真的不想要任何附件文件,即使它不是那么糟糕,尝试制作另一个实际输出标准输出的文件.然后制作一个让Matematica从标准输入中读取的内容.现在,管道:
./cprogram | ./mprogram
这意味着C程序的输出应该是Mathematica程序的输入.据我所知,这仍然会创建一个管道,但系统会在完成时自动将其删除,而普通的最终用户可能无法看到它.