1 
2 
3 #include "Config.hh"
4 #include <boost/python.hpp>
5 #include "Functional.hh"
6 #include "MMACdb.hh"
7 #include "PreClean.hh"
8 #include "Cleanup.hh"
9 #include "Parser.hh"
10 #include "Kernel.hh"
11 #include "DisplayMMA.hh"
12 #include "algorithms/substitute.hh"
13 
14 using namespace cadabra;
15 
16 WSLINK        MMA::lp = 0;
17 WSEnvironment MMA::stdenv = 0;
18 
19 //#define DEBUG 1
20 
apply_mma(const Kernel & kernel,Ex & ex,Ex::iterator & it,const std::vector<std::string> & wrap,std::vector<std::string> args,const std::string & method)21 Ex::iterator MMA::apply_mma(const Kernel& kernel, Ex& ex, Ex::iterator& it, const std::vector<std::string>& wrap,
22                             std::vector<std::string> args, const std::string& method)
23 	{
24 	// We first need to print the sub-expression using DisplaySympy,
25 	// optionally with the head wrapped around it and the args added
26 	// (if present).
27 	std::ostringstream str;
28 
29 	for(size_t i=0; i<wrap.size(); ++i) {
30 		str << wrap[i] << "[";
31 		}
32 
33 	DisplayMMA ds(kernel, ex, true);
34 	ds.output(str, it);
35 
36 	if(wrap.size()>0)
37 		if(args.size()>0)
38 			for(size_t i=0; i<args.size(); ++i)
39 				str << ", " << args[i];
40 	for(size_t i=1; i<wrap.size(); ++i)
41 		str << "]";
42 	str << method;
43 
44 	if(wrap.size()>0)
45 		str << "]";
46 
47 	// We then execute the expression in Python.
48 
49 	//ex.print_recursive_treeform(std::cerr, it);
50 #ifdef DEBUG
51 	std::cerr << "feeding " << str.str() << std::endl;
52 #endif
53 
54 	std::string result;
55 
56 	// ---------------------
57 	setup_link();
58 
59 	WSPutFunction(lp, "EvaluatePacket", 1L);
60 	WSPutFunction(lp, "ToString", 1L);
61 	WSPutFunction(lp, "FullForm", 1L);
62 	WSPutFunction(lp, "ToExpression", 1L);
63 	WSPutUTF8String(lp, (const unsigned char *)str.str().c_str(), str.str().size());
64 	WSEndPacket(lp);
65 	WSFlush(lp);
66 
67 	// std::cerr << "flushed" << std::endl;
68 
69 	int pkt=0;
70 	while( (pkt = WSNextPacket(lp), pkt) && pkt != RETURNPKT ) {
71 		// std::cerr << "received packet " << pkt << std::endl;
72 		WSNewPacket(lp);
73 		if (WSError(lp)) {
74 			std::cerr << "error" << std::endl;
75 			}
76 		}
77 	// std::cerr << "packet now " << pkt << std::endl;
78 
79 	const char *out;
80 	if(! WSGetString(lp, &out)) {
81 		throw InternalError("Unable to read from WSTP link");
82 		}
83 	else {
84 		result=out;
85 		WSReleaseString(lp, out);
86 		if(result=="$Failed") {
87 			throw RuntimeException("Mathematica failed to handle expression.");
88 			}
89 		}
90 	// -------------------------------
91 
92 	// After that, we construct a new sub-expression from this string by using our
93 	// own parser, and replace the original.
94 
95 #ifdef DEBUG
96 	std::cerr << "result: " << result << std::endl;
97 #endif
98 
99 	result = ds.preparse_import(result);
100 
101 #ifdef DEBUG
102 	std::cerr << "preparsed: " << result << std::endl;
103 #endif
104 
105 	auto ptr = std::make_shared<Ex>();
106 	cadabra::Parser parser(ptr);
107 	std::stringstream istr(result);
108 	istr >> parser;
109 
110 	pre_clean_dispatch_deep(kernel, *parser.tree);
111 	cleanup_dispatch_deep(kernel, *parser.tree);
112 
113 	//parser.tree->print_recursive_treeform(std::cerr, parser.tree->begin());
114 
115 #ifdef DEBUG
116 	std::cerr << "cleaned up: " << *parser.tree << std::endl;
117 #endif
118 
119 	ds.import(*parser.tree);
120 
121 #ifdef DEBUG
122 	std::cerr << "imported: " << *parser.tree << std::endl;
123 #endif
124 
125 	pre_clean_dispatch_deep(kernel, *parser.tree);
126 	cleanup_dispatch_deep(kernel, *parser.tree);
127 
128 	Ex::iterator first=parser.tree->begin();
129 	// std::cerr << "reparsed " << Ex(first) << std::endl;
130 	it = ex.move_ontop(it, first);
131 
132 	return it;
133 	}
134 
setup_link()135 void MMA::setup_link()
136 	{
137 	if(lp!=0) return; // already setup
138 
139 	char argvi[4][512] = { "-linkname", Mathematica_KERNEL_EXECUTABLE " -mathlink", "-linkmode", "launch" };
140 	char *argv[4];
141 	for (size_t i=0; i<4; ++i)
142 		argv[i] = argvi[i];
143 	int  argc = 4;
144 
145 	int errno;
146 	stdenv = WSInitialize((WSEnvironmentParameter)0);
147 	if(stdenv==0)
148 		throw InternalError("Failed to initialise WSTP");
149 
150 	// std::cerr << "initialised" << std::endl;
151 
152 	try {
153 		lp = WSOpenArgcArgv(stdenv, argc, argv, &errno);
154 		if(lp==0 || errno!=WSEOK) {
155 			// std::cerr << errno << ", " << WSErrorMessage(lp) << ";" << std::endl;
156 			lp=0;
157 			WSDeinitialize(stdenv);
158 			throw InternalError("Failed to open Mathematica link");
159 			}
160 		}
161 	catch(std::exception& ex) {
162 		lp=0;
163 		WSDeinitialize(stdenv);
164 		throw InternalError("Failed to open Mathematica link");
165 		}
166 
167 	// std::cerr << "loopback link open" << std::endl;
168 
169 	WSActivate(lp);
170 	}
171 
teardown_link()172 void MMA::teardown_link()
173 	{
174 	if(lp!=0) {
175 		WSClose(lp);
176 		WSDeinitialize(stdenv);
177 		lp=0;
178 		}
179 	}
180