我知道如何在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]],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}}的形式编写.第二个函数将能够读取二进制文件并返回矩阵.
接下来是我的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,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,fout); fwrite(&n,fout); fwrite(matrix,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.
我不喜欢的是事先将所有内容存储到文件中然后在其他程序中读取.有人可以告诉我如何在不写文件的情况下交换数据.我觉得管道是我需要的,但我不知道如何从两种语言中读取或写入它们.如果您可以修改此程序以使其适应管道,将会很有帮助.
更新:
我发现了如何使C程序“可管理”.
//genDataPipe.c #include <stdlib.h> #include <stdio.h> int main(int argc,i; double* matrix; // Reading input file fread(&m,stdin); fread(&n,stdin); matrix = (double*)malloc(m*n*sizeof(double)); fread(matrix,stdin); //Modifying data for (i = 0; i < m*n; ++i) matrix[i] = 2*matrix[i]; // Writing output file fwrite(&m,stdout); fwrite(&n,stdout); fwrite(matrix,stdout); // Deallocate memory used for matrix. free(matrix); return 0; }
这意味着我们必须使用这样的程序:
./genDataPipe < fileIn.bin > fileOut.bin
我一直在搜索Mathematica方面的文档,但我已经发现我可以通过管道外部命令打开一个文件.以OpenWrite为例:
On computer systems that support pipes,OpenWrite[“!command”] runs the external program specified by command,and opens a pipe to send input to it.
这意味着我可以直接将二进制输入提供给c程序.问题是我找不到重定向程序输出的方法.我想到的是,将数据写入文件并制作包装器以运行外部命令并读取外部命令输出的内容.这里我们假设之前存在writeDoubleMatrix.
getDataPipe[fileName_] := Module[{file,file = OpenRead["!./genDataPipe < " <> fileName,n] ] matrix = {{1,3},{4,5,6}}; writeDoubleMatrix[matrix,"MData.bin"]; output = getDataPipe["MData.bin"]
这导致输出具有以下内容{{2.,6.},{8.,10.,12.}}.
现在唯一的目标是找出如何消除writeDoubleMatrix的需要并直接传递数据而无需编写文件.
解决方法
基本上,管道的工作方式如下:
mkfifo mypipe或在C:system(“mkfifo mypipe”);
下一步是将输出写入管道,因为Linux中的所有内容都是文件,您可以只使用标准的i / o操作,甚至将标准输入重定向到管道.你已经在Mathematica和C中都有了代码.因此,在将文件的输出写入管道之后,Mathematica版本可以从管道中读取输入,将其相乘,并在stdout或任何您喜欢的地方显示.你真的不应该对这个方法有任何问题,因为管道在读取后被清空,并且在你完成后可以很容易地删除.如果你想在之后删除管道,只需运行system(“rm myfifo”);.
如果你真的不想要任何配件文件,即使它不是那么糟糕,尝试制作另一个实际输出标准输出的文件.然后制作一个让Matematica从标准输入中读取的内容.现在,管道:
./cprogram | ./mprogram
这意味着C程序的输出应该是Mathematica程序的输入.据我所知,这仍然会创建一个管道,但系统会在完成时自动将其删除,而普通的最终用户可能无法看到它.