|
Requesting Evaluations by Mathematica
So far, we have seen only cases where a Java method has a very simple interaction with Mathematica. It is called and returns a result, either automatically or manually. There are many circumstances, however, where you might want to have a more complex interaction with Mathematica. You might want a message to appear in Mathematica, or some Print output, or you might want to have Mathematica evaluate something and return the answer to you. This is a completely separate issue from what you want to return to Mathematica at the end of your method—you can request evaluations from the body of a method whether it returns its final result manually or not.
In some sense, when we perform this type of interaction with Mathematica we are turning the tables on Mathematica, reversing the "master" and "slave" roles for a moment. When Mathematica calls into Java, the Java code is acting as the slave, performing a computation and returning control to Mathematica. In the middle of a Java method, however, we can call back into Mathematica, temporarily turning it into a computational server for the Java side. Thus we would expect to encounter essentially all the same issues that are discussed in Part 2 of this User Guide, and we would need to understand the full J/Link Java-side API.
The full treatment of the MathLink and KernelLink interfaces is presented in Part 2. In this section we will discuss a few special methods in KernelLink that are specifically for use by "installed" methods. We have already seen one, the beginManual() method. Now we will treat the message(), print(), and evaluate() methods.
The task of issuing a Mathematica message from a Java method and triggering some Print output are so commonly done that the KernelLink interface has special methods for these operations. The method message() performs all the steps of issuing a Mathematica message. It comes in two signatures:
public void message(String symtag, String arg);
public void message(String symtag, String[] args);
The first form is for when you just have a single string argument to be slotted into the message text, and the second form is for if the message text needs two or more arguments. You can pass null as the second argument if the message text needs no arguments.
The print() method performs all the steps necessary to invoke Mathematica's Print function:
public void print(String s);
Here is an example method that uses both. Assume that the following messages are defined in Mathematica (this could be from loading a package or during this class' onLoadClass() method):
Foo::arg = "The `1` argument to foo must be greater than or equal to 0."
Here is the Java code:
public static double foo(double x, double y) {
KernelLink link = StdLink.getLink();
if (link != null) {
link.print("inside foo");
if (x < 0)
link.message("Foo::arg", "first");
if (y < 0)
link.message("Foo::arg", "second");
}
return Math.sqrt(x) * Math.sqrt(y);
}
Note that print() and message() send the required code to Mathematica and also read the result from the link (it will always be the symbol Null). They do not throw MathLinkException so you do not have to wrap them in try/catch blocks.
Here is what happens when we call foo():


Note that you automatically get Indeterminate returned to Mathematica when a floating-point result from Java is NaN ("Not-a-Number").
The methods print() and message() are convenience functions for two special cases of the more general notion of sending intermediate evaluations to Mathematica before your method returns a result. The general means of doing this is to wrap whatever you send to Mathematica in EvaluatePacket, which is a signal to the kernel that this is not the final result, but rather something that it should evaluate and send the result back to Java. You can explicitly send the EvaluatePacket head, or you can use one of the methods in KernelLink that use EvaluatePacket for you. These methods are:
 These methods are discussed in Part 2 (actually, they also come in several more flavors with other argument sequences). Here is a simple example:
public static double foo(double x, double y) {
KernelLink link = StdLink.getLink();
if (link != null) {
try {
link.evaluate("2+2");
// Wait for, and then read, the answer.
link.waitForAnswer();
int sum1 = link.getInteger();
// evaluateToOutputForm makes the result come back as a
// string formatted in OutputForm, and all in one step
// (no waitForAnswer call needed).
String s = link.evaluateToOutputForm("3+3");
int sum2 = Integer.parseInt(s);
// If you want, put the whole evaluation piece by piece,
// including the EvaluatePacket head.
link.putFunction("EvaluatePacket");
link.putFunction("Plus", 2);
link.put(4);
link.put(4);
link.waitForAnswer();
int sum3 = link.getInteger();
} catch (MathLinkException e) {
// The only type of mathlink error we are likely to get
// is from a "get" function when what we are trying to
// get is not the type of expression that is waiting. We
// just clear the error state, throw away the packet we
// are reading, and let the method finish normally.
link.clearError();
link.newPacket();
}
}
return Math.sqrt(x) * Math.sqrt(y);
}
|