2

First of all I am aware of the complexity involved in the following question, but I wonder if something similar has been already solved (maybe even partially) by someone, who was interested in this task. Basically I thought it would be really helpful the implementation of a MATLAB code in LuaLaTeX by using Lua. For instance let's consider the following example:

\documentclass{article}
\usepackage{amsmath}
\begin{document}
The resulting value of the sought parameter can be 
obtained by the following equation:
\begin{equation}
h = x^2 \sin(k^2 - t) + \frac{\kappa^2 - 1}{\kappa} 
    - \log (x+1) = ?? \mathrm{ mm}
\end{equation}
\end{document}

Since I frequently work with MATLAB, I thought it would be really convenient to run directly the file.m from the latex environment. I imagine the process would be:

  1. Create an external file example.m, which would be:

    x = 24; k = 2*pi; t = -pi/2; kappa = 0.8;
    
    h = x^2*sin(k^2 - t) + (kappa^2-1)/kappa - log10(x+1);
    
  2. By using Lua, send and run locally the code to MATLAB

  3. At the end obtain all the assigned variables from the workspace by means of a command

So at the end it would be possible to compile:

\documentclass{article}
\usepackage{amsmath}
\begin{document}
The resulting value of the sought parameter can be 
obtained by the following equation:
\begin{equation}
h = x^2 \sin(k^2 - t) + \frac{\kappa^2 - 1}{\kappa} 
    - \log (x+1) = \matlabvariable{/example.m}{h} \mathrm{ mm}
\end{equation}
\end{document}

where the command \matlabvariable{<script path>}{<variable>} can access the value.

In case there are other suggestions, which would solve this question, please be free to share.

14
  • 2
    Why send the code to Matlab? Why not execute it in Lua directly?
    – Mico
    Commented Sep 23 at 18:07
  • @Mico Because I almost always use MATLAB for engineering purposes, so for my case it would be really helpful in this manner.
    – Richard
    Commented Sep 23 at 18:33
  • 1
    I don't know anything about matlab, so this probably explains it, but I don't really understand what you're trying to do. you can execute arbitrary code during compilation, so if you have example.m you can run whatever programme you like on example.m. you can either collect the results directly or output them to a file you then read or whatever works for the external programme. what's the particular problem with matlab? and what about it needs lua? of course you need shell escape to do it, but I assume you know that already.
    – cfr
    Commented Sep 26 at 2:48
  • @cfr Honestly my programming skills are precarious and I do not really know how a shell escape should be carried out through LaTeX. Basically I am trying to automate the process between LaTeX and Matlab, where by simply compiling the LaTeX code, the Matlab code runs, generates output and by means of a LaTeX command I can get the value of the selected variable in the math mode environment. In this manner I do not need always to copy/paste all the values of the parameter for each case. I thought a feature like this would be really useful, especially if combined with Overleaf for example.
    – Richard
    Commented Sep 26 at 12:25
  • @cfr Regarding Lua, I thought it was necessary to solve this problem. If Lua is not required to make it work, better so.
    – Richard
    Commented Sep 26 at 12:30

2 Answers 2

5
+100

Disclaimer: I don't have matlab so I used python for testing instead (see end of post). This really is only a proof of concept.

as @cfr pointed out: from a LaTeX point of view, this problem is rather simple:

First you need a script that executes the matlab code and prints the variables to a text file in a format LaTeX understands. Then you import the text file and use the variables.

Lets get to the LaTeX side of it first. We therefore assume we have a matlab script save_workspace_vars.m which executes any given matlab file, e.g. example.m, and stores all its workspace variables and values as LaTeX macros into the file example_vars.txt like so: \newcommand{\varname}{varvalue}. But since we do not know the names of the variables and there could be a lot of them, there could easily be name clashes if we run multiple matlab scripts from one LaTeX file. So we better use \newcommand{\prefixvarname}{varvalue} where prefix could be any string, especially the name of the matlab script, making the macro name unique.

So now we have a matlab script that generates a text file containing neat macros with unique names expanding to all our variables values, how do we use it?

  1. We need a macro to execute the script from inside LaTeX with \immediate\write18. This requires us to compile the .tex file with --shell-escape like so: pdflatex --shell-escape mydocument.tex
  2. We need to import the textfile with \import
  3. We need a macro that allows us to print the variables in a convenient way, e.g. \matlabvariable{prefix}{varname}

1 and 2 can be dealt with in a single command that may be used in the preamble:

\newcommand{\getvars}[1]{
    \immediate\write18{matlab -batch "save_workspace_vars('#1')"}%
    \input{#1_vars.txt}
}

3 is now even simpler

\newcommand{\matlabvariable}[2]{\csname #1#2\endcsname}

Assume we have the variables h = 42 and pi = 3.1415 inside our matlab workspace in example.m (and example.m and save_workspace_vars.m are inside our working directory). Our whole document would simply look like this:

\documentclass{article}

\newcommand{\getvars}[1]{
    \immediate\write18{matlab -batch "save_workspace_vars('#1')"}%
    \input{#1_vars.txt}
}

\newcommand{\matlabvariable}[2]{\csname #1#2\endcsname}

\getvars{example}

\begin{document}
    
    The value of h is: \matlabvariable{example}{h}
    
    The value of pi is: \matlabvariable{example}{pi}

\end{document}

Output: Screenshot of output from the python tests

Things to consider:

  • The variable names inside the matlab script have to be possible LaTeX macro names, e.g. they should not contain numbers or dots et. al. As @cfr pointed out: due to \csname and \endcsname some of the restrictions for normal LaTeX macro names are lifted but I can't tell you which ones and so it might be better to stick to names that you are shure to work.
  • same applies to the name of the matlab script.
  • the matlab scripts are assumed to be in the same directory as the tex file

Now comes the hard part: the matlab script for saving the variables.

I dont have matlab and don't know much about it. So I tested all the above code with python instead of matlab. In order to give you a hint in the right direction I asked an AI to generate a corresponding matlab script and chatgpt gave me this:

function save_workspace_vars(script_name)
    % Load the workspace of the specified MATLAB file
    % Assume the script_name is passed without the '.m' extension
    try
        run(script_name); % Executes the specified MATLAB script
    catch ME
        error('Error executing %s.m: %s', script_name, ME.message);
    end
    
    % Get all variables from the workspace
    vars = whos;
    
    % Prepare the output file
    filename = strcat(script_name, '_vars.txt');
    fid = fopen(filename, 'w');
        
    % Loop through each variable in the workspace
    for i = 1:length(vars)
        var_name = vars(i).name;
        var_value = eval(var_name); % Get the value of the variable
            
        % Generate the LaTeX command for the variable based on its type
        if isnumeric(var_value) && isscalar(var_value)
            % Handle integer or double scalar values
            fprintf(fid, '\\newcommand{\\%s%s}{%g}\n', script_name, var_name, var_value);
        elseif ischar(var_value)
            % Handle string (character array) values
            fprintf(fid, '\\newcommand{\\%s%s}{%s}\n', script_name, var_name, var_value);
        elseif isstring(var_value) && isscalar(var_value)
            % Handle scalar string values
            fprintf(fid, '\\newcommand{\\%s%s}{%s}\n', script_name, var_name, var_value);
        else
            % Unsupported data type, skip this variable
            fprintf(fid, '\\newcommand{\\%s%s}{Unsupported data type}\n', script_name, var_name);
        end
    end
    
    % Close the file
    fclose(fid);
        
    disp(['Variables saved to ', filename]);
end

Looks ok to me. You iterate over all variables and save them according to their type. This even allows for sophisticated formatting, where you could generate multiple commands for the same variable, say if you have a vector or a matrix or if the value of a variable is infinite..

But of course: I have no idea if this matlab script actually works. But I hope it will help you find way to do something along these lines in matlab.

Edit 2024-10-02 (4 days later)

For convenience it might be better not to assume, that all the files are in the same directory. Then we have three directories of interest:

  1. The current working directory (workDir)
  2. The directory where save_workspace_vars.m is located (exportScriptDir)
  3. The directory where the matlab scripts are (scriptDir)

Let's assume we're ok with saving the txt-file containing our new macros in scriptDir and we want exportScriptDir to be at some freely chosen location. Then we do as follows:

\documentclass{article}
\usepackage{etoolbox}

\newcommand{\getvars}[2]{
    % #1 is path/to/scriptDir/ 
    % #2 is nameOfMatlabScript without '.m'
    % \exportScript stores the location of exportScriptDir. \providecommand needed if \getvars is used more then once
    \providecommand{\exportScript}{/path/to/exportScriptDir/save_workspace_vars.m}
    % I am assuming python here, because again: don't know much about matlab
    \immediate\write18{python3 \exportScript \expandonce{ #1 #2}}
    \input{#1#2_vars.txt}
}

\newcommand{\matlabvariable}[2]{\csname #1#2\endcsname}

\getvars{path/to/scriptDir}{example}

\begin{document}

    The value of h is: \matlabvariable{example}{h}
        
    The value of pi is: \matlabvariable{example}{pi}

\end{document}

You then need a matlab script save_workspace_vars.m to which you can pass two arguments. The first beeing the full path of scriptDir and the second beeing the name of the script without .m.

Let me know, if you are interested in changing all this to save the _vars.txt to an arbitrary location (for example the workDir).

Of course I can generate another save_workspace_vars.m in matlab for accepting a path too. But I guess you can either write it yourself or better ask someone who knows matlab better.

As I used python for testing, I should share my approach in python as well. I used the following python script save_vars.py to fake the creation of variables:

import sys

# Ensure the correct number of arguments is provided
if len(sys.argv) != 2:
   print("Usage: save_vars.py <script_name>")
   sys.exit(1)

# Extract script name (without extension)
script_name = sys.argv[1]

# Simulate some variables for the given script name
variables = {
    "h": 42,
    "pi": 3.1415
}

# Open a file to save the variables in LaTeX command format
filename = f"{script_name}_vars.txt"
with open(filename, "w") as f:
    for var_name, value in variables.items():
        if isinstance(value, (int, float)):
            value_str = str(value)
        elif isinstance(value, str):
            value_str = value
        else:
            value_str = "Unsupported data type"
        
        # Write in the format: \newcommand{\prefixvarname}{var_value}
        f.write(f"\\newcommand{{\\{script_name}{var_name}}}{{{value_str}}}\n")
        
print(f"Variables saved to {filename}")

To then call it, I used \immediate\write18{python save_vars.py #1}

4
  • \csname ... \endcsname means many of the restrictions on names don't apply, but it is not a bad idea to keep the matlab names tex-friendly if possible ;).
    – cfr
    Commented Sep 29 at 0:05
  • Thank you @cfr ! I dont know what restrictions still apply and I dont want to be (even more) fuzzy about it.
    – Wamseln
    Commented Sep 29 at 10:24
  • I think you don't need etoolbox to use \csname#1#2\endcsname, they're TeX primitives. Commented Oct 2 at 11:00
  • Thank you @DanielDiniz . I changed it accordingly.
    – Wamseln
    Commented Oct 2 at 11:15
1

If you know how to program math formulas in Matlab, doing so in Lua should be easy for you.

enter image description here

\documentclass{article}
\usepackage{amsmath}
\usepackage{siunitx} % for '\qty' macro

\directlua{
  local x, k, t, kappa
  x=24; k=2*math.pi; t=-math.pi/2; kappa=0.8
  function h_func ( )
    return ( x^2 * math.sin(k^2-t) + (kappa^2-1)/kappa - math.log10(x+1) )
  end
}
\newcommand{\hcalc}{\directlua{tex.sprint(h_func())}} % utility macro

\begin{document}

The value of the sought-after parameter $h$ can be 
obtained as follows:
\begin{equation}
h = x^2 \sin(k^2 - t) + (\kappa^2 - 1)/\kappa - \log (x+1) 
  = \qty[round-mode=places,round-precision=2]{\hcalc}{\milli\meter}\,.
\end{equation}

\end{document}
1
  • 4
    The stated script in MATLAB is far from being complex and usually I use packages and Simulink as well. It is just an example of a meaningless equation. That's also the reason I would prefer a MATLAB compatibility. By the way thank you for the proposed solution.
    – Richard
    Commented Sep 23 at 19:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .