Интеграция Mathematica в Java

Java + Mathematica

Математический пакет (далее пакет), исполняющий роль умного калькулятора, неплохо подойдет студенту начальных курсов, однако зачем нам пакет, который не может быть интегрирован в стороннюю программу? В этой статье речь пойдет исключительно о связке Mathematica с Java. Мы постараемся рассмотреть основные методы взаимодействия и подводные камни, на которые вы можете натолкнуться.

Java → Mathematica

Взаимодействие с локальным ядром (kernel)

Давайте сначала рассмотрим самый простой случай, в котором пакет уже установлен на наш компьютер и нам требуется только связаться с ядром и начать взаимодействовать. В Mathematica уже есть готовый инструмент для взаимодействия с Java - JLink. Все классы для "общения" уже написаны, нам остается только подключить их.

Подключаем JLink в проект

Рассмотрим произвольный java-проект, который открыт в среде программирования. В нашем примере я буду использовать IntelliJ IDEA.

add jlink to intelijj idea

C:/Program Files/Wolfram Research/Mathematica9.0/SystemFiles/Links/JLink/JLink.jar

Все. Готово. Теперь мы можем подключить com.wolfram.jlink и начать взаимодействовать с Mathematica.

Пример подключения к ядру приведен ниже:

KernelLink ml = null;
try {
    ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:program fileswolfram researchmathematica7.0mathkernel'");
} catch (MathLinkException e) {
    // This is equivalent to MLOpen returning NULL in a C program.
    System.out.println(e.getMessage());
    System.exit(1);
}

Hello World

В данном примере мы будем отправлять произвольные команды в ядро Mathematica и получать ответ в текстовом формате.

import com.wolfram.jlink.*;

public class Main {
    static KernelLink ml;
    public static void main(String[] args) {
        String path = "-linkmode launch -linkname 'C:/Program Files/Wolfram Research/Mathematica/9.0/MathKernel'";
        try {
            ml = MathLinkFactory.createKernelLink(path);// подключаем ядро
            ml.discardAnswer();// дожидаемся загрузки ядра
            ml.evaluate("2+2");
            ml.waitForAnswer();
            int result = ml.getInteger();// считываем результат
            System.out.println("2 + 2 = " + result);
        }
        catch (Exception e){
            System.out.println(e.toString());
        }
    }
}

Подключаем графику

Теперь мы несколько усложним задачу и попытаемся загрузить ответ в формате Graphics. Например получим график некоторой функции.

import com.wolfram.jlink.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends Frame {
    static Main app;
    static KernelLink mL;
    MathCanvas mathCanvas;
    String exec = "Plot[BesselJ[0, x], {x, 0, 50}]";

    public Main(){

        setLayout(new BorderLayout());
        setTitle(exec);
        //

        mathCanvas = new MathCanvas(mL);// создаем canvas
        add(mathCanvas, BorderLayout.CENTER);
        mathCanvas.setBackground(Color.WHITE);
        mathCanvas.setBounds(10, 10, 500, 500);// устанавливаем отступ и размеры canvas
        mathCanvas.setImageType(MathCanvas.GRAPHICS);// определяем тип графики
        mathCanvas.setUsesFE(true);
        mathCanvas.setMathCommand(exec);// отправляем команду ядру

        //
        setSize(550,350);
        setLocationRelativeTo(null);
        addWindowListener(new WnAdptr());
        setResizable(false);
        setVisible(true);
        toFront();
    }
    /* Важно! Нам нужен отдельный обработчик для закрытия сеанса общения с ядром */
    class WnAdptr extends WindowAdapter {
        public void windowClosing(WindowEvent event) {
            if (mL != null) {
                // Because we used the front end, it is important
                // to call CloseFrontEnd[] before closing the link.
                // Counterintuitively, this is not because we want
                // to force the front end to quit, but because we
                // _don't_ want to do this if the user has begun
                // working in the front end session we started.
                // CloseFrontEnd knows how to politely disengage
                // from the front end if necessary. The need for
                // this will go away in future releases of
                // Mathematica.
                mL.evaluateToInputForm("CloseFrontEnd[]", 0);
                mL.close();
            }
            dispose();
            System.exit(0);
        }
    }
    /* init */
    public static void main(String[] args) {
        /* подключаем ядро */
        try {
            String[] mlArgs = {"-linkmode", "launch", "-linkname", "C:/Program Files/Wolfram Research/Mathematica/9.0/MathKernel"};
            mL = MathLinkFactory.createKernelLink(mlArgs);
            mL.discardAnswer();
        } catch (MathLinkException e) {
            System.out.println("An error occurred connecting to the kernel.");
            if (mL != null)
                mL.close();
            return;
        }
        app = new Main();
    }

}

Краткая документация

// Typical launch on Windows
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:program fileswolfram researchmathematica7.0mathkernel.exe'");

// Typical launch on Unix
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'math -mathlink'");

// Typical launch on Mac OS X
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname '"/Applications/Mathematica.app/Contents/MacOS/MathKernel" -mathlink'");

// Typical "listen" link on any platform:
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode listen -linkname 1234 -linkprotocol tcp");

// Windows can use the default protocol for listen/connect links:
KernelLink ml = MathLinkFactory.createKernelLink("-linkmode listen -linkname foo");
Можно передать и массив строк:
// Typical launch on Windows:
String[] argv = {"-linkmode", "launch", "-linkname", "c:program fileswolfram researchmathematica7.0mathkernel"};

// Typical launch on UNIX:
String[] argv = {"-linkmode", "launch", "-linkname", "math -mathlink"};

// Typical launch on Mac OS X:
String[] argv = {"-linkmode", "launch", "-linkname", ""/Applications/Mathematica.app/Contents/MacOS/MathKernel" -mathlink"};

// Typical "listen" link on any platform:
String[] argv = {"-linkmode", "listen", "-linkname", "1234", "-linkprotocol", "tcp"};

// Windows can use the default protocol for listen/connect links:
String[] argv = {"-linkmode", "listen", "-linkname", "foo"};
Получение ответа от ядра:
int getInteger() throws MathLinkException;

long getLongInteger() throws MathLinkException;

double getDouble() throws MathLinkException;

String getString() throws MathLinkException;

byte[] getByteString(int missing) throws MathLinkException;

String getSymbol() throws MathLinkException;

boolean getBoolean() throws MathLinkException;
Object getArray(int type, int depth) throws MathLinkException;
// New in J/Link 2.0:
Object getArray(int type, int depth, String[] heads) throws MathLinkException;

Источник: reference.wolfram.com

Если нет ядра

Если вдруг на компьютере конечного пользователя не установлена Mathematica, тогда у вас начинаются проблемы. "Переносное" ядро официально не распространяется. Одним из вариантов создания независимого кода является генерация C-кода, который вы можете попытаться подключить к Java.

В то же время Wolfram предлагает собственный свободный формат файлов - cdf. Такие документы могут выполнять скомпилированный в Mathematica код и отображать элементы управления. Для отображения cdf-документов требуется только установить соответствующий плагин, скачать (~165 MB).

//edunow.su/images/cdf-demo

Mathematica → Java

Подключаем JLink

Первым шагом нужно подключить jLink, который позволит создавать программы на Java

Needs["JLink`"]

Следующим шагом запускаем Java runtime и "устанавливаем" его в Mathematica. Для этого используем функцию InstallJava[].

InstallJava[]запускает Java runtime и подготавливает для использования из Mathematica
ReinstallJava[]выходит и перезапускает Java runtime, если он уже запущен
JavaLink[]возвращает LinkObject, который позволяет общаться с Java runtime

"Совместимость"

Mathematica по своему понимает, как нужно писать на Java, поэтому наша любимая Java слегка преображается:

Источник: reference.wolfram.com

Пример программы

GetAngle[] :=
	JavaBlock[
		Module[{frm, inputField, cbGroup, degBox, radBox,
					label, okButton, cancelButton, wasOKButton, angle},
			InstallJava[]; (* In case the user has not called it already. *)
			frm = JavaNew["com.wolfram.jlink.MathFrame"];
			label = JavaNew["java.awt.Label", "Enter an angle:"];
			inputField = JavaNew["java.awt.TextField"];
			cbGroup = JavaNew["java.awt.CheckboxGroup"];
			degBox = JavaNew["java.awt.Checkbox", "degrees", cbGroup, True];
			radBox = JavaNew["java.awt.Checkbox", "radians", cbGroup, False];
			okButton = JavaNew["java.awt.Button", "OK"];
			cancelButton = JavaNew["java.awt.Button", "Cancel"];
			
			frm@setLayout[Null];
			frm@add[label];
			frm@add[inputField];
			frm@add[degBox];
			frm@add[radBox];
			frm@add[okButton];
			frm@add[cancelButton];
			
			frm@setBounds[200, 200, 200, 160];
			label@setBounds[20, 30, 150, 20];
			inputField@setBounds[20, 70, 60, 28];
			degBox@setBounds[100, 60, 80, 20];
			radBox@setBounds[100, 80, 80, 20];
			okButton@setBounds[40, 120, 50, 20];
			cancelButton@setBounds[100, 120, 50, 20];
			frm@setResizable[False];
			okButton@addActionListener[
				JavaNew["com.wolfram.jlink.MathActionListener",
							"(EndModal[]; True)&"]
			];
			cancelButton@addActionListener[
				JavaNew["com.wolfram.jlink.MathActionListener",
							"(EndModal[]; False)&"]
			];
			
			(* Now make the window visible and bring it to the foreground. *)
			JavaShow[frm];
			frm@setModal[];
			wasOKButton = DoModal[];
			(* Even though the window may have been closed, it is perfectly
			   OK to extract values from the controls in the window.
			*)
			If[TrueQ[wasOKButton],
				angle = ToExpression[inputField@getText[]];
				If[angle =!= Null && degBox@getState[], angle *= Pi/180],
			(* else *)
				(* We will get here if the Cancel button was clicked
				   (wasOKButton will be False), or the dialog was closed
				   by clicking in its close box (wasOKButton will be Null).
				*)
				angle = $Failed
			];
			(* If the cancel or OK buttons were clicked, frm is still
			   visible, so we dispose it here.
			*)
			frm@dispose[];
			angle
		]
	]
GetAngle[]

Полезные материалы:
  • J/Link User Guide - pdf (пароль: edunow.su)

↑ Расскажите друзьям о статье


Comments system Cackle

© EduNow.su — материалы подлежат полному/частичному копированию при указании прямой ссылки на источник. (Сегодня 26.06.17)