Engee documentation
Notebook

Using Julia, MATLAB, and Python together to solve engineering problems

Introduction

A modern engineer and scientist is rarely limited to one programming language. Numerical calculations are based on MATLAB, data analysis is based on Python, and high—performance computing is based on Julia. But what if you combine them instead of choosing them?

The Engee computing environment allows you to run Julia, MATLAB, and Python code directly in a single script, exchanging data between languages on the fly. In this example, we'll show how it works: create a matrix in Julia, process it in MATLAB, save it to a .mat file, and then analyze the result using NumPy — all without going beyond one environment.

Joining libraries

In this example, we will need the following libraries:

  • MATLAB — to run MATLAB commands and functions directly from Julia, allowing you to share variables between environments
  • MAT — for reading and writing files .mat works as an offline data converter without having to run MATLAB itself.
  • PyCall — for Python scripts and libraries from Julia with automatic type conversion between languages.
In [ ]:
using MATLAB, MAT, PyCall

Calling MATLAB from Julia

Executing MATLAB commands

This script will be executed inside the MATLAB core.

In [ ]:
mat"""
a = 10;
b = 20;
c = a + b;
disp(c);
"""
>> >> >> >> >> >>     30

Calling the MATLAB function

There is a file:

% function1.m\
\
function y = function1(x)\
 y = x.^2 + 1;\
end

Let's execute the MATLAB script using the command mxcall()and we will display the result.

In [ ]:
result = mxcall(:function1, 1, 5)
println(result)
26

Data transfer Julia → MATLAB

The macro @mput places Julia variables in the MATLAB workspace.

In [ ]:
x = [1,2,3,4,5]

@mput x

mat"""
y = x.^2;
disp(y)
"""
>> >> >> >>     1
    4
    9
   16
   25

Now MATLAB sees the variable x.

Multiple variables
In [ ]:
a = 10
b = 20

@mput a b
mat"""
c = a + b;
disp(c)
"""
>> >> >> >>    30

Getting MATLAB → Julia data

The macro @mget extracts MATLAB variables and places them in the Julia workspace.

In [ ]:
mat"""
x = 42;
"""

@mget x

println(x)
42.0
Getting an array
In [ ]:
mat"""
A = magic(3);
"""

@mget A

println(A)
[8.0 1.0 6.0; 3.0 5.0 7.0; 4.0 9.0 2.0]

Simultaneous data transmission

In [ ]:
x = [1.0, 2.0, 3.0]

@mput x

mat"""
y = sin(x);
z = cos(x);
"""

@mget y z

println(y)
println(z)
[0.8414709848078965, 0.9092974268256817, 0.1411200080598672]
[0.5403023058681398, -0.4161468365471424, -0.9899924966004454]
Transfer of matrices
In [ ]:
A = rand(5,5)
@mput A
mat"""
B = inv(A);
"""
@mget B
println(B)
[-5.221370437657235 4.536689829822023 1.7853694400555051 -1.7555803059084987 2.5459703018696143; -2.656223457338815 2.6954496614608283 1.9527633720615352 -0.7726425993370551 0.3924611199505691; 1.1298133336804967 0.13971945565486266 -1.0208263947545195 -0.09726994177272896 -0.013276362895074445; 8.019040759955885 -7.849628311451011 -2.63590807356968 2.136718238044462 -1.7078887483116802; 3.268552864160139 -3.710816487781914 -1.5021042004828817 2.4835666024648373 -1.7450236032972575]

Data exchange without using macros

Through put_variable() and get_variable()

In [ ]:
x = 10

put_variable(:x, x)

mat"""
y = x^2;
"""

y = get_variable(:y)

println(y) 
100

Through interpolation $

In [ ]:
x = 10

mat"""
y = $x^2;
"""

y = get_variable(:y)

println(y)  
100

Through mxcall()

In [ ]:
x = 10
y = mxcall(:sqrt, 1, x)
println(y)

Analog in MATLAB:

y = sqrt(10);

Through an explicit session MSession

In [ ]:
s = MSession()
put_variable(s, :x, 10)
eval_string(s, "y = x^2;")
y = get_mvariable(s, :y)
println(y)
close(s)
MxArray(Ptr{Nothing}(0x000077b0f43c39e0), true)
mkdir: cannot create directory ‘/user/.MathWorks’: Permission denied

Using the built-in MATLAB expression

In [ ]:
y = mxcall(:power, 1, 10, 2)
println(y) 

Analog in MATLAB:

power(10,2)

Calling the MATLAB script

There is a file:

% script1.m

x = 100;
y = x^2;

disp(y)

In [ ]:
mat"""
run('script1.m');
"""
>> >> >>        10000

or

In [ ]:
mat"""
script1
"""
>> >> >>        10000

Saving MAT files

Julia → MAT

In [ ]:
A = rand(100,100)
matwrite("data.mat", Dict("A" => A))

Then, in MATLAB, you can do:

In [ ]:
mat"""
load('data.mat')
"""

MATLAB → Julia

In [ ]:
data = matread("data.mat")
A = data["A"]
Out[0]:
100×100 Matrix{Float64}:
 0.187665    0.536775   0.559974   …  0.497759   0.370136   0.217892
 0.498748    0.802852   0.447108      0.137034   0.986267   0.0492607
 0.692961    0.585268   0.0409884     0.675473   0.352056   0.832218
 0.16713     0.523383   0.488701      0.64212    0.339589   0.0828162
 0.994572    0.0283767  0.932887      0.29104    0.573378   0.11291
 0.287387    0.787492   0.92626    …  0.312808   0.13772    0.796877
 0.930736    0.39265    0.133021      0.536968   0.665237   0.768994
 0.185316    0.0128372  0.846072      0.494333   0.36337    0.151129
 0.137108    0.0811613  0.612712      0.913359   0.0901814  0.639056
 0.257916    0.267885   0.0811315     0.309257   0.806105   0.982611
 0.153683    0.480328   0.330206   …  0.0230829  0.440528   0.584395
 0.147242    0.830841   0.611354      0.913737   0.175778   0.294328
 0.141859    0.259777   0.473815      0.391229   0.448802   0.783275
 ⋮                                 ⋱                        
 0.491116    0.22047    0.914381      0.403631   0.572556   0.680288
 0.31416     0.0558817  0.119846      0.58611    0.976843   0.402179
 0.523465    0.549084   0.292965   …  0.947264   0.593057   0.0757108
 0.505689    0.569463   0.271353      0.840848   0.613332   0.429195
 0.00443699  0.777516   0.928007      0.125124   0.702318   0.947103
 0.506735    0.841525   0.632436      0.389265   0.0218632  0.830129
 0.540411    0.701873   0.806918      0.588761   0.540034   0.473754
 0.643525    0.979437   0.540921   …  0.850907   0.661718   0.224936
 0.225163    0.693345   0.953538      0.0294944  0.0242852  0.983359
 0.80467     0.069913   0.223371      0.771978   0.675066   0.482565
 0.174844    0.123621   0.549536      0.146337   0.701713   0.917493
 0.962306    0.950703   0.678788      0.394894   0.0613499  0.605355

Calling Python from Julia

Executing a Python script

In [ ]:
py"""
x = 10
y = 20
z = x + y
print(z)
"""
30

Getting the result

In [ ]:
result = py"z"
println(result)

Calling a Python function

There is a file:

# mymodule.py

def square(x):
return x*x

In [ ]:
pushfirst!(PyVector(pyimport("sys")."path"), ".")
mod = pyimport("mymodule")
result = mod.square(5)
println(result)
25

Data transfer Julia → Python

In [ ]:
a = [1,2,3,4]
py"""
a = $a
"""

Python now sees the vector x.

Transfer of the NumPy matrix

In [ ]:
A = rand(3,3)
py"""
A = $A
"""

PyCall automatically converts the array.

Getting Python → Julia data

In [ ]:
py"""
import numpy as np
A = np.random.rand(3,3)
"""

A = py"A"
println(A)
[0.6654948909047511 0.3864146000126685 0.6323793133576465; 0.44635742775821485 0.751622525464147 0.12916692842936617; 0.2232885178400401 0.5449276484095866 0.18403058713001075]

Using NumPy directly

In [ ]:
np = pyimport("numpy")
x = np.linspace(0, 10, 100)
println(x)
[0.0, 0.10101010101010101, 0.20202020202020202, 0.30303030303030304, 0.40404040404040403, 0.5050505050505051, 0.6060606060606061, 0.7070707070707071, 0.8080808080808081, 0.9090909090909091, 1.0101010101010102, 1.1111111111111112, 1.2121212121212122, 1.3131313131313131, 1.4141414141414141, 1.5151515151515151, 1.6161616161616161, 1.7171717171717171, 1.8181818181818181, 1.9191919191919191, 2.0202020202020203, 2.121212121212121, 2.2222222222222223, 2.323232323232323, 2.4242424242424243, 2.525252525252525, 2.6262626262626263, 2.727272727272727, 2.8282828282828283, 2.929292929292929, 3.0303030303030303, 3.131313131313131, 3.2323232323232323, 3.3333333333333335, 3.4343434343434343, 3.5353535353535355, 3.6363636363636362, 3.7373737373737375, 3.8383838383838382, 3.9393939393939394, 4.040404040404041, 4.141414141414141, 4.242424242424242, 4.343434343434343, 4.444444444444445, 4.545454545454545, 4.646464646464646, 4.747474747474747, 4.848484848484849, 4.94949494949495, 5.05050505050505, 5.151515151515151, 5.252525252525253, 5.353535353535354, 5.454545454545454, 5.555555555555555, 5.656565656565657, 5.757575757575758, 5.858585858585858, 5.959595959595959, 6.0606060606060606, 6.161616161616162, 6.262626262626262, 6.363636363636363, 6.4646464646464645, 6.565656565656566, 6.666666666666667, 6.767676767676767, 6.8686868686868685, 6.96969696969697, 7.070707070707071, 7.171717171717171, 7.2727272727272725, 7.373737373737374, 7.474747474747475, 7.575757575757575, 7.6767676767676765, 7.777777777777778, 7.878787878787879, 7.979797979797979, 8.080808080808081, 8.181818181818182, 8.282828282828282, 8.383838383838384, 8.484848484848484, 8.585858585858587, 8.686868686868687, 8.787878787878787, 8.88888888888889, 8.98989898989899, 9.09090909090909, 9.191919191919192, 9.292929292929292, 9.393939393939394, 9.494949494949495, 9.595959595959595, 9.696969696969697, 9.797979797979798, 9.8989898989899, 10.0]

NumPy + Julia-array

In [ ]:
A = rand(100)
np.mean(A)
Out[0]:
0.4975610444322162

Data transfer between all three languages

Julia ↔ MATLAB ↔ Python

Julia:

In [ ]:
x = rand(100)
@mput x

MATLAB:

In [ ]:
mat"""
y = fft(x);
save('fft.mat','y')
"""

Julia:

In [ ]:
d = matread("fft.mat")
y = d["y"]
Out[0]:
100×1 Matrix{ComplexF64}:
  50.313741254263505 + 0.0im
 -1.5771407887055269 + 2.124727170787205im
 -1.2688118432157607 + 0.05402836822868018im
   2.004984078494711 - 1.3179735416202203im
 -0.8416332361392718 + 1.717682921499197im
   -0.92602810124836 + 3.5138264917159967im
   1.593016731074605 - 0.7439815251896407im
 0.46384142685195917 + 3.8454495764527im
  1.0924993653124653 - 3.905545719219579im
  0.7162821343272152 + 1.4136618648658554im
 -0.6796169943349781 + 0.7628501552265539im
 -3.4342798941532124 - 0.5686610086095321im
 -2.3822899937223627 + 0.03900956219344409im
                     ⋮
 -2.3822899937223627 - 0.03900956219344409im
 -3.4342798941532124 + 0.5686610086095321im
 -0.6796169943349781 - 0.7628501552265539im
  0.7162821343272152 - 1.4136618648658554im
  1.0924993653124653 + 3.905545719219579im
 0.46384142685195917 - 3.8454495764527im
   1.593016731074605 + 0.7439815251896407im
   -0.92602810124836 - 3.5138264917159967im
 -0.8416332361392718 - 1.717682921499197im
   2.004984078494711 + 1.3179735416202203im
 -1.2688118432157607 - 0.05402836822868018im
 -1.5771407887055269 - 2.124727170787205im

Python:

In [ ]:
np = pyimport("numpy")
py_y = PyObject(y)
meanval = np.mean(abs.(y))
Out[0]:
2.972701599598033

Calling MATLAB and Python in the same Julia script

In [ ]:
x = 1:10
@mput x

mat"""
y = x.^2;
"""

@mget y

np = pyimport("numpy")
avg = np.mean(y)

println(avg)
38.5

Here, the data flows through the chain: Julia → MATLAB → Julia → Python → Julia, which is one of the typical scenarios of scientific computing and data analysis.

Conclusion

We have seen that the Engee computing environment is able to seamlessly integrate three language universes into a single computing process, which allows us to unite engineering communities using different programming languages, providing a ready-made platform where MATLAB-compatible calculations, Python scripts and high-performance Julia code work together without having to manually configure interlanguage bridges.